<commit_before>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use std::io;
    use std::fs::File;
    use Rng;
    use read::ReadRng;
    use std::mem;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(target_arch = "powerpc")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = io::Error::last_os_error();
                if err.kind() == io::ErrorKind::Interrupted {
                    continue
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn is_getrandom_available() -> bool {
        use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
        use std::sync::{Once, ONCE_INIT};

        static CHECKER: Once = ONCE_INIT;
        static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReadRng(ReadRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open("/dev/urandom"));
            let reader_rng = ReadRng::new(reader);

            Ok(OsRng { inner: OsReadRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReadRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReadRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReadRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use std::io;
    use std::mem;
    use Rng;
    use self::libc::{c_int, size_t};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate advapi32;

    use std::io;
    use std::mem;
    use std::ptr;
    use Rng;
    use self::winapi::{CRYPT_SILENT, CRYPT_VERIFYCONTEXT, DWORD, HCRYPTPROV, PROV_RSA_FULL};
    use self::advapi32::{CryptAcquireContextA, CryptGenRandom, CryptReleaseContext};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, ptr::null(), ptr::null(),
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::channel;
    use Rng;
    use OsRng;
    use std::thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in 0..20 {
            let (tx, rx) = channel();
            txs.push(tx);

            thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in 0..100 {
                    r.next_u32();
                    thread::yield_now();
                    r.next_u64();
                    thread::yield_now();
                    r.fill_bytes(&mut v);
                    thread::yield_now();
                }
            });
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<commit_msg>Fix getrandom syscall number for aarch64-unknown-linux-gnu<commit_after>// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use std::io;
    use std::fs::File;
    use Rng;
    use read::ReadRng;
    use std::mem;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;
        #[cfg(target_arch = "aarch64")]
        const NR_GETRANDOM: libc::c_long = 278;
        #[cfg(target_arch = "powerpc")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(&mut v[read..]);
            if result == -1 {
                let err = io::Error::last_os_error();
                if err.kind() == io::ErrorKind::Interrupted {
                    continue
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as usize;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8; 4] = [0u8; 4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8; 8] = [0u8; 8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8; 8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64",
                  target_arch = "x86",
                  target_arch = "arm",
                  target_arch = "aarch64",
                  target_arch = "powerpc")))]
    fn is_getrandom_available() -> bool {
        use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
        use std::sync::{Once, ONCE_INIT};

        static CHECKER: Once = ONCE_INIT;
        static AVAILABLE: AtomicBool = ATOMIC_BOOL_INIT;

        CHECKER.call_once(|| {
            let mut buf: [u8; 0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = io::Error::last_os_error().raw_os_error();
                err != Some(libc::ENOSYS)
            } else {
                true
            };
            AVAILABLE.store(available, Ordering::Relaxed);
        });

        AVAILABLE.load(Ordering::Relaxed)
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64",
                      target_arch = "x86",
                      target_arch = "arm",
                      target_arch = "aarch64",
                      target_arch = "powerpc"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReadRng(ReadRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open("/dev/urandom"));
            let reader_rng = ReadRng::new(reader);

            Ok(OsRng { inner: OsReadRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReadRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReadRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReadRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use std::io;
    use std::mem;
    use Rng;
    use self::libc::{c_int, size_t};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    const kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", io::Error::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate winapi;
    extern crate advapi32;

    use std::io;
    use std::mem;
    use std::ptr;
    use Rng;
    use self::winapi::{CRYPT_SILENT, CRYPT_VERIFYCONTEXT, DWORD, HCRYPTPROV, PROV_RSA_FULL};
    use self::advapi32::{CryptAcquireContextA, CryptGenRandom, CryptReleaseContext};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> io::Result<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, ptr::null(), ptr::null(),
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(io::Error::last_os_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8; 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8; 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}",
                       io::Error::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}",
                       io::Error::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::sync::mpsc::channel;
    use Rng;
    use OsRng;
    use std::thread;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8; 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in 0..20 {
            let (tx, rx) = channel();
            txs.push(tx);

            thread::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv().unwrap();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                thread::yield_now();
                let mut v = [0u8; 1000];

                for _ in 0..100 {
                    r.next_u32();
                    thread::yield_now();
                    r.next_u64();
                    thread::yield_now();
                    r.fill_bytes(&mut v);
                    thread::yield_now();
                }
            });
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(()).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).

use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, CustomIdent, HasViewportPercentage};
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::specified::LengthOrPercentage;

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<grid-line>` type.
///
/// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
pub struct GridLine {
    /// Flag to check whether it's a `span` keyword.
    pub is_span: bool,
    /// A custom identifier for named lines.
    ///
    /// https://drafts.csswg.org/css-grid/#grid-placement-slot
    pub ident: Option<String>,
    /// Denotes the nth grid line from grid item's placement.
    pub integer: Option<i32>,
}

impl Default for GridLine {
    fn default() -> Self {
        GridLine {
            is_span: false,
            ident: None,
            integer: None,
        }
    }
}

impl ToCss for GridLine {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        if !self.is_span && self.ident.is_none() && self.integer.is_none() {
            return dest.write_str("auto")
        }

        if self.is_span {
            try!(dest.write_str("span"));
        }

        if let Some(i) = self.integer {
            try!(write!(dest, " {}", i));
        }

        if let Some(ref s) = self.ident {
            try!(write!(dest, " {}", s));
        }

        Ok(())
    }
}

impl Parse for GridLine {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        let mut grid_line = Default::default();
        if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
            return Ok(grid_line)
        }

        for _ in 0..3 {     // Maximum possible entities for <grid-line>
            if input.try(|i| i.expect_ident_matching("span")).is_ok() {
                if grid_line.is_span {
                    return Err(())
                }
                grid_line.is_span = true;
            } else if let Ok(i) = input.try(|i| i.expect_integer()) {
                if i == 0 || grid_line.integer.is_some() {
                    return Err(())
                }
                grid_line.integer = Some(i);
            } else if let Ok(name) = input.try(|i| i.expect_ident()) {
                if grid_line.ident.is_some() {
                    return Err(())
                }
                grid_line.ident = Some(name.into_owned());
            } else {
                break
            }
        }

        if grid_line.is_span {
            if let Some(i) = grid_line.integer {
                if i < 0 {      // disallow negative integers for grid spans
                    return Err(())
                }
            } else {
                grid_line.integer = Some(1);
            }
        }

        Ok(grid_line)
    }
}

impl ComputedValueAsSpecified for GridLine {}
no_viewport_percentage!(GridLine);

define_css_keyword_enum!{ TrackKeyword:
    "auto" => Auto,
    "max-content" => MaxContent,
    "min-content" => MinContent
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A track breadth for explicit grid track sizing. It's generic solely to
/// avoid re-implementing it for the computed type.
///
/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
pub enum TrackBreadth<L> {
    /// The generic type is almost always a non-negative `<length-percentage>`
    Breadth(L),
    /// A flex fraction specified in `fr` units.
    Flex(CSSFloat),
    /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`)
    Keyword(TrackKeyword),
}

/// Parse a single flexible length.
pub fn parse_flex(input: &mut Parser) -> Result<CSSFloat, ()> {
    match try!(input.next()) {
        Token::Dimension(ref value, ref unit) if unit.eq_ignore_ascii_case("fr") && value.value.is_sign_positive()
            => Ok(value.value),
        _ => Err(()),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Flex(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl<L: ToCss> ToCss for TrackBreadth<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackBreadth::Breadth(ref lop) => lop.to_css(dest),
            TrackBreadth::Flex(ref value) => write!(dest, "{}fr", value),
            TrackBreadth::Keyword(ref k) => k.to_css(dest),
        }
    }
}

impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        if let TrackBreadth::Breadth(ref lop) = *self {
            lop.has_viewport_percentage()
        } else {
            false
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackBreadth<L> {
    type ComputedValue = TrackBreadth<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackBreadth::Breadth(ref lop) => TrackBreadth::Breadth(lop.to_computed_value(context)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackBreadth::Breadth(ref lop) =>
                TrackBreadth::Breadth(ToComputedValue::from_computed_value(lop)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<track-size>` type for explicit grid track sizing. Like `<track-breadth>`, this is
/// generic only to avoid code bloat. It only takes `<length-percentage>`
///
/// https://drafts.csswg.org/css-grid/#typedef-track-size
pub enum TrackSize<L> {
    /// A flexible `<track-breadth>`
    Breadth(TrackBreadth<L>),
    /// A `minmax` function for a range over an inflexible `<track-breadth>`
    /// and a flexible `<track-breadth>`
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax
    MinMax(TrackBreadth<L>, TrackBreadth<L>),
    /// A `fit-content` function.
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content
    FitContent(L),
}

impl<L> Default for TrackSize<L> {
    fn default() -> Self {
        TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto))
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = try!(TrackKeyword::parse(input));
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                try!(input.expect_comma());
                Ok(TrackSize::MinMax(inflexible_breadth, try!(TrackBreadth::parse(context, input))))
            });
        }

        try!(input.expect_function_matching("fit-content"));
        // FIXME(emilio): This needs a parse_nested_block, doesn't it?
        Ok(try!(LengthOrPercentage::parse(context, input).map(TrackSize::FitContent)))
    }
}

impl<L: ToCss> ToCss for TrackSize<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackSize::Breadth(ref b) => b.to_css(dest),
            TrackSize::MinMax(ref infexible, ref flexible) => {
                try!(dest.write_str("minmax("));
                try!(infexible.to_css(dest));
                try!(dest.write_str(","));
                try!(flexible.to_css(dest));
                dest.write_str(")")
            },
            TrackSize::FitContent(ref lop) => {
                try!(dest.write_str("fit-content("));
                try!(lop.to_css(dest));
                dest.write_str(")")
            },
        }
    }
}

impl HasViewportPercentage for TrackSize<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            TrackSize::Breadth(ref b) => b.has_viewport_percentage(),
            TrackSize::MinMax(ref inf_b, ref b) => inf_b.has_viewport_percentage() || b.has_viewport_percentage(),
            TrackSize::FitContent(ref lop) => lop.has_viewport_percentage(),
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
    type ComputedValue = TrackSize<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(b_1.to_computed_value(context), b_2.to_computed_value(context)),
            TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackSize::Breadth(ref b) =>
                TrackSize::Breadth(ToComputedValue::from_computed_value(b)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(ToComputedValue::from_computed_value(b_1),
                                  ToComputedValue::from_computed_value(b_2)),
            TrackSize::FitContent(ref lop) =>
                TrackSize::FitContent(ToComputedValue::from_computed_value(lop)),
        }
    }
}

/// Parse the grid line names into a vector of owned strings.
///
/// https://drafts.csswg.org/css-grid/#typedef-line-names
pub fn parse_line_names(input: &mut Parser) -> Result<Vec<String>, ()> {
    input.expect_square_bracket_block()?;
    input.parse_nested_block(|input| {
        let mut values = vec![];
        while let Ok(ident) = input.try(|i| i.expect_ident()) {
            if CustomIdent::from_ident((&*ident).into(), &["span"]).is_err() {
                return Err(())
            }

            values.push(ident.into_owned());
        }

        Ok(values)
    })
}
<commit_msg>Add functions for checking <fixed-size> and <fixed-breadth><commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).

use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, CustomIdent, HasViewportPercentage};
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::specified::LengthOrPercentage;

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<grid-line>` type.
///
/// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
pub struct GridLine {
    /// Flag to check whether it's a `span` keyword.
    pub is_span: bool,
    /// A custom identifier for named lines.
    ///
    /// https://drafts.csswg.org/css-grid/#grid-placement-slot
    pub ident: Option<String>,
    /// Denotes the nth grid line from grid item's placement.
    pub integer: Option<i32>,
}

impl Default for GridLine {
    fn default() -> Self {
        GridLine {
            is_span: false,
            ident: None,
            integer: None,
        }
    }
}

impl ToCss for GridLine {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        if !self.is_span && self.ident.is_none() && self.integer.is_none() {
            return dest.write_str("auto")
        }

        if self.is_span {
            try!(dest.write_str("span"));
        }

        if let Some(i) = self.integer {
            try!(write!(dest, " {}", i));
        }

        if let Some(ref s) = self.ident {
            try!(write!(dest, " {}", s));
        }

        Ok(())
    }
}

impl Parse for GridLine {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        let mut grid_line = Default::default();
        if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
            return Ok(grid_line)
        }

        for _ in 0..3 {     // Maximum possible entities for <grid-line>
            if input.try(|i| i.expect_ident_matching("span")).is_ok() {
                if grid_line.is_span {
                    return Err(())
                }
                grid_line.is_span = true;
            } else if let Ok(i) = input.try(|i| i.expect_integer()) {
                if i == 0 || grid_line.integer.is_some() {
                    return Err(())
                }
                grid_line.integer = Some(i);
            } else if let Ok(name) = input.try(|i| i.expect_ident()) {
                if grid_line.ident.is_some() {
                    return Err(())
                }
                grid_line.ident = Some(name.into_owned());
            } else {
                break
            }
        }

        if grid_line.is_span {
            if let Some(i) = grid_line.integer {
                if i < 0 {      // disallow negative integers for grid spans
                    return Err(())
                }
            } else {
                grid_line.integer = Some(1);
            }
        }

        Ok(grid_line)
    }
}

impl ComputedValueAsSpecified for GridLine {}
no_viewport_percentage!(GridLine);

define_css_keyword_enum!{ TrackKeyword:
    "auto" => Auto,
    "max-content" => MaxContent,
    "min-content" => MinContent
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A track breadth for explicit grid track sizing. It's generic solely to
/// avoid re-implementing it for the computed type.
///
/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
pub enum TrackBreadth<L> {
    /// The generic type is almost always a non-negative `<length-percentage>`
    Breadth(L),
    /// A flex fraction specified in `fr` units.
    Flex(CSSFloat),
    /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`)
    Keyword(TrackKeyword),
}

impl<L> TrackBreadth<L> {
    /// Check whether this is a `<fixed-breadth>` (i.e., it only has `<length-percentage>`)
    ///
    /// https://drafts.csswg.org/css-grid/#typedef-fixed-breadth
    #[inline]
    pub fn is_fixed(&self) -> bool {
        match *self {
            TrackBreadth::Breadth(ref _lop) => true,
            _ => false,
        }
    }
}

/// Parse a single flexible length.
pub fn parse_flex(input: &mut Parser) -> Result<CSSFloat, ()> {
    match try!(input.next()) {
        Token::Dimension(ref value, ref unit) if unit.eq_ignore_ascii_case("fr") && value.value.is_sign_positive()
            => Ok(value.value),
        _ => Err(()),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Flex(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl<L: ToCss> ToCss for TrackBreadth<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackBreadth::Breadth(ref lop) => lop.to_css(dest),
            TrackBreadth::Flex(ref value) => write!(dest, "{}fr", value),
            TrackBreadth::Keyword(ref k) => k.to_css(dest),
        }
    }
}

impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        if let TrackBreadth::Breadth(ref lop) = *self {
            lop.has_viewport_percentage()
        } else {
            false
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackBreadth<L> {
    type ComputedValue = TrackBreadth<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackBreadth::Breadth(ref lop) => TrackBreadth::Breadth(lop.to_computed_value(context)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackBreadth::Breadth(ref lop) =>
                TrackBreadth::Breadth(ToComputedValue::from_computed_value(lop)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<track-size>` type for explicit grid track sizing. Like `<track-breadth>`, this is
/// generic only to avoid code bloat. It only takes `<length-percentage>`
///
/// https://drafts.csswg.org/css-grid/#typedef-track-size
pub enum TrackSize<L> {
    /// A flexible `<track-breadth>`
    Breadth(TrackBreadth<L>),
    /// A `minmax` function for a range over an inflexible `<track-breadth>`
    /// and a flexible `<track-breadth>`
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax
    MinMax(TrackBreadth<L>, TrackBreadth<L>),
    /// A `fit-content` function.
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content
    FitContent(L),
}

impl<L> TrackSize<L> {
    /// Check whether this is a `<fixed-size>`
    ///
    /// https://drafts.csswg.org/css-grid/#typedef-fixed-size
    pub fn is_fixed(&self) -> bool {
        match *self {
            TrackSize::Breadth(ref breadth) => breadth.is_fixed(),
            // For minmax function, it could be either
            // minmax(<fixed-breadth>, <track-breadth>) or minmax(<inflexible-breadth>, <fixed-breadth>),
            // and since both variants are a subset of minmax(<inflexible-breadth>, <track-breadth>), we only
            // need to make sure that they're fixed. So, we don't have to modify the parsing function.
            TrackSize::MinMax(ref breadth_1, ref breadth_2) => {
                if breadth_1.is_fixed() {
                    return true     // the second value is always a <track-breadth>
                }

                match *breadth_1 {
                    TrackBreadth::Flex(_) => false,     // should be <inflexible-breadth> at this point
                    _ => breadth_2.is_fixed(),
                }
            },
            TrackSize::FitContent(_) => false,
        }
    }
}

impl<L> Default for TrackSize<L> {
    fn default() -> Self {
        TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto))
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = try!(TrackKeyword::parse(input));
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                try!(input.expect_comma());
                Ok(TrackSize::MinMax(inflexible_breadth, try!(TrackBreadth::parse(context, input))))
            });
        }

        try!(input.expect_function_matching("fit-content"));
        // FIXME(emilio): This needs a parse_nested_block, doesn't it?
        Ok(try!(LengthOrPercentage::parse(context, input).map(TrackSize::FitContent)))
    }
}

impl<L: ToCss> ToCss for TrackSize<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackSize::Breadth(ref b) => b.to_css(dest),
            TrackSize::MinMax(ref infexible, ref flexible) => {
                try!(dest.write_str("minmax("));
                try!(infexible.to_css(dest));
                try!(dest.write_str(","));
                try!(flexible.to_css(dest));
                dest.write_str(")")
            },
            TrackSize::FitContent(ref lop) => {
                try!(dest.write_str("fit-content("));
                try!(lop.to_css(dest));
                dest.write_str(")")
            },
        }
    }
}

impl HasViewportPercentage for TrackSize<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            TrackSize::Breadth(ref b) => b.has_viewport_percentage(),
            TrackSize::MinMax(ref inf_b, ref b) => inf_b.has_viewport_percentage() || b.has_viewport_percentage(),
            TrackSize::FitContent(ref lop) => lop.has_viewport_percentage(),
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
    type ComputedValue = TrackSize<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(b_1.to_computed_value(context), b_2.to_computed_value(context)),
            TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackSize::Breadth(ref b) =>
                TrackSize::Breadth(ToComputedValue::from_computed_value(b)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(ToComputedValue::from_computed_value(b_1),
                                  ToComputedValue::from_computed_value(b_2)),
            TrackSize::FitContent(ref lop) =>
                TrackSize::FitContent(ToComputedValue::from_computed_value(lop)),
        }
    }
}

/// Parse the grid line names into a vector of owned strings.
///
/// https://drafts.csswg.org/css-grid/#typedef-line-names
pub fn parse_line_names(input: &mut Parser) -> Result<Vec<String>, ()> {
    input.expect_square_bracket_block()?;
    input.parse_nested_block(|input| {
        let mut values = vec![];
        while let Ok(ident) = input.try(|i| i.expect_ident()) {
            if CustomIdent::from_ident((&*ident).into(), &["span"]).is_err() {
                return Err(())
            }

            values.push(ident.into_owned());
        }

        Ok(values)
    })
}
<|endoftext|>


<commit_before>extern crate glutin;

use interface::i_ui::{ IUi, InputFiltered, KeyCode, Coord, State };

pub struct XformInput {
    _moving_avg: u32,
}

impl Default for XformInput {

    fn default() -> Self {
        XformInput {
            _moving_avg: 1,
        }
    }

}

impl IUi for XformInput {

    type EventInput = glutin::Event;
    type EventInputFiltered = InputFiltered;

    fn new() -> Self {
        Default::default()
    }

    fn process_input_events( & mut self, e: & [ Self::EventInput ] ) -> Vec< InputFiltered > {
        let filtered = e.iter()
            .map( |x| InputFiltered::from( x ) )
            .filter( |x| if let &InputFiltered::Ignored = x { false } else { true } )
            .inspect( |x| { trace!("{:?}", x); () } )
            .collect();
        filtered
    }
}

///convert glutin::Event into i_ui::InputFiltered
impl< 'a > From< & 'a glutin::Event > for InputFiltered {
    fn from( e: & 'a glutin::Event ) -> Self {
        match e {
            &glutin::Event::WindowEvent{ ref event, .. } => match event {
                &glutin::WindowEvent::Closed => {
                    InputFiltered::Button { key: KeyCode::Close, state: State::Press }
                },
                &glutin::WindowEvent::Resized(_w, _h) => { //todo
                    InputFiltered::Ignored
                },
                &glutin::WindowEvent::ReceivedCharacter(x) => {
                    match x {
                        'a' | 'A' => InputFiltered::Button { key: KeyCode::A, state: State::Press },
                        'b' | 'B' => InputFiltered::Button { key: KeyCode::B, state: State::Press },
                        'c' | 'C' => InputFiltered::Button { key: KeyCode::C, state: State::Press },
                        'd' | 'D' => InputFiltered::Button { key: KeyCode::D, state: State::Press },
                        'e' | 'E' => InputFiltered::Button { key: KeyCode::E, state: State::Press },
                        'f' | 'F' => InputFiltered::Button { key: KeyCode::F, state: State::Press },
                        'g' | 'G' => InputFiltered::Button { key: KeyCode::G, state: State::Press },
                        'h' | 'H' => InputFiltered::Button { key: KeyCode::H, state: State::Press },
                        'i' | 'I' => InputFiltered::Button { key: KeyCode::I, state: State::Press },
                        'j' | 'J' => InputFiltered::Button { key: KeyCode::J, state: State::Press },
                        'k' | 'K' => InputFiltered::Button { key: KeyCode::K, state: State::Press },
                        'l' | 'L' => InputFiltered::Button { key: KeyCode::L, state: State::Press },
                        'm' | 'M' => InputFiltered::Button { key: KeyCode::M, state: State::Press },
                        'n' | 'N' => InputFiltered::Button { key: KeyCode::N, state: State::Press },
                        'o' | 'O' => InputFiltered::Button { key: KeyCode::O, state: State::Press },
                        'p' | 'P' => InputFiltered::Button { key: KeyCode::P, state: State::Press },
                        'q' | 'Q' => InputFiltered::Button { key: KeyCode::Q, state: State::Press },
                        'r' | 'R' => InputFiltered::Button { key: KeyCode::R, state: State::Press },
                        's' | 'S' => InputFiltered::Button { key: KeyCode::S, state: State::Press },
                        't' | 'T' => InputFiltered::Button { key: KeyCode::T, state: State::Press },
                        'u' | 'U' => InputFiltered::Button { key: KeyCode::U, state: State::Press },
                        'v' | 'V' => InputFiltered::Button { key: KeyCode::V, state: State::Press },
                        'w' | 'W' => InputFiltered::Button { key: KeyCode::W, state: State::Press },
                        'x' | 'X' => InputFiltered::Button { key: KeyCode::X, state: State::Press },
                        'y' | 'Y' => InputFiltered::Button { key: KeyCode::Y, state: State::Press },
                        'z' | 'Z' => InputFiltered::Button { key: KeyCode::Z, state: State::Press },
                        '0' => InputFiltered::Button { key: KeyCode::Num0, state: State::Press },
                        '1' => InputFiltered::Button { key: KeyCode::Num1, state: State::Press },
                        '2' => InputFiltered::Button { key: KeyCode::Num2, state: State::Press },
                        '3' => InputFiltered::Button { key: KeyCode::Num3, state: State::Press },
                        '4' => InputFiltered::Button { key: KeyCode::Num4, state: State::Press },
                        '5' => InputFiltered::Button { key: KeyCode::Num5, state: State::Press },
                        '6' => InputFiltered::Button { key: KeyCode::Num6, state: State::Press },
                        '7' => InputFiltered::Button { key: KeyCode::Num7, state: State::Press },
                        '8' => InputFiltered::Button { key: KeyCode::Num8, state: State::Press },
                        '9' => InputFiltered::Button { key: KeyCode::Num9, state: State::Press },
                        _ => {
                            trace!("key events ignored: {:?}", e );
                            InputFiltered::Ignored
                        },
                    }
                },
                &glutin::WindowEvent::AxisMotion { ref axis, ref value, .. } => {
                    // info!("mouse input: {:?}, {:?}", axis, value );
                    let coord = match axis {
                        &0 => { Coord::X },
                        &1 => { Coord::Y },
                        _ => { Coord::Z },
                    };
                    InputFiltered::MouseCoord( coord, *value as f32 )
                },
                &glutin::WindowEvent::KeyboardInput { ref input, .. } => {
                    match input {
                        &glutin::KeyboardInput {
                            ref state,
                            ref virtual_keycode,
                            ..
                        } => {
                            // trace!("probing: {:?}", input );
                            let k = match virtual_keycode {
                                &Some(glutin::VirtualKeyCode::Left) => Some( KeyCode::Left ),
                                &Some(glutin::VirtualKeyCode::Right) => Some( KeyCode::Right ),
                                &Some(glutin::VirtualKeyCode::Up) => Some( KeyCode::Up ),
                                &Some(glutin::VirtualKeyCode::Down) => Some( KeyCode::Down ),
                                _ => None,
                            };
                            let s = match state {
                                &glutin::ElementState::Pressed => State::Press,
                                _ => State::Release,
                            };
                            if let Some( x ) = k {
                                InputFiltered::Button { key: x, state: s }
                            } else {
                                InputFiltered::Ignored
                            }
                        },
                    }
                },
                &glutin::WindowEvent::MouseInput { ref state, ref button, ref _modifiers, .. } => {
                    let k = match button {
                        &glutin::MouseButton::Left  => {
                            Some( KeyCode::MouseL )
                        },
                        &glutin::MouseButton::Right  => {
                            Some( KeyCode::MouseR )
                        },
                        _ => None
                    };
                    let s = match state {
                        &glutin::ElementState::Pressed => State::Press,
                        _ => State::Release,
                    };
                    if let Some( x ) = k {
                        InputFiltered::Button { key: x, state: s }
                    } else {
                        InputFiltered::Ignored
                    }
                },
                _ => {
                    trace!("events input ignored: {:?}", e );
                    InputFiltered::Ignored
                },
            },
            _ => InputFiltered::Ignored
        }
    }
}
<commit_msg>fixed typo.<commit_after>extern crate glutin;

use interface::i_ui::{ IUi, InputFiltered, KeyCode, Coord, State };

pub struct XformInput {
    _moving_avg: u32,
}

impl Default for XformInput {

    fn default() -> Self {
        XformInput {
            _moving_avg: 1, //todo
        }
    }

}

impl IUi for XformInput {

    type EventInput = glutin::Event;
    type EventInputFiltered = InputFiltered;

    fn new() -> Self {
        Default::default()
    }

    fn process_input_events( & mut self, e: & [ Self::EventInput ] ) -> Vec< InputFiltered > {
        let filtered = e.iter()
            .map( |x| InputFiltered::from( x ) )
            .filter( |x| if let &InputFiltered::Ignored = x { false } else { true } )
            .inspect( |x| { trace!("{:?}", x); () } )
            .collect();
        filtered
    }
}

///convert glutin::Event into i_ui::InputFiltered
impl< 'a > From< & 'a glutin::Event > for InputFiltered {
    fn from( e: & 'a glutin::Event ) -> Self {
        match e {
            &glutin::Event::WindowEvent{ ref event, .. } => match event {
                &glutin::WindowEvent::Closed => {
                    InputFiltered::Button { key: KeyCode::Close, state: State::Press }
                },
                &glutin::WindowEvent::Resized(_w, _h) => { //todo
                    InputFiltered::Ignored
                },
                &glutin::WindowEvent::ReceivedCharacter(x) => {
                    match x {
                        'a' | 'A' => InputFiltered::Button { key: KeyCode::A, state: State::Press },
                        'b' | 'B' => InputFiltered::Button { key: KeyCode::B, state: State::Press },
                        'c' | 'C' => InputFiltered::Button { key: KeyCode::C, state: State::Press },
                        'd' | 'D' => InputFiltered::Button { key: KeyCode::D, state: State::Press },
                        'e' | 'E' => InputFiltered::Button { key: KeyCode::E, state: State::Press },
                        'f' | 'F' => InputFiltered::Button { key: KeyCode::F, state: State::Press },
                        'g' | 'G' => InputFiltered::Button { key: KeyCode::G, state: State::Press },
                        'h' | 'H' => InputFiltered::Button { key: KeyCode::H, state: State::Press },
                        'i' | 'I' => InputFiltered::Button { key: KeyCode::I, state: State::Press },
                        'j' | 'J' => InputFiltered::Button { key: KeyCode::J, state: State::Press },
                        'k' | 'K' => InputFiltered::Button { key: KeyCode::K, state: State::Press },
                        'l' | 'L' => InputFiltered::Button { key: KeyCode::L, state: State::Press },
                        'm' | 'M' => InputFiltered::Button { key: KeyCode::M, state: State::Press },
                        'n' | 'N' => InputFiltered::Button { key: KeyCode::N, state: State::Press },
                        'o' | 'O' => InputFiltered::Button { key: KeyCode::O, state: State::Press },
                        'p' | 'P' => InputFiltered::Button { key: KeyCode::P, state: State::Press },
                        'q' | 'Q' => InputFiltered::Button { key: KeyCode::Q, state: State::Press },
                        'r' | 'R' => InputFiltered::Button { key: KeyCode::R, state: State::Press },
                        's' | 'S' => InputFiltered::Button { key: KeyCode::S, state: State::Press },
                        't' | 'T' => InputFiltered::Button { key: KeyCode::T, state: State::Press },
                        'u' | 'U' => InputFiltered::Button { key: KeyCode::U, state: State::Press },
                        'v' | 'V' => InputFiltered::Button { key: KeyCode::V, state: State::Press },
                        'w' | 'W' => InputFiltered::Button { key: KeyCode::W, state: State::Press },
                        'x' | 'X' => InputFiltered::Button { key: KeyCode::X, state: State::Press },
                        'y' | 'Y' => InputFiltered::Button { key: KeyCode::Y, state: State::Press },
                        'z' | 'Z' => InputFiltered::Button { key: KeyCode::Z, state: State::Press },
                        '0' => InputFiltered::Button { key: KeyCode::Num0, state: State::Press },
                        '1' => InputFiltered::Button { key: KeyCode::Num1, state: State::Press },
                        '2' => InputFiltered::Button { key: KeyCode::Num2, state: State::Press },
                        '3' => InputFiltered::Button { key: KeyCode::Num3, state: State::Press },
                        '4' => InputFiltered::Button { key: KeyCode::Num4, state: State::Press },
                        '5' => InputFiltered::Button { key: KeyCode::Num5, state: State::Press },
                        '6' => InputFiltered::Button { key: KeyCode::Num6, state: State::Press },
                        '7' => InputFiltered::Button { key: KeyCode::Num7, state: State::Press },
                        '8' => InputFiltered::Button { key: KeyCode::Num8, state: State::Press },
                        '9' => InputFiltered::Button { key: KeyCode::Num9, state: State::Press },
                        _ => {
                            trace!("key events ignored: {:?}", e );
                            InputFiltered::Ignored
                        },
                    }
                },
                &glutin::WindowEvent::AxisMotion { ref axis, ref value, .. } => {
                    // info!("mouse input: {:?}, {:?}", axis, value );
                    let coord = match axis {
                        &0 => { Coord::X },
                        &1 => { Coord::Y },
                        _ => { Coord::Z },
                    };
                    InputFiltered::MouseCoord( coord, *value as f32 )
                },
                &glutin::WindowEvent::KeyboardInput { ref input, .. } => {
                    match input {
                        &glutin::KeyboardInput {
                            ref state,
                            ref virtual_keycode,
                            ..
                        } => {
                            // trace!("probing: {:?}", input );
                            let k = match virtual_keycode {
                                &Some(glutin::VirtualKeyCode::Left) => Some( KeyCode::Left ),
                                &Some(glutin::VirtualKeyCode::Right) => Some( KeyCode::Right ),
                                &Some(glutin::VirtualKeyCode::Up) => Some( KeyCode::Up ),
                                &Some(glutin::VirtualKeyCode::Down) => Some( KeyCode::Down ),
                                _ => None,
                            };
                            let s = match state {
                                &glutin::ElementState::Pressed => State::Press,
                                _ => State::Release,
                            };
                            if let Some( x ) = k {
                                InputFiltered::Button { key: x, state: s }
                            } else {
                                InputFiltered::Ignored
                            }
                        },
                    }
                },
                &glutin::WindowEvent::MouseInput { ref state, ref button, .. } => {
                    let k = match button {
                        &glutin::MouseButton::Left  => {
                            Some( KeyCode::MouseL )
                        },
                        &glutin::MouseButton::Right  => {
                            Some( KeyCode::MouseR )
                        },
                        _ => None
                    };
                    let s = match state {
                        &glutin::ElementState::Pressed => State::Press,
                        _ => State::Release,
                    };
                    if let Some( x ) = k {
                        InputFiltered::Button { key: x, state: s }
                    } else {
                        InputFiltered::Ignored
                    }
                },
                _ => {
                    trace!("events input ignored: {:?}", e );
                    InputFiltered::Ignored
                },
            },
            _ => InputFiltered::Ignored
        }
    }
}
<|endoftext|>


<commit_before>use std::any::TypeId;

use crate::prelude::*;

use dces::prelude::{Component, Entity, EntityComponentManager};

/// The `WidgetContainer` wraps the entity of a widget and provides access to its properties, its children properties and its parent properties.
pub struct WidgetContainer<'a> {
    ecm: &'a mut EntityComponentManager<Tree>,
    current_node: Entity,
    theme: &'a ThemeValue,
}

impl<'a> WidgetContainer<'a> {
    /// Creates a new widget container for the given `entity`.
    pub fn new(root: Entity, ecm: &'a mut EntityComponentManager<Tree>, theme: &'a ThemeValue) -> Self {
        WidgetContainer {
            ecm,
            current_node: root,
            theme
        }
    }

    /// Gets the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn get
(&self) -> &P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return property;
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Gets a mutable reference of the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn get_mut
(&mut self) -> &mut P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .borrow_mut_component::
(self.current_node)
        {
            return property;
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Clones the property. If the property does not exists for the widget the
    /// default of the property value will be returned,
    pub fn clone_or_default
(&self) -> P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return property.clone();
        }

        P::default()
    }

    /// Clones the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn clone
(&self) -> P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return property.clone();
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Clones the property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_clone
(&self) -> Option

    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return Some(property.clone());
        }

        None
    }

    /// Sets the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn set
(&mut self, value: P)
    where
        P: Component + Default + Clone,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .borrow_mut_component::
(self.current_node)
        {
            *property = value;
            return;
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Returns `true` if the widget has a property of type `P` otherwise `false`.
    pub fn has
(&self) -> bool
    where
        P: Clone + Component + Default,
    {
        self.ecm
            .component_store()
            .borrow_component::
(self.current_node)
            .is_ok()
    }

    /// Returns a reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get
(&self) -> Option<&P> {
        self.ecm
            .component_store()
            .borrow_component::
(self.current_node)
            .ok()
    }

    /// Returns a mutable reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get_mut
(&mut self) -> Option<&mut P> {
        self.ecm
            .component_store_mut()
            .borrow_mut_component::
(self.current_node)
            .ok()
    }
}
<commit_msg>Add theme update ability to widget container.<commit_after>use std::any::TypeId;

use crate::{prelude::*, utils::*};

use dces::prelude::{Component, Entity, EntityComponentManager};

/// The `WidgetContainer` wraps the entity of a widget and provides access to its properties, its children properties and its parent properties.
pub struct WidgetContainer<'a> {
    ecm: &'a mut EntityComponentManager<Tree>,
    current_node: Entity,
    theme: &'a ThemeValue,
}

impl<'a> WidgetContainer<'a> {
    /// Creates a new widget container for the given `entity`.
    pub fn new(
        root: Entity,
        ecm: &'a mut EntityComponentManager<Tree>,
        theme: &'a ThemeValue,
    ) -> Self {
        WidgetContainer {
            ecm,
            current_node: root,
            theme,
        }
    }

    /// Gets the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn get
(&self) -> &P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return property;
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Gets a mutable reference of the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn get_mut
(&mut self) -> &mut P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .borrow_mut_component::
(self.current_node)
        {
            return property;
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Clones the property. If the property does not exists for the widget the
    /// default of the property value will be returned,
    pub fn clone_or_default
(&self) -> P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return property.clone();
        }

        P::default()
    }

    /// Clones the property.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn clone
(&self) -> P
    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return property.clone();
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Clones the property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_clone
(&self) -> Option

    where
        P: Clone + Component + Default,
    {
        if let Ok(property) = self
            .ecm
            .component_store()
            .borrow_component::
(self.current_node)
        {
            return Some(property.clone());
        }

        None
    }

    /// Sets the property of type `P`.
    ///
    /// # Panics
    ///
    /// Panics if the widget does not contains the property.
    pub fn set
(&mut self, value: P)
    where
        P: Component + Default + Clone,
    {
        if let Ok(property) = self
            .ecm
            .component_store_mut()
            .borrow_mut_component::
(self.current_node)
        {
            *property = value;
            return;
        }

        panic!(
            "Entity {} does not contain property type {:?}",
            self.current_node.0,
            TypeId::of::
()
        );
    }

    /// Returns `true` if the widget has a property of type `P` otherwise `false`.
    pub fn has
(&self) -> bool
    where
        P: Clone + Component + Default,
    {
        self.ecm
            .component_store()
            .borrow_component::
(self.current_node)
            .is_ok()
    }

    /// Returns a reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get
(&self) -> Option<&P> {
        self.ecm
            .component_store()
            .borrow_component::
(self.current_node)
            .ok()
    }

    /// Returns a mutable reference of a property of type `P` from the given widget entity. If the entity does
    /// not exists or it doesn't have a component of type `P` `None` will be returned.
    pub fn try_get_mut
(&mut self) -> Option<&mut P> {
        self.ecm
            .component_store_mut()
            .borrow_mut_component::
(self.current_node)
            .ok()
    }

    /// Updates the theme by the inner state e.g. `selected` or `pressed`.
    pub fn update_theme_by_state(&mut self) {
        let selector = self.clone::<Selector>();

        if let Some(focus) = self.try_clone::<Focused>() {
            if focus.0 && !selector.0.pseudo_classes.contains("focus") {
                add_selector_to_widget("focus", self);
            } else if !focus.0 && selector.0.pseudo_classes.contains("focus") {
                remove_selector_from_widget("focus", self)
            }
        }

        if let Some(selected) = self.try_clone::<Selected>() {
            if selected.0 && !selector.0.pseudo_classes.contains("selected") {
                add_selector_to_widget("selected", self);
            } else if !selected.0 && selector.0.pseudo_classes.contains("selected") {
                remove_selector_from_widget("selected", self)
            }
        }

        if let Some(pressed) = self.try_clone::<Pressed>() {
            if pressed.0 && !selector.0.pseudo_classes.contains("active") {
                add_selector_to_widget("active", self);
            } else if !pressed.0 && selector.0.pseudo_classes.contains("active") {
                remove_selector_from_widget("active", self)
            }
        }

        self.update_properties_by_theme();
    }

    /// Update all properties for the theme.
    pub fn update_properties_by_theme(&mut self) {
        if !self.has::<Selector>() {
            return;
        }

        let selector = self.clone::<Selector>();

        if !selector.0.dirty() {
            return;
        }

        if self.has::<Foreground>() {
            if let Some(color) = self.theme.brush("color", &selector.0) {
                self.set::<Foreground>(Foreground::from(color));
            }
        }

        if self.has::<Background>() {
            if let Some(background) = self.theme.brush("background", &selector.0) {
                self.set::<Background>(Background::from(background));
            }
        }

        if self.has::<BorderBrush>() {
            if let Some(border_color) = self.theme.brush("border-color", &selector.0) {
                self.set::<BorderBrush>(BorderBrush::from(border_color));
            }
        }

        if self.has::<BorderRadius>() {
            if let Some(radius) = self.theme.float("border-radius", &selector.0) {
                self.set::<BorderRadius>(BorderRadius::from(radius as f64));
            }
        }

        if self.has::<BorderThickness>() {
            if let Some(border_width) = self.theme.uint("border-width", &selector.0) {
                self.set::<BorderThickness>(BorderThickness::from(border_width as f64));
            }
        }

        if self.has::<FontSize>() {
            if let Some(size) = self.theme.uint("font-size", &selector.0) {
                self.set::<FontSize>(FontSize::from(size as f64));
            }
        }

        if self.has::() {
            if let Some(font_family) = self.theme.string("font-family", &selector.0) {
                self.set::(Font::from(font_family));
            }
        }

        if self.has::<IconBrush>() {
            if let Some(color) = self.theme.brush("icon-color", &selector.0) {
                self.set::<IconBrush>(IconBrush::from(color));
            }
        }

        if self.has::<IconSize>() {
            if let Some(size) = self.theme.uint("icon-size", &selector.0) {
                self.set::<IconSize>(IconSize::from(size as f64));
            }
        }

        if self.has::<IconFont>() {
            if let Some(font_family) = self.theme.string("icon-family", &selector.0) {
                self.set::<IconFont>(IconFont::from(font_family));
            }
        }

        if let Some(padding) = self.try_clone::<Padding>() {
            if let Some(pad) = self.theme.uint("padding", &selector.0) {
                let mut padding = padding;
                padding.set_thickness(pad as f64);
                self.set::<Padding>(padding);
            }
        }

        if let Some(padding) = self.try_clone::<Padding>() {
            if let Some(left) = self.theme.uint("padding-left", &selector.0) {
                let mut padding = padding;
                padding.set_left(left as f64);
                self.set::<Padding>(padding);
            }
        }

        if let Some(padding) = self.try_clone::<Padding>() {
            if let Some(top) = self.theme.uint("padding-top", &selector.0) {
                let mut padding = padding;
                padding.set_top(top as f64);
                self.set::<Padding>(padding);
            }
        }

        if let Some(padding) = self.try_clone::<Padding>() {
            if let Some(right) = self.theme.uint("padding-right", &selector.0) {
                let mut padding = padding;
                padding.set_right(right as f64);
                self.set::<Padding>(padding);
            }
        }

        if let Some(padding) = self.try_clone::<Padding>() {
            if let Some(bottom) = self.theme.uint("padding-bottom", &selector.0) {
                let mut padding = padding;
                padding.set_bottom(bottom as f64);
                self.set::<Padding>(padding);
            }
        }

        // todo padding, icon_margin

        self.get_mut::<Selector>().0.set_dirty(true);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate js;
extern crate libc;

use std::ffi::CStr;
use std::ptr;
use std::str;

use js::{JSCLASS_RESERVED_SLOTS_MASK,JSCLASS_RESERVED_SLOTS_SHIFT,JSCLASS_GLOBAL_SLOT_COUNT,JSCLASS_IS_GLOBAL};
use js::jsapi::_Z24JS_GlobalObjectTraceHookP8JSTracerP8JSObject;
use js::jsapi::{CallArgs,CompartmentOptions,OnNewGlobalHookOption,Rooted,Value};
use js::jsapi::{JS_DefineFunction,JS_Init,JS_NewGlobalObject,JS_EncodeStringToUTF8,JS_ReportError};
use js::jsapi::{JSAutoCompartment,JSAutoRequest,JSContext,JSClass};
use js::jsval::UndefinedValue;
use js::rust::Runtime;

static CLASS: &'static JSClass = &JSClass {
    name: b"test\0" as *const u8 as *const libc::c_char,
    flags: JSCLASS_IS_GLOBAL | ((JSCLASS_GLOBAL_SLOT_COUNT & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT),
    addProperty: None,
    delProperty: None,
    getProperty: None,
    setProperty: None,
    enumerate: None,
    resolve: None,
    convert: None,
    finalize: None,
    call: None,
    hasInstance: None,
    construct: None,
    trace: Some(_Z24JS_GlobalObjectTraceHookP8JSTracerP8JSObject),
    reserved: [0 as *mut _; 25]
};

fn main() {
    unsafe {
        JS_Init();
    }
    let runtime = Runtime::new();
    let context = runtime.cx();

    unsafe {
        let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
        let c_option = CompartmentOptions::default();
        let _ar = JSAutoRequest::new(context);
        let global = JS_NewGlobalObject(context, CLASS, ptr::null_mut(), h_option, &c_option);
        let global_root = Rooted::new(context, global);
        let global = global_root.handle();
        let _ac = JSAutoCompartment::new(context, global.get());
        JS_DefineFunction(context, global, b"puts\0".as_ptr() as *const libc::c_char, Some(puts), 1, 0);
        let javascript = "puts('Test Iñtërnâtiônàlizætiøn ┬─┬ノ( º _ ºノ) ');".to_string();
        let _ = runtime.evaluate_script(global, javascript, "test.js".to_string(), 0);
    }
}

unsafe extern "C" fn puts(context: *mut JSContext, argc: u32, vp: *mut Value) -> u8 {
    let args = CallArgs::from_vp(vp, argc);

    if args.argc_ != 1 {
        JS_ReportError(context, b"puts() requires exactly 1 argument\0".as_ptr() as *const libc::c_char);
        return 0;
    }

    let arg = args.get(0);
    let js = js::rust::ToString(context, arg);
    let message_root = Rooted::new(context, js);
    let message = JS_EncodeStringToUTF8(context, message_root.handle());
    let message = CStr::from_ptr(message);
    println!("{}", str::from_utf8(message.to_bytes()).unwrap());

    args.rval().set(UndefinedValue());
    return 1;
}
<commit_msg>Auto merge of #199 - servo:check-example, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate js;
extern crate libc;

use std::ffi::CStr;
use std::ptr;
use std::str;

use js::{JSCLASS_RESERVED_SLOTS_MASK,JSCLASS_RESERVED_SLOTS_SHIFT,JSCLASS_GLOBAL_SLOT_COUNT,JSCLASS_IS_GLOBAL};
use js::jsapi::_Z24JS_GlobalObjectTraceHookP8JSTracerP8JSObject;
use js::jsapi::{CallArgs,CompartmentOptions,OnNewGlobalHookOption,Rooted,Value};
use js::jsapi::{JS_DefineFunction,JS_Init,JS_NewGlobalObject,JS_EncodeStringToUTF8,JS_ReportError};
use js::jsapi::{JSAutoCompartment,JSAutoRequest,JSContext,JSClass};
use js::jsval::UndefinedValue;
use js::rust::Runtime;

static CLASS: &'static JSClass = &JSClass {
    name: b"test\0" as *const u8 as *const libc::c_char,
    flags: JSCLASS_IS_GLOBAL | ((JSCLASS_GLOBAL_SLOT_COUNT & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT),
    addProperty: None,
    delProperty: None,
    getProperty: None,
    setProperty: None,
    enumerate: None,
    resolve: None,
    convert: None,
    finalize: None,
    call: None,
    hasInstance: None,
    construct: None,
    trace: Some(_Z24JS_GlobalObjectTraceHookP8JSTracerP8JSObject),
    reserved: [0 as *mut _; 25]
};

fn main() {
    unsafe {
        JS_Init();
    }
    let runtime = Runtime::new();
    let context = runtime.cx();

    unsafe {
        let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
        let c_option = CompartmentOptions::default();
        let _ar = JSAutoRequest::new(context);
        let global = JS_NewGlobalObject(context, CLASS, ptr::null_mut(), h_option, &c_option);
        let global_root = Rooted::new(context, global);
        let global = global_root.handle();
        let _ac = JSAutoCompartment::new(context, global.get());
        let function = JS_DefineFunction(context, global, b"puts\0".as_ptr() as *const libc::c_char,
                                         Some(puts), 1, 0);
        assert!(!function.is_null());
        let javascript = "puts('Test Iñtërnâtiônàlizætiøn ┬─┬ノ( º _ ºノ) ');".to_string();
        let _ = runtime.evaluate_script(global, javascript, "test.js".to_string(), 0);
    }
}

unsafe extern "C" fn puts(context: *mut JSContext, argc: u32, vp: *mut Value) -> u8 {
    let args = CallArgs::from_vp(vp, argc);

    if args.argc_ != 1 {
        JS_ReportError(context, b"puts() requires exactly 1 argument\0".as_ptr() as *const libc::c_char);
        return 0;
    }

    let arg = args.get(0);
    let js = js::rust::ToString(context, arg);
    let message_root = Rooted::new(context, js);
    let message = JS_EncodeStringToUTF8(context, message_root.handle());
    let message = CStr::from_ptr(message);
    println!("{}", str::from_utf8(message.to_bytes()).unwrap());

    args.rval().set(UndefinedValue());
    return 1;
}
<|endoftext|>