<commit_before>use crate::prelude::*;

/// A `Brush` describes how a shape is filled or stroked.  A `Brush`
/// can be parse from a string (themes are parsing brushes that way).
/// With the given implementation you can choose between three methods
/// to define a solid color:
///
/// A. Use `color codes`
///
/// Define the value with a symbol "#" followed by 6 letters or numbers.
/// These numbers are in hexadecimal numeral system.
/// For example `#f00` will give you red. If you write `#00ff00`, you will
/// get blue and you also included an alpha channel.
///
/// B. Use `a function`
///
/// Currently the unique available functions that interprete a color are
/// destincted with the keywords `rgb`, `hsv`, `hsb`, `hsl`. There are
/// `alpha variants` as well. `hsb` is an alias to `hsv`.
/// Alpha variants are coded with the keywords `rgba`, `abgr`  or `argb`.
/// Here is an example to define a color via the function method:
/// `hsl(197, 71%, 73%)` will provide you a pretty skyblue color.
/// For `rgb` and `rgba` the range of the values are 0-255.
/// Any other keyword will use floating point integers to define the color
/// value. `hsva(0.0-360.0, 0.0-1.0, 0.0-1.0, 0.0-1.0)` is such an example.
/// In addition you can choose to use percent values (`%` sign) for the given
/// parameters.
/// When appending the `%` sign to the range parameters of the `rgb` function
/// call, the values are mapped to 0.0-100.0 (percent) or 0.0-1.0 (min/max).
/// For all other keywords (`hsv`, `hsb`, `hsl`) you are not allowed to append
/// the percent sign to the first parameter. If you append `%` to the following
/// parameters, OrbTk will interpret the values in a range between `0.0-100.0`.
///
/// C. Use the `color name`
///
/// OrbTK maintains a color name map (crates/utils/colors.txt). It enables
/// you, to directly choose from the listed color names. The toolkit will
/// decode the value with the corresponding color code.
/// Example color names are:
///  * white
///  * red
///  * olive,
///  * bombay
///
/// You can also define a gradient with an expression. Its syntax is
/// structured as follows:
/// ```
/// [repeating-]linear-gradient({Gradient-angle}{deg|rad|turn}, ...) [{X Displacement}px {Y Displacement}px]
/// ```
///
/// Within the braces (`{}`) you define the customized parameters.
/// The pipe (`|`) is offering mutual exclusive variants (e.g: degrees(deg),
/// radians(rad) or turns(turn)).
/// The syntax offers optional paramters inside brackets (`[]`).
/// The three points (`...`) refer to multiple stops. They are respected when
/// a gradient is rendered. Use the following syntax:
///
/// ```
/// {Color} [{Stop /// position}{%|px}]
/// ```
///
/// Quite a bit of theory. Lets see some examples:
///
/// ```
/// * linear-gradient(0deg, #4b6cb7, #182848)
/// * repeating-linear-gradient(0.25turn, rgba(255, 255, 0, 0.6), dodgerblue, deepskyblue)
/// * linear-gradient(-90deg, hsv(201, 94%, 80.5%), steelblue)
/// ```
///
/// Oh yes, I do like blue (smile)! Anyway, these examples should
/// introduce the concept and provide some nice implementations using
/// degrees and orientations.
/// You are free to adopt it as appropriate.
#[derive(Clone, PartialEq, Debug)]
pub enum Brush {
    /// Paints an area with a solid color.
    SolidColor(Color),

    /// Paints an area with a gradient.
    Gradient(Gradient),
}

impl Brush {
    pub fn is_transparent(&self) -> bool {
        match self {
            Brush::SolidColor(color) => color.a() == 0,
            _ => false,
        }
    }
}

impl From<Brush> for Color {
    fn from(b: Brush) -> Color {
        match b {
            Brush::SolidColor(color) => color,
            _ => Color::rgb(0, 0, 0),
        }
    }
}

impl From<Brush> for Gradient {
    fn from(b: Brush) -> Gradient {
        match b {
            Brush::Gradient(g) => g,
            _ => Gradient::default(),
        }
    }
}

impl Default for Brush {
    fn default() -> Self {
        Brush::SolidColor(Color::rgba(0, 0, 0, 0))
    }
}

impl From<Color> for Brush {
    fn from(c: Color) -> Brush {
        Brush::SolidColor(c)
    }
}

impl From<Gradient> for Brush {
    fn from(g: Gradient) -> Brush {
        Brush::Gradient(g)
    }
}

impl From<&str> for Brush {
    fn from(s: &str) -> Brush {
        Expression::from(s).brush().unwrap_or_default()
    }
}

impl From<String> for Brush {
    fn from(s: String) -> Brush {
        Self::from(&s[..])
    }
}

impl From<Value> for Brush {
    fn from(v: Value) -> Self {
        let value = v.get::<String>();
        Brush::from(value)
    }
}

#[cfg(test)]
mod tests {
    //  use crate::prelude::*;
    // todo: tbd after brush struct is finished
}
<commit_msg>brush: update documentation section, introduce directions<commit_after>use crate::prelude::*;

/// A `Brush` defines the fill pattern of shapes.
/// The syntax allows to express fill patterns in several ways:
///
/// * solid colors
/// * colors with alpha channel
/// * gradients of colors
/// * gradients with directions
/// * gradients with angles
///
/// The string declaration of a `Brush` is composed combining the following
/// syntax elements:
///
/// 1. The `color name`
/// 2. The `gradient` string
///    * the gradient type (linear, repeating-linear)
///    * gradient attributes (direction-identifier, angles, color names )
///
/// ## Examples
/// Here are some implementations with declarations of colors, degrees, orientations and directions.
///
/// ```text
/// .foreground("white")
/// .background("black")
/// .background("linear-gradient(0deg, #4b6cb7, #182848)")
/// .background("repeating-linear-gradient(0.25turn, rgba(255, 255, 0, 0.6), dodgerblue, deepskyblue)")
/// .background("linear-gradient(-90deg, hsv(201, 94%, 80.5%), steelblue)")
/// .background("linear-gradient(to top right, white, skyblue 60%, lightskyblue 80%, yellow 83%, yellow)")
/// ```
/// Read on to see how the syntax is composed.
///
/// ## Definition of a color name
/// With the given implementation you can choose between three methods
/// to define a color.
///
/// A. `color codes`
///
/// You can define the value of a color with a symbol "#" followed
/// by letters or numbers. These numbers are in hexadecimal numeral system.
/// The short variant will use 3 numbers , the long variant will use 6
/// numbers.
/// For example `#f00` will give you red. If you write `#0000ff`, you will
/// get blue.
/// To include an alpha channel, the short variant takes 4 numbers.
/// If you need a yellow with 50.2% opaque, you use `#ff08`.
/// In the long form you need 8 numbers. `#0000ff80` represents 50.2% opaque
/// (non-premultiplied) blue.
///
/// B. `color function`
///
/// Currently the unique available functions that interpret a color are
/// distincted with the keywords `rgb`, `hsv`, `hsb`, `hsl`. There are
/// `alpha variants` as well. `hsb` is an alias to `hsv`.
/// Alpha variants are coded with the keywords `rgba`, `abgr`  or `argb`.
/// Here is an example to define a color via the function method:
/// `hsl(197, 71%, 73%)` will provide you a pretty skyblue color.
/// For `rgb` and `rgba` the range of the values are 0-255.
/// Any other keyword will use floating point integers to define the color
/// value. `hsva(0.0-360.0, 0.0-1.0, 0.0-1.0, 0.0-1.0)` is such an example.
/// In addition you can choose to use percent values (`%` sign) for the given
/// parameters.
/// When appending the `%` sign to the range parameters of the `rgb` function
/// call, the values are mapped to 0.0-100.0 (percent) or 0.0-1.0 (min/max).
/// For all other keywords (`hsv`, `hsb`, `hsl`) you are not allowed to append
/// the percent sign to the first parameter. If you append `%` to the following
/// parameters, OrbTk will interpret the values in a range between `0.0-100.0`.
///
/// C. `color name`
///
/// **WIP: The given implementation is using (utils/colors.txt). This has to be adopted!!!**
///
/// OrbTK maintains color names as constants [`utils::const_colors`]. It enables
/// you, to directly choose their string value inside the code.
/// Example color names are:
///
///  * COLOR_WHITE
///  * COLOR_RED
///  * COLOR_OLIVE
///  * COLOR_LINK_WATER
///  * COLOR_SLATE_GRAY
///
/// ## Definition of a gradient
/// The syntax of a gradient definition is structured as follows:
///
/// * Optional parameters are inside brackets (`[]`).
/// * Within braces (`{}`) you define the appropriate parameter value.
/// * The pipe (`|`) is offering mutual exclusive variants
///   e.g: degrees(deg), radians(rad) or turns(turn).
/// * Three points (`...`) refer to multiple stops.
///   They are respected when a gradient is rendered.
///
/// The next example shows the structure of an angled gradient
///
/// ```
/// [repeating-]linear-gradient({Gradient-angle}{deg|rad|turn}, ...) [{X Displacement}px {Y Displacement}px], {Color} [{Stop  position}{%|px}]

/// ```
///
/// This example shows the structure of a gradient that will be rendered in a given direction
///
/// ```
/// [repeating-]linear-gradient({direction-identifier}, {initial color-name}, {terminating color-name}
/// ```
///
//#[cfg(feature = "nightly")]
//#[doc(include = "../colors.md")]

#[derive(Clone, PartialEq, Debug)]
pub enum Brush {
    /// Paints an area with a solid color.
    SolidColor(Color),

    /// Paints an area with a gradient.
    Gradient(Gradient),
}

impl Brush {
    pub fn is_transparent(&self) -> bool {
        match self {
            Brush::SolidColor(color) => color.a() == 0,
            _ => false,
        }
    }
}

impl From<Brush> for Color {
    fn from(b: Brush) -> Color {
        match b {
            Brush::SolidColor(color) => color,
            _ => Color::rgb(0, 0, 0),
        }
    }
}

impl From<Brush> for Gradient {
    fn from(b: Brush) -> Gradient {
        match b {
            Brush::Gradient(g) => g,
            _ => Gradient::default(),
        }
    }
}

impl Default for Brush {
    fn default() -> Self {
        Brush::SolidColor(Color::rgba(0, 0, 0, 0))
    }
}

impl From<Color> for Brush {
    fn from(c: Color) -> Brush {
        Brush::SolidColor(c)
    }
}

impl From<Gradient> for Brush {
    fn from(g: Gradient) -> Brush {
        Brush::Gradient(g)
    }
}

impl From<&str> for Brush {
    fn from(s: &str) -> Brush {
        Expression::from(s).brush().unwrap_or_default()
    }
}

impl From<String> for Brush {
    fn from(s: String) -> Brush {
        Self::from(&s[..])
    }
}

impl From<Value> for Brush {
    fn from(v: Value) -> Self {
        let value = v.get::<String>();
        Brush::from(value)
    }
}

#[cfg(test)]
mod tests {
    //  use crate::prelude::*;
    // todo: tbd after brush struct is finished
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use super::super::*;
use assert_approx_eq::assert_approx_eq;
use once_cell::sync::Lazy;
use prometheus::{proto::MetricFamily, Counter, IntCounter, Opts, Registry};
use rusty_fork::rusty_fork_test;

const INT_COUNTER_NAME: &str = "INT_COUNTER";
pub static INT_COUNTER: Lazy<IntCounter> =
    Lazy::new(|| register_int_counter!(INT_COUNTER_NAME, "An integer counter").unwrap());

rusty_fork_test! {
#[test]
fn gather_metrics_test() {
    let iterations = 12;
    for _ in 0..iterations {
        INT_COUNTER.inc();
    }

    for (metric, value) in get_all_metrics() {
        // The metric seems to be METRIC_NAME{}, so this is intended to be agile
        if metric.starts_with(INT_COUNTER_NAME) {
            assert_eq!(value, iterations.to_string());
            return;
        }
    }
    panic!("Metric {} not found", INT_COUNTER_NAME);
}
}

// To test if the placeholder static metrics registered in Registry, a counter type metric,
// has been successfully published to prometheus and the result gathered reflect the value change.
#[test]
fn publish_metrics_test() {
    let counter_opts = Opts::new("diem_test_counter", "diem test counter help");
    let counter = Counter::with_opts(counter_opts).unwrap();

    let r = Registry::new();
    r.register(Box::new(counter.clone())).unwrap();
    counter.inc();

    let metric_families = r.gather();

    assert_eq!(metric_families.len(), 1);
    let m: &MetricFamily = metric_families.get(0).unwrap();
    assert_eq!("diem test counter help", m.get_help());
    assert_eq!("diem_test_counter", m.get_name());

    let metrics = m.get_metric();
    assert_eq!(metrics.len(), 1);
    assert_approx_eq!(1.0, metrics.get(0).unwrap().get_counter().get_value());
}

rusty_fork_test! {
#[test]
fn get_all_metrics_test() {
    INT_COUNTER.inc();

    let metrics = get_all_metrics();
    assert_eq!(metrics.len(), 1);
    for (k, v) in metrics {
        assert_eq!(
            v.parse::<i32>().unwrap(), 1,
            "{} has unexpected value {}",
            k,
            v
        );
    }
}
}
<commit_msg>[rename] diem[ _]test[ _]counters -> test[ _]counters<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use super::super::*;
use assert_approx_eq::assert_approx_eq;
use once_cell::sync::Lazy;
use prometheus::{proto::MetricFamily, Counter, IntCounter, Opts, Registry};
use rusty_fork::rusty_fork_test;

const INT_COUNTER_NAME: &str = "INT_COUNTER";
pub static INT_COUNTER: Lazy<IntCounter> =
    Lazy::new(|| register_int_counter!(INT_COUNTER_NAME, "An integer counter").unwrap());

rusty_fork_test! {
#[test]
fn gather_metrics_test() {
    let iterations = 12;
    for _ in 0..iterations {
        INT_COUNTER.inc();
    }

    for (metric, value) in get_all_metrics() {
        // The metric seems to be METRIC_NAME{}, so this is intended to be agile
        if metric.starts_with(INT_COUNTER_NAME) {
            assert_eq!(value, iterations.to_string());
            return;
        }
    }
    panic!("Metric {} not found", INT_COUNTER_NAME);
}
}

// To test if the placeholder static metrics registered in Registry, a counter type metric,
// has been successfully published to prometheus and the result gathered reflect the value change.
#[test]
fn publish_metrics_test() {
    let counter_opts = Opts::new("test_counter", "test counter help");
    let counter = Counter::with_opts(counter_opts).unwrap();

    let r = Registry::new();
    r.register(Box::new(counter.clone())).unwrap();
    counter.inc();

    let metric_families = r.gather();

    assert_eq!(metric_families.len(), 1);
    let m: &MetricFamily = metric_families.get(0).unwrap();
    assert_eq!("test counter help", m.get_help());
    assert_eq!("test_counter", m.get_name());

    let metrics = m.get_metric();
    assert_eq!(metrics.len(), 1);
    assert_approx_eq!(1.0, metrics.get(0).unwrap().get_counter().get_value());
}

rusty_fork_test! {
#[test]
fn get_all_metrics_test() {
    INT_COUNTER.inc();

    let metrics = get_all_metrics();
    assert_eq!(metrics.len(), 1);
    for (k, v) in metrics {
        assert_eq!(
            v.parse::<i32>().unwrap(), 1,
            "{} has unexpected value {}",
            k,
            v
        );
    }
}
}
<|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/. */

use dom::bindings::codegen::Bindings::DOMStringMapBinding;
use dom::bindings::codegen::Bindings::DOMStringMapBinding::DOMStringMapMethods;
use dom::bindings::error::ErrorResult;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::htmlelement::HTMLElement;
use dom::node::window_from_node;
use util::str::DOMString;

#[dom_struct]
pub struct DOMStringMap {
    reflector_: Reflector,
    element: JS<HTMLElement>,
}

impl DOMStringMap {
    fn new_inherited(element: &HTMLElement) -> DOMStringMap {
        DOMStringMap {
            reflector_: Reflector::new(),
            element: JS::from_ref(element),
        }
    }

    pub fn new(element: &HTMLElement) -> Root<DOMStringMap> {
        let window = window_from_node(element);
        reflect_dom_object(box DOMStringMap::new_inherited(element),
                           GlobalRef::Window(window.r()), DOMStringMapBinding::Wrap)
    }
}

// https://html.spec.whatwg.org/multipage/#domstringmap
impl DOMStringMapMethods for DOMStringMap {
    // https://html.spec.whatwg.org/multipage/#dom-domstringmap-removeitem
    fn NamedDeleter(&self, name: DOMString) {
        let element = self.element.root();
        element.r().delete_custom_attr(name)
    }

    // https://html.spec.whatwg.org/multipage/#dom-domstringmap-setitem
    fn NamedSetter(&self, name: DOMString, value: DOMString) -> ErrorResult {
        let element = self.element.root();
        element.r().set_custom_attr(name, value)
    }

    // https://html.spec.whatwg.org/multipage/#dom-domstringmap-nameditem
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> DOMString {
        let element = self.element.root();
        match element.r().get_custom_attr(name) {
            Some(value) => {
                *found = true;
                value.clone()
            },
            None => {
                *found = false;
                String::new()
            }
        }
    }

    // https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        // FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
        vec![]
    }
}
<commit_msg>Do not root DOMStringMap::element<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/. */

use dom::bindings::codegen::Bindings::DOMStringMapBinding;
use dom::bindings::codegen::Bindings::DOMStringMapBinding::DOMStringMapMethods;
use dom::bindings::error::ErrorResult;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::htmlelement::HTMLElement;
use dom::node::window_from_node;
use util::str::DOMString;

#[dom_struct]
pub struct DOMStringMap {
    reflector_: Reflector,
    element: JS<HTMLElement>,
}

impl DOMStringMap {
    fn new_inherited(element: &HTMLElement) -> DOMStringMap {
        DOMStringMap {
            reflector_: Reflector::new(),
            element: JS::from_ref(element),
        }
    }

    pub fn new(element: &HTMLElement) -> Root<DOMStringMap> {
        let window = window_from_node(element);
        reflect_dom_object(box DOMStringMap::new_inherited(element),
                           GlobalRef::Window(window.r()), DOMStringMapBinding::Wrap)
    }
}

// https://html.spec.whatwg.org/multipage/#domstringmap
impl DOMStringMapMethods for DOMStringMap {
    // https://html.spec.whatwg.org/multipage/#dom-domstringmap-removeitem
    fn NamedDeleter(&self, name: DOMString) {
        self.element.delete_custom_attr(name)
    }

    // https://html.spec.whatwg.org/multipage/#dom-domstringmap-setitem
    fn NamedSetter(&self, name: DOMString, value: DOMString) -> ErrorResult {
        self.element.set_custom_attr(name, value)
    }

    // https://html.spec.whatwg.org/multipage/#dom-domstringmap-nameditem
    fn NamedGetter(&self, name: DOMString, found: &mut bool) -> DOMString {
        match self.element.get_custom_attr(name) {
            Some(value) => {
                *found = true;
                value.clone()
            },
            None => {
                *found = false;
                String::new()
            }
        }
    }

    // https://html.spec.whatwg.org/multipage/#the-domstringmap-interface:supported-property-names
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        // FIXME: unimplemented (https://github.com/servo/servo/issues/7273)
        vec![]
    }
}
<|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/. */

use dom::bindings::codegen::DocumentBinding;
use dom::bindings::utils::{DOMString, WrapperCache, ErrorResult, Fallible};
use dom::bindings::utils::{BindingObject, CacheableWrapper, DerivedWrapper};
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable, null_str_as_empty};
use dom::element::{Element};
use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId};
use dom::event::Event;
use dom::htmlcollection::HTMLCollection;
use dom::htmldocument::HTMLDocument;
use dom::htmlelement::HTMLElement;
use dom::htmlhtmlelement::HTMLHtmlElement;
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId};
use dom::text::Text;
use dom::window::Window;
use dom::windowproxy::WindowProxy;
use dom::htmltitleelement::HTMLTitleElement;
use html::hubbub_html_parser::build_element_from_tag;
use js::jsapi::{JSObject, JSContext, JSVal};
use js::jsapi::{JSTRACE_OBJECT, JSTracer, JS_CallTracer};
use js::glue::RUST_OBJECT_TO_JSVAL;
use servo_util::tree::TreeNodeRef;

use std::cast;
use std::ptr;
use std::str::eq_slice;
use std::libc;
use std::ascii::StrAsciiExt;
use std::unstable::raw::Box;

pub trait WrappableDocument {
    fn init_wrapper(@mut self, cx: *JSContext);
}

#[deriving(Eq)]
pub struct AbstractDocument {
    document: *Document
}

impl AbstractDocument {
    pub fn as_abstract<T: WrappableDocument>(cx: *JSContext, doc: @mut T) -> AbstractDocument {
        doc.init_wrapper(cx);
        AbstractDocument {
            document: unsafe { cast::transmute(doc) }
        }
    }

    unsafe fn transmute<T, R>(&self, f: &fn(&T) -> R) -> R {
        let box: *Box<T> = cast::transmute(self.document);
        f(&(*box).data)
    }

    unsafe fn transmute_mut<T, R>(&self, f: &fn(&mut T) -> R) -> R {
        let box: *mut Box<T> = cast::transmute(self.document);
        f(&mut (*box).data)
    }

    pub fn with_base<R>(&self, callback: &fn(&Document) -> R) -> R {
        unsafe {
            self.transmute(callback)
        }
    }

    pub fn with_mut_base<R>(&self, callback: &fn(&mut Document) -> R) -> R {
        unsafe {
            self.transmute_mut(callback)
        }
    }

    pub fn with_html<R>(&self, callback: &fn(&HTMLDocument) -> R) -> R {
        match self.with_base(|doc| doc.doctype) {
            HTML => unsafe { self.transmute(callback) },
            _ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument")
        }
    }

    pub fn set_root(&mut self, root: AbstractNode<ScriptView>) {
        self.with_mut_base(|document| {
            document.set_root(root);
        });
    }
}

pub enum DocumentType {
    HTML,
    SVG,
    XML
}

pub struct Document {
    root: Option<AbstractNode<ScriptView>>,
    wrapper: WrapperCache,
    window: Option<@mut Window>,
    doctype: DocumentType,
    title: ~str
}

impl Document {
    #[fixed_stack_segment]
    pub fn new(window: Option<@mut Window>, doctype: DocumentType) -> Document {
        Document {
            root: None,
            wrapper: WrapperCache::new(),
            window: window,
            doctype: doctype,
            title: ~""
        }
    }

    pub fn set_root(&mut self, root: AbstractNode<ScriptView>) {
        self.root = Some(root);
    }

    pub fn Constructor(owner: @mut Window) -> Fallible<AbstractDocument> {
        let cx = owner.page.js_info.get_ref().js_compartment.cx.ptr;

        let mut document = AbstractDocument::as_abstract(cx, @mut Document::new(None, XML));

        let root = @HTMLHtmlElement {
            htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html")
        };
        let root = unsafe { Node::as_abstract_node(cx, root) };
        document.set_root(root);

        Ok(document)
    }
}

impl WrappableDocument for Document {
    fn init_wrapper(@mut self, cx: *JSContext) {
        self.wrap_object_shared(cx, ptr::null()); //XXXjdm a proper scope would be nice
    }
}

impl CacheableWrapper for AbstractDocument {
    fn get_wrappercache(&mut self) -> &mut WrapperCache {
        do self.with_mut_base |doc| {
            doc.get_wrappercache()
        }
    }

    fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
        match self.with_base(|doc| doc.doctype) {
            HTML => {
                let doc: @mut HTMLDocument = unsafe { cast::transmute(self.document) };
                doc.wrap_object_shared(cx, scope)
            }
            XML | SVG => {
                fail!("no wrapping for documents that don't exist")
            }
        }
    }
}

impl BindingObject for AbstractDocument {
    fn GetParentObject(&self, cx: *JSContext) -> Option<@mut CacheableWrapper> {
        do self.with_mut_base |doc| {
            doc.GetParentObject(cx)
        }
    }
}

impl DerivedWrapper for AbstractDocument {
    #[fixed_stack_segment]
    fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
        let cache = self.get_wrappercache();
        let wrapper = cache.get_wrapper();
        unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
        return 1;
    }

    fn wrap_shared(@mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
        fail!(~"nyi")
    }
}

impl CacheableWrapper for Document {
    fn get_wrappercache(&mut self) -> &mut WrapperCache {
        unsafe {
            cast::transmute(&self.wrapper)
        }
    }

    fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
        let mut unused = false;
        DocumentBinding::Wrap(cx, scope, self, &mut unused)
    }
}

impl BindingObject for Document {
    fn GetParentObject(&self, _cx: *JSContext) -> Option<@mut CacheableWrapper> {
        match self.window {
            Some(win) => Some(win as @mut CacheableWrapper),
            None => None
        }
    }
}

impl Document {
    pub fn URL(&self) -> DOMString {
        None
    }

    pub fn DocumentURI(&self) -> DOMString {
        None
    }

    pub fn CompatMode(&self) -> DOMString {
        None
    }

    pub fn CharacterSet(&self) -> DOMString {
        None
    }

    pub fn ContentType(&self) -> DOMString {
        None
    }

    pub fn GetDocumentElement(&self) -> Option<AbstractNode<ScriptView>> {
        self.root
    }

    fn get_cx(&self) -> *JSContext {
        let win = self.window.get_ref();
        win.page.js_info.get_ref().js_compartment.cx.ptr
    }

    fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
        let win = self.window.get_ref();
        let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
        let cache = win.get_wrappercache();
        let scope = cache.get_wrapper();
        (scope, cx)
    }

    pub fn GetElementsByTagName(&self, tag: &DOMString) -> @mut HTMLCollection {
        self.createHTMLCollection(|elem| eq_slice(elem.tag_name, null_str_as_empty(tag)))
    }

    pub fn GetElementsByTagNameNS(&self, _ns: &DOMString, _tag: &DOMString) -> @mut HTMLCollection {
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(~[], cx, scope)
    }

    pub fn GetElementsByClassName(&self, _class: &DOMString) -> @mut HTMLCollection {
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(~[], cx, scope)
    }

    pub fn GetElementById(&self, _id: &DOMString) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn CreateElement(&self, local_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
        let cx = self.get_cx();
        let local_name = null_str_as_empty(local_name);
        if !is_valid_element_name(local_name) {
            return Err(InvalidCharacter);
        }
        let local_name = local_name.to_ascii_lower();
        Ok(build_element_from_tag(cx, local_name))
    }

    pub fn CreateElementNS(&self, _namespace: &DOMString, _qualified_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
        fail!("stub")
    }

    pub fn CreateTextNode(&self, data: &DOMString) -> AbstractNode<ScriptView> {
        let cx = self.get_cx();
        unsafe { Node::as_abstract_node(cx, @Text::new(null_str_as_empty(data))) }
    }

    pub fn CreateEvent(&self, _interface: &DOMString) -> Fallible<@mut Event> {
        fail!("stub")
    }

    pub fn GetInputEncoding(&self) -> DOMString {
        None
    }

    pub fn Referrer(&self) -> DOMString {
        None
    }

    pub fn LastModified(&self) -> DOMString {
        None
    }

    pub fn ReadyState(&self) -> DOMString {
        None
    }

    pub fn Title(&self) -> DOMString {
        let mut title = ~"";
        match self.doctype {
            SVG => {
                fail!("no SVG document yet")
            },
            _ => {
                match self.root {
                    None => {},
                    Some(root) => {
                        let _ = for node in root.traverse_preorder() {
                            if node.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) {
                                loop;
                            }
                            for child in node.children() {
                                if child.is_text() {
                                    do child.with_imm_text() |text| {
                                        let s = text.element.Data();
                                        title = title + null_str_as_empty(&s);
                                    }
                                }
                            }
                            break;
                        };
                    }
                }
            }
        }
        let v: ~[&str] = title.word_iter().collect();
        title = v.connect(" ");
        title = title.trim().to_owned();
        Some(title)
    }

    pub fn SetTitle(&self, title: &DOMString) -> ErrorResult {
        match self.doctype {
            SVG => {
                fail!("no SVG document yet")
            },
            _ => {
                let (_scope, cx) = self.get_scope_and_cx();
                match self.root {
                    None => {},
                    Some(root) => {
                        let _ = for node in root.traverse_preorder() {
                            if node.type_id() != ElementNodeTypeId(HTMLHeadElementTypeId) {
                                loop;
                            }
                            let mut has_title = false;
                            for child in node.children() {
                                if child.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) {
                                    loop;
                                }
                                has_title = true;
                                for title_child in child.children() {
                                    child.remove_child(title_child);
                                }
                                child.add_child(self.CreateTextNode(title));
                                break;
                            }
                            if !has_title {
                                let new_title = @HTMLTitleElement {
                                    htmlelement: HTMLElement::new(HTMLTitleElementTypeId, ~"title")
                                };
                                let new_title = unsafe {
                                    Node::as_abstract_node(cx, new_title)
                                };
                                new_title.add_child(self.CreateTextNode(title));
                                node.add_child(new_title);
                            }
                            break;
                        };
                    }
                }
            }
        }
        Ok(())
    }

    pub fn Dir(&self) -> DOMString {
        None
    }

    pub fn SetDir(&self, _dir: &DOMString) {
    }

    pub fn GetDefaultView(&self) -> Option<@mut WindowProxy> {
        None
    }

    pub fn GetActiveElement(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn HasFocus(&self) -> Fallible<bool> {
        Ok(false)
    }

    pub fn GetCurrentScript(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozFullScreenEnabled(&self) -> bool {
        false
    }

    pub fn GetMozFullScreenElement(&self) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }

    pub fn GetMozPointerLockElement(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn MozExitPointerLock(&self) {
    }

    pub fn Hidden(&self) -> bool {
        false
    }

    pub fn MozHidden(&self) -> bool {
        self.Hidden()
    }

    pub fn VisibilityState(&self) -> DocumentBinding::VisibilityState {
        DocumentBinding::VisibilityStateValues::Visible
    }

    pub fn MozVisibilityState(&self) -> DocumentBinding::VisibilityState {
        self.VisibilityState()
    }

    pub fn GetSelectedStyleSheetSet(&self) -> DOMString {
        None
    }

    pub fn SetSelectedStyleSheetSet(&self, _sheet: &DOMString) {
    }

    pub fn GetLastStyleSheetSet(&self) -> DOMString {
        None
    }

    pub fn GetPreferredStyleSheetSet(&self) -> DOMString {
        None
    }

    pub fn EnableStyleSheetsForSet(&self, _name: &DOMString) {
    }

    pub fn ElementFromPoint(&self, _x: f32, _y: f32) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn QuerySelector(&self, _selectors: &DOMString) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }

    pub fn GetElementsByName(&self, name: &DOMString) -> @mut HTMLCollection {
        self.createHTMLCollection(|elem|
            elem.get_attr("name").is_some() && eq_slice(elem.get_attr("name").unwrap(), null_str_as_empty(name)))
    }

    pub fn createHTMLCollection(&self, callback: &fn(elem: &Element) -> bool) -> @mut HTMLCollection {
        let mut elements = ~[];
        match self.root {
            None => {},
            Some(root) => {
                let _ = for child in root.traverse_preorder() {
                    if child.is_element() {
                        do child.with_imm_element |elem| {
                            if callback(elem) {
                                elements.push(child);
                            }
                        }
                    }
                };
            }
        }
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(elements, cx, scope)
    }

    pub fn content_changed(&self) {
        for window in self.window.iter() {
            window.content_changed()
        }
    }

    pub fn wait_until_safe_to_modify_dom(&self) {
        for window in self.window.iter() {
            window.wait_until_safe_to_modify_dom();
        }
    }
}

impl Traceable for Document {
    #[fixed_stack_segment]
    fn trace(&self, tracer: *mut JSTracer) {
        match self.root {
            None => {},
            Some(root) => {
                unsafe {
                    (*tracer).debugPrinter = ptr::null();
                    (*tracer).debugPrintIndex = -1;
                    do "root".to_c_str().with_ref |name| {
                        (*tracer).debugPrintArg = name as *libc::c_void;
                        debug!("tracing root node");
                        do root.with_base |node| {
                            JS_CallTracer(tracer as *JSTracer,
                                          node.wrapper.wrapper,
                                          JSTRACE_OBJECT as u32);
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Address review comments.<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/. */

use dom::bindings::codegen::DocumentBinding;
use dom::bindings::utils::{DOMString, WrapperCache, ErrorResult, Fallible};
use dom::bindings::utils::{BindingObject, CacheableWrapper, DerivedWrapper};
use dom::bindings::utils::{is_valid_element_name, InvalidCharacter, Traceable, null_str_as_empty};
use dom::element::{Element};
use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId};
use dom::event::Event;
use dom::htmlcollection::HTMLCollection;
use dom::htmldocument::HTMLDocument;
use dom::htmlelement::HTMLElement;
use dom::htmlhtmlelement::HTMLHtmlElement;
use dom::node::{AbstractNode, ScriptView, Node, ElementNodeTypeId};
use dom::text::Text;
use dom::window::Window;
use dom::windowproxy::WindowProxy;
use dom::htmltitleelement::HTMLTitleElement;
use html::hubbub_html_parser::build_element_from_tag;
use js::jsapi::{JSObject, JSContext, JSVal};
use js::jsapi::{JSTRACE_OBJECT, JSTracer, JS_CallTracer};
use js::glue::RUST_OBJECT_TO_JSVAL;
use servo_util::tree::TreeNodeRef;

use std::cast;
use std::ptr;
use std::str::eq_slice;
use std::libc;
use std::ascii::StrAsciiExt;
use std::unstable::raw::Box;

pub trait WrappableDocument {
    fn init_wrapper(@mut self, cx: *JSContext);
}

#[deriving(Eq)]
pub struct AbstractDocument {
    document: *Document
}

impl AbstractDocument {
    pub fn as_abstract<T: WrappableDocument>(cx: *JSContext, doc: @mut T) -> AbstractDocument {
        doc.init_wrapper(cx);
        AbstractDocument {
            document: unsafe { cast::transmute(doc) }
        }
    }

    unsafe fn transmute<T, R>(&self, f: &fn(&T) -> R) -> R {
        let box: *Box<T> = cast::transmute(self.document);
        f(&(*box).data)
    }

    unsafe fn transmute_mut<T, R>(&self, f: &fn(&mut T) -> R) -> R {
        let box: *mut Box<T> = cast::transmute(self.document);
        f(&mut (*box).data)
    }

    pub fn with_base<R>(&self, callback: &fn(&Document) -> R) -> R {
        unsafe {
            self.transmute(callback)
        }
    }

    pub fn with_mut_base<R>(&self, callback: &fn(&mut Document) -> R) -> R {
        unsafe {
            self.transmute_mut(callback)
        }
    }

    pub fn with_html<R>(&self, callback: &fn(&HTMLDocument) -> R) -> R {
        match self.with_base(|doc| doc.doctype) {
            HTML => unsafe { self.transmute(callback) },
            _ => fail!("attempt to downcast a non-HTMLDocument to HTMLDocument")
        }
    }

    pub fn set_root(&self, root: AbstractNode<ScriptView>) {
        self.with_mut_base(|document| {
            document.set_root(root);
        });
    }
}

pub enum DocumentType {
    HTML,
    SVG,
    XML
}

pub struct Document {
    root: Option<AbstractNode<ScriptView>>,
    wrapper: WrapperCache,
    window: Option<@mut Window>,
    doctype: DocumentType,
    title: ~str
}

impl Document {
    #[fixed_stack_segment]
    pub fn new(window: Option<@mut Window>, doctype: DocumentType) -> Document {
        Document {
            root: None,
            wrapper: WrapperCache::new(),
            window: window,
            doctype: doctype,
            title: ~""
        }
    }

    pub fn set_root(&mut self, root: AbstractNode<ScriptView>) {
        self.root = Some(root);
    }

    pub fn Constructor(owner: @mut Window) -> Fallible<AbstractDocument> {
        let cx = owner.page.js_info.get_ref().js_compartment.cx.ptr;

        let mut document = AbstractDocument::as_abstract(cx, @mut Document::new(None, XML));

        let root = @HTMLHtmlElement {
            htmlelement: HTMLElement::new(HTMLHtmlElementTypeId, ~"html")
        };
        let root = unsafe { Node::as_abstract_node(cx, root) };
        document.set_root(root);

        Ok(document)
    }
}

impl WrappableDocument for Document {
    fn init_wrapper(@mut self, cx: *JSContext) {
        self.wrap_object_shared(cx, ptr::null()); //XXXjdm a proper scope would be nice
    }
}

impl CacheableWrapper for AbstractDocument {
    fn get_wrappercache(&mut self) -> &mut WrapperCache {
        do self.with_mut_base |doc| {
            doc.get_wrappercache()
        }
    }

    fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
        match self.with_base(|doc| doc.doctype) {
            HTML => {
                let doc: @mut HTMLDocument = unsafe { cast::transmute(self.document) };
                doc.wrap_object_shared(cx, scope)
            }
            XML | SVG => {
                fail!("no wrapping for documents that don't exist")
            }
        }
    }
}

impl BindingObject for AbstractDocument {
    fn GetParentObject(&self, cx: *JSContext) -> Option<@mut CacheableWrapper> {
        do self.with_mut_base |doc| {
            doc.GetParentObject(cx)
        }
    }
}

impl DerivedWrapper for AbstractDocument {
    #[fixed_stack_segment]
    fn wrap(&mut self, _cx: *JSContext, _scope: *JSObject, vp: *mut JSVal) -> i32 {
        let cache = self.get_wrappercache();
        let wrapper = cache.get_wrapper();
        unsafe { *vp = RUST_OBJECT_TO_JSVAL(wrapper) };
        return 1;
    }

    fn wrap_shared(@mut self, _cx: *JSContext, _scope: *JSObject, _vp: *mut JSVal) -> i32 {
        fail!(~"nyi")
    }
}

impl CacheableWrapper for Document {
    fn get_wrappercache(&mut self) -> &mut WrapperCache {
        unsafe {
            cast::transmute(&self.wrapper)
        }
    }

    fn wrap_object_shared(@mut self, cx: *JSContext, scope: *JSObject) -> *JSObject {
        let mut unused = false;
        DocumentBinding::Wrap(cx, scope, self, &mut unused)
    }
}

impl BindingObject for Document {
    fn GetParentObject(&self, _cx: *JSContext) -> Option<@mut CacheableWrapper> {
        match self.window {
            Some(win) => Some(win as @mut CacheableWrapper),
            None => None
        }
    }
}

impl Document {
    pub fn URL(&self) -> DOMString {
        None
    }

    pub fn DocumentURI(&self) -> DOMString {
        None
    }

    pub fn CompatMode(&self) -> DOMString {
        None
    }

    pub fn CharacterSet(&self) -> DOMString {
        None
    }

    pub fn ContentType(&self) -> DOMString {
        None
    }

    pub fn GetDocumentElement(&self) -> Option<AbstractNode<ScriptView>> {
        self.root
    }

    fn get_cx(&self) -> *JSContext {
        let win = self.window.get_ref();
        win.page.js_info.get_ref().js_compartment.cx.ptr
    }

    fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
        let win = self.window.get_ref();
        let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
        let cache = win.get_wrappercache();
        let scope = cache.get_wrapper();
        (scope, cx)
    }

    pub fn GetElementsByTagName(&self, tag: &DOMString) -> @mut HTMLCollection {
        self.createHTMLCollection(|elem| eq_slice(elem.tag_name, null_str_as_empty(tag)))
    }

    pub fn GetElementsByTagNameNS(&self, _ns: &DOMString, _tag: &DOMString) -> @mut HTMLCollection {
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(~[], cx, scope)
    }

    pub fn GetElementsByClassName(&self, _class: &DOMString) -> @mut HTMLCollection {
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(~[], cx, scope)
    }

    pub fn GetElementById(&self, _id: &DOMString) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn CreateElement(&self, local_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
        let cx = self.get_cx();
        let local_name = null_str_as_empty(local_name);
        if !is_valid_element_name(local_name) {
            return Err(InvalidCharacter);
        }
        let local_name = local_name.to_ascii_lower();
        Ok(build_element_from_tag(cx, local_name))
    }

    pub fn CreateElementNS(&self, _namespace: &DOMString, _qualified_name: &DOMString) -> Fallible<AbstractNode<ScriptView>> {
        fail!("stub")
    }

    pub fn CreateTextNode(&self, data: &DOMString) -> AbstractNode<ScriptView> {
        let cx = self.get_cx();
        unsafe { Node::as_abstract_node(cx, @Text::new(null_str_as_empty(data))) }
    }

    pub fn CreateEvent(&self, _interface: &DOMString) -> Fallible<@mut Event> {
        fail!("stub")
    }

    pub fn GetInputEncoding(&self) -> DOMString {
        None
    }

    pub fn Referrer(&self) -> DOMString {
        None
    }

    pub fn LastModified(&self) -> DOMString {
        None
    }

    pub fn ReadyState(&self) -> DOMString {
        None
    }

    pub fn Title(&self) -> DOMString {
        let mut title = ~"";
        match self.doctype {
            SVG => {
                fail!("no SVG document yet")
            },
            _ => {
                match self.root {
                    None => {},
                    Some(root) => {
                        for node in root.traverse_preorder() {
                            if node.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) {
                                loop;
                            }
                            for child in node.children() {
                                if child.is_text() {
                                    do child.with_imm_text() |text| {
                                        let s = text.element.Data();
                                        title = title + null_str_as_empty(&s);
                                    }
                                }
                            }
                            break;
                        };
                    }
                }
            }
        }
        let v: ~[&str] = title.word_iter().collect();
        title = v.connect(" ");
        title = title.trim().to_owned();
        Some(title)
    }

    pub fn SetTitle(&self, title: &DOMString) -> ErrorResult {
        match self.doctype {
            SVG => {
                fail!("no SVG document yet")
            },
            _ => {
                let (_scope, cx) = self.get_scope_and_cx();
                match self.root {
                    None => {},
                    Some(root) => {
                        for node in root.traverse_preorder() {
                            if node.type_id() != ElementNodeTypeId(HTMLHeadElementTypeId) {
                                loop;
                            }
                            let mut has_title = false;
                            for child in node.children() {
                                if child.type_id() != ElementNodeTypeId(HTMLTitleElementTypeId) {
                                    loop;
                                }
                                has_title = true;
                                for title_child in child.children() {
                                    child.remove_child(title_child);
                                }
                                child.add_child(self.CreateTextNode(title));
                                break;
                            }
                            if !has_title {
                                let new_title = @HTMLTitleElement {
                                    htmlelement: HTMLElement::new(HTMLTitleElementTypeId, ~"title")
                                };
                                let new_title = unsafe {
                                    Node::as_abstract_node(cx, new_title)
                                };
                                new_title.add_child(self.CreateTextNode(title));
                                node.add_child(new_title);
                            }
                            break;
                        };
                    }
                }
            }
        }
        Ok(())
    }

    pub fn Dir(&self) -> DOMString {
        None
    }

    pub fn SetDir(&self, _dir: &DOMString) {
    }

    pub fn GetDefaultView(&self) -> Option<@mut WindowProxy> {
        None
    }

    pub fn GetActiveElement(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn HasFocus(&self) -> Fallible<bool> {
        Ok(false)
    }

    pub fn GetCurrentScript(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn ReleaseCapture(&self) {
    }

    pub fn MozFullScreenEnabled(&self) -> bool {
        false
    }

    pub fn GetMozFullScreenElement(&self) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }

    pub fn GetMozPointerLockElement(&self) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn MozExitPointerLock(&self) {
    }

    pub fn Hidden(&self) -> bool {
        false
    }

    pub fn MozHidden(&self) -> bool {
        self.Hidden()
    }

    pub fn VisibilityState(&self) -> DocumentBinding::VisibilityState {
        DocumentBinding::VisibilityStateValues::Visible
    }

    pub fn MozVisibilityState(&self) -> DocumentBinding::VisibilityState {
        self.VisibilityState()
    }

    pub fn GetSelectedStyleSheetSet(&self) -> DOMString {
        None
    }

    pub fn SetSelectedStyleSheetSet(&self, _sheet: &DOMString) {
    }

    pub fn GetLastStyleSheetSet(&self) -> DOMString {
        None
    }

    pub fn GetPreferredStyleSheetSet(&self) -> DOMString {
        None
    }

    pub fn EnableStyleSheetsForSet(&self, _name: &DOMString) {
    }

    pub fn ElementFromPoint(&self, _x: f32, _y: f32) -> Option<AbstractNode<ScriptView>> {
        None
    }

    pub fn QuerySelector(&self, _selectors: &DOMString) -> Fallible<Option<AbstractNode<ScriptView>>> {
        Ok(None)
    }

    pub fn GetElementsByName(&self, name: &DOMString) -> @mut HTMLCollection {
        self.createHTMLCollection(|elem|
            elem.get_attr("name").is_some() && eq_slice(elem.get_attr("name").unwrap(), null_str_as_empty(name)))
    }

    pub fn createHTMLCollection(&self, callback: &fn(elem: &Element) -> bool) -> @mut HTMLCollection {
        let mut elements = ~[];
        match self.root {
            None => {},
            Some(root) => {
                for child in root.traverse_preorder() {
                    if child.is_element() {
                        do child.with_imm_element |elem| {
                            if callback(elem) {
                                elements.push(child);
                            }
                        }
                    }
                };
            }
        }
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(elements, cx, scope)
    }

    pub fn content_changed(&self) {
        for window in self.window.iter() {
            window.content_changed()
        }
    }

    pub fn wait_until_safe_to_modify_dom(&self) {
        for window in self.window.iter() {
            window.wait_until_safe_to_modify_dom();
        }
    }
}

impl Traceable for Document {
    #[fixed_stack_segment]
    fn trace(&self, tracer: *mut JSTracer) {
        match self.root {
            None => {},
            Some(root) => {
                unsafe {
                    (*tracer).debugPrinter = ptr::null();
                    (*tracer).debugPrintIndex = -1;
                    do "root".to_c_str().with_ref |name| {
                        (*tracer).debugPrintArg = name as *libc::c_void;
                        debug!("tracing root node");
                        do root.with_base |node| {
                            JS_CallTracer(tracer as *JSTracer,
                                          node.wrapper.wrapper,
                                          JSTRACE_OBJECT as u32);
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use layers::{ARGB32Format, ContainerLayerKind, Image, ImageLayerKind, RGB24Format};
use layers::{TiledImageLayerKind};
use scene::Scene;

use geom::matrix::{Matrix4, ortho};
use opengles::gl2;
use opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, CLAMP_TO_EDGE, COMPILE_STATUS};
use opengles::gl2::{FRAGMENT_SHADER, LINEAR, LINK_STATUS, NEAREST, NO_ERROR, REPEAT, RGB, RGBA,
                      BGRA};
use opengles::gl2::{STATIC_DRAW, TEXTURE_2D, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{TRIANGLE_STRIP, UNPACK_ALIGNMENT, UNPACK_CLIENT_STORAGE_APPLE, UNSIGNED_BYTE};
use opengles::gl2::{UNPACK_ROW_LENGTH, UNSIGNED_BYTE, UNSIGNED_INT_8_8_8_8_REV, VERTEX_SHADER};
use opengles::gl2::{GLclampf, GLenum, GLint, GLsizei, GLuint, attach_shader, bind_buffer};
use opengles::gl2::{bind_texture, buffer_data, create_program, clear, clear_color};
use opengles::gl2::{compile_shader, create_shader, draw_arrays, enable};
use opengles::gl2::{enable_vertex_attrib_array, gen_buffers, gen_textures};
use opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use opengles::gl2::{get_shader_info_log, get_shader_iv};
use opengles::gl2::{get_uniform_location, link_program, pixel_store_i, shader_source};
use opengles::gl2::{tex_image_2d, tex_parameter_i, uniform_1i, uniform_matrix_4fv, use_program};
use opengles::gl2::{vertex_attrib_pointer_f32, viewport};

use io::println;
use libc::c_int;
use str::to_bytes;

pub fn FRAGMENT_SHADER_SOURCE() -> ~str {
    ~"
        #ifdef GLES2
            precision mediump float;
        #endif

        varying vec2 vTextureCoord;

        uniform sampler2DRect uSampler;

        void main(void) {
            gl_FragColor = texture2DRect(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
        }
    "
}

pub fn VERTEX_SHADER_SOURCE() -> ~str {
    ~"
        attribute vec3 aVertexPosition;
        attribute vec2 aTextureCoord;

        uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;

        varying vec2 vTextureCoord;

        void main(void) {
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
            vTextureCoord = aTextureCoord;
        }
    "
}

pub fn load_shader(source_string: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[ to_bytes(source_string) ]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(#fmt("error: %d", get_error() as int));
        fail ~"failed to compile shader";
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(#fmt("shader info log: %s", get_shader_info_log(shader_id)));
        fail ~"failed to compile shader";
    }

    return shader_id;
}

pub struct RenderContext {
    program: GLuint,
    vertex_position_attr: c_int,
    texture_coord_attr: c_int,
    modelview_uniform: c_int,
    projection_uniform: c_int,
    sampler_uniform: c_int,
    vertex_buffer: GLuint,
    texture_coord_buffer: GLuint,
}

pub fn RenderContext(program: GLuint) -> RenderContext {
    let (vertex_buffer, texture_coord_buffer) = init_buffers();
    let rc = RenderContext {
        program: program,
        vertex_position_attr: get_attrib_location(program, ~"aVertexPosition"),
        texture_coord_attr: get_attrib_location(program, ~"aTextureCoord"),
        modelview_uniform: get_uniform_location(program, ~"uMVMatrix"),
        projection_uniform: get_uniform_location(program, ~"uPMatrix"),
        sampler_uniform: get_uniform_location(program, ~"uSampler"),
        vertex_buffer: vertex_buffer,
        texture_coord_buffer: texture_coord_buffer,
    };

    enable_vertex_attrib_array(rc.vertex_position_attr as GLuint);
    enable_vertex_attrib_array(rc.texture_coord_attr as GLuint);

    rc
}

pub fn init_render_context() -> RenderContext {
    let vertex_shader = load_shader(VERTEX_SHADER_SOURCE(), VERTEX_SHADER);
    let fragment_shader = load_shader(FRAGMENT_SHADER_SOURCE(), FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail ~"failed to initialize program";
    }

    use_program(program);

    enable(TEXTURE_2D);
    enable(TEXTURE_RECTANGLE_ARB);

    return RenderContext(program);
}

pub fn init_buffers() -> (GLuint, GLuint) {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);

    let (_0, _1) = (0.0f32, 1.0f32);
    let vertices = ~[
        _0, _0, _0,
        _0, _1, _0,
        _1, _0, _0,
        _1, _1, _0
    ];

    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);

    let texture_coord_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, texture_coord_buffer);

    return (triangle_vertex_buffer, texture_coord_buffer);
}

pub fn create_texture_for_image_if_necessary(image: @Image) {
    match image.texture {
        None => {}
        Some(_) => { return; /* Nothing to do. */ }
    }

    #debug("making texture");

    let texture = gen_textures(1 as GLsizei)[0];
    bind_texture(TEXTURE_RECTANGLE_ARB, texture);

    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, LINEAR as GLint);

    // These two are needed for DMA on the Mac. Don't touch them unless you know what you're doing!
    let stride = image.data.stride() as GLsizei;
    pixel_store_i(UNPACK_ALIGNMENT, 4);
    pixel_store_i(UNPACK_ROW_LENGTH, stride);
    if stride % 32 != 0 {
        info!("rust-layers: suggest using stride multiples of 32 for DMA on the Mac");
    }

    // FIXME: This makes the lifetime requirements somewhat complex...
    pixel_store_i(UNPACK_CLIENT_STORAGE_APPLE, 1);

    let size = image.data.size();
    match image.data.format() {
        RGB24Format => {
            do image.data.with_data |data| {
                tex_image_2d(TEXTURE_RECTANGLE_ARB, 0 as GLint, RGB as GLint,
                             size.width as GLsizei, size.height as GLsizei, 0 as GLint, RGB,
                             UNSIGNED_BYTE, Some(data));
            }
        }
        ARGB32Format => {
            do image.data.with_data |data| {
                tex_parameter_i(TEXTURE_RECTANGLE_ARB, gl2::TEXTURE_STORAGE_HINT_APPLE,
                                gl2::STORAGE_CACHED_APPLE as GLint);

                tex_image_2d(TEXTURE_RECTANGLE_ARB, 0 as GLint, RGBA as GLint,
                             size.width as GLsizei, size.height as GLsizei, 0 as GLint, BGRA,
                             UNSIGNED_INT_8_8_8_8_REV, Some(data));
            }
        }
    }

    image.texture = Some(texture);
}

pub fn bind_and_render_quad(render_context: RenderContext, size: Size2D<uint>, texture: GLuint) {
    bind_texture(TEXTURE_2D, texture);

    uniform_1i(render_context.sampler_uniform, 0);

    bind_buffer(ARRAY_BUFFER, render_context.vertex_buffer);
    vertex_attrib_pointer_f32(render_context.vertex_position_attr as GLuint, 3, false, 0, 0);

    // Create the texture coordinate array.
    bind_buffer(ARRAY_BUFFER, render_context.texture_coord_buffer);

    let (width, height) = (size.width as f32, size.height as f32);
    let vertices = [
        0.0f32, 0.0f32,
        0.0f32, height,
        width,  0.0f32,
        width,  height
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);

    vertex_attrib_pointer_f32(render_context.texture_coord_attr as GLuint, 2, false, 0, 0);

    draw_arrays(TRIANGLE_STRIP, 0, 4);
}

// Layer rendering

pub trait Render {
    fn render(render_context: RenderContext);
}

impl @layers::ImageLayer : Render {
    fn render(render_context: RenderContext) {
        create_texture_for_image_if_necessary(self.image);

        uniform_matrix_4fv(render_context.modelview_uniform, false,
                           self.common.transform.to_array());

        bind_and_render_quad(
            render_context, self.image.data.size(), option::get(&self.image.texture));
    }
}

impl @layers::TiledImageLayer : Render {
    fn render(render_context: RenderContext) {
        let tiles_down = self.tiles.len() / self.tiles_across;
        for self.tiles.eachi |i, tile| {
            create_texture_for_image_if_necessary(*tile);

            let x = ((i % self.tiles_across) as f32);
            let y = ((i / self.tiles_across) as f32);

            let transform = self.common.transform.scale(&(1.0f32 / (self.tiles_across as f32)),
                                                        &(1.0f32 / (tiles_down as f32)),
                                                        &1.0f32);
            let transform = transform.translate(&(x * 1.0f32), &(y * 1.0f32), &0.0f32);

            uniform_matrix_4fv(render_context.modelview_uniform, false, transform.to_array());

            bind_and_render_quad(render_context, tile.data.size(), option::get(&tile.texture));
        }
    }
}

pub fn render_scene(render_context: RenderContext, scene: &Scene) {
    // Set the viewport.
    viewport(0 as GLint, 0 as GLint, scene.size.width as GLsizei, scene.size.height as GLsizei);

    // Clear the screen.
    clear_color(0.38f32, 0.36f32, 0.36f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    // Set the projection matrix.
    let projection_matrix = ortho(0.0f32, copy scene.size.width, copy scene.size.height, 0.0f32,
                                  -10.0f32, 10.0f32);
    uniform_matrix_4fv(render_context.projection_uniform, false, projection_matrix.to_array());

    match copy scene.root {
        ContainerLayerKind(*) => fail ~"container layers unsupported",
        ImageLayerKind(image_layer) => image_layer.render(render_context),
        TiledImageLayerKind(tiled_image_layer) => tiled_image_layer.render(render_context)
    }
}

<commit_msg>Remove extraneous by-ref to option::get()<commit_after>use layers::{ARGB32Format, ContainerLayerKind, Image, ImageLayerKind, RGB24Format};
use layers::{TiledImageLayerKind};
use scene::Scene;

use geom::matrix::{Matrix4, ortho};
use opengles::gl2;
use opengles::gl2::{ARRAY_BUFFER, COLOR_BUFFER_BIT, CLAMP_TO_EDGE, COMPILE_STATUS};
use opengles::gl2::{FRAGMENT_SHADER, LINEAR, LINK_STATUS, NEAREST, NO_ERROR, REPEAT, RGB, RGBA,
                      BGRA};
use opengles::gl2::{STATIC_DRAW, TEXTURE_2D, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{TRIANGLE_STRIP, UNPACK_ALIGNMENT, UNPACK_CLIENT_STORAGE_APPLE, UNSIGNED_BYTE};
use opengles::gl2::{UNPACK_ROW_LENGTH, UNSIGNED_BYTE, UNSIGNED_INT_8_8_8_8_REV, VERTEX_SHADER};
use opengles::gl2::{GLclampf, GLenum, GLint, GLsizei, GLuint, attach_shader, bind_buffer};
use opengles::gl2::{bind_texture, buffer_data, create_program, clear, clear_color};
use opengles::gl2::{compile_shader, create_shader, draw_arrays, enable};
use opengles::gl2::{enable_vertex_attrib_array, gen_buffers, gen_textures};
use opengles::gl2::{get_attrib_location, get_error, get_program_iv};
use opengles::gl2::{get_shader_info_log, get_shader_iv};
use opengles::gl2::{get_uniform_location, link_program, pixel_store_i, shader_source};
use opengles::gl2::{tex_image_2d, tex_parameter_i, uniform_1i, uniform_matrix_4fv, use_program};
use opengles::gl2::{vertex_attrib_pointer_f32, viewport};

use io::println;
use libc::c_int;
use str::to_bytes;

pub fn FRAGMENT_SHADER_SOURCE() -> ~str {
    ~"
        #ifdef GLES2
            precision mediump float;
        #endif

        varying vec2 vTextureCoord;

        uniform sampler2DRect uSampler;

        void main(void) {
            gl_FragColor = texture2DRect(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
        }
    "
}

pub fn VERTEX_SHADER_SOURCE() -> ~str {
    ~"
        attribute vec3 aVertexPosition;
        attribute vec2 aTextureCoord;

        uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;

        varying vec2 vTextureCoord;

        void main(void) {
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
            vTextureCoord = aTextureCoord;
        }
    "
}

pub fn load_shader(source_string: ~str, shader_type: GLenum) -> GLuint {
    let shader_id = create_shader(shader_type);
    shader_source(shader_id, ~[ to_bytes(source_string) ]);
    compile_shader(shader_id);

    if get_error() != NO_ERROR {
        println(#fmt("error: %d", get_error() as int));
        fail ~"failed to compile shader";
    }

    if get_shader_iv(shader_id, COMPILE_STATUS) == (0 as GLint) {
        println(#fmt("shader info log: %s", get_shader_info_log(shader_id)));
        fail ~"failed to compile shader";
    }

    return shader_id;
}

pub struct RenderContext {
    program: GLuint,
    vertex_position_attr: c_int,
    texture_coord_attr: c_int,
    modelview_uniform: c_int,
    projection_uniform: c_int,
    sampler_uniform: c_int,
    vertex_buffer: GLuint,
    texture_coord_buffer: GLuint,
}

pub fn RenderContext(program: GLuint) -> RenderContext {
    let (vertex_buffer, texture_coord_buffer) = init_buffers();
    let rc = RenderContext {
        program: program,
        vertex_position_attr: get_attrib_location(program, ~"aVertexPosition"),
        texture_coord_attr: get_attrib_location(program, ~"aTextureCoord"),
        modelview_uniform: get_uniform_location(program, ~"uMVMatrix"),
        projection_uniform: get_uniform_location(program, ~"uPMatrix"),
        sampler_uniform: get_uniform_location(program, ~"uSampler"),
        vertex_buffer: vertex_buffer,
        texture_coord_buffer: texture_coord_buffer,
    };

    enable_vertex_attrib_array(rc.vertex_position_attr as GLuint);
    enable_vertex_attrib_array(rc.texture_coord_attr as GLuint);

    rc
}

pub fn init_render_context() -> RenderContext {
    let vertex_shader = load_shader(VERTEX_SHADER_SOURCE(), VERTEX_SHADER);
    let fragment_shader = load_shader(FRAGMENT_SHADER_SOURCE(), FRAGMENT_SHADER);

    let program = create_program();
    attach_shader(program, vertex_shader);
    attach_shader(program, fragment_shader);
    link_program(program);

    if get_program_iv(program, LINK_STATUS) == (0 as GLint) {
        fail ~"failed to initialize program";
    }

    use_program(program);

    enable(TEXTURE_2D);
    enable(TEXTURE_RECTANGLE_ARB);

    return RenderContext(program);
}

pub fn init_buffers() -> (GLuint, GLuint) {
    let triangle_vertex_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, triangle_vertex_buffer);

    let (_0, _1) = (0.0f32, 1.0f32);
    let vertices = ~[
        _0, _0, _0,
        _0, _1, _0,
        _1, _0, _0,
        _1, _1, _0
    ];

    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);

    let texture_coord_buffer = gen_buffers(1 as GLsizei)[0];
    bind_buffer(ARRAY_BUFFER, texture_coord_buffer);

    return (triangle_vertex_buffer, texture_coord_buffer);
}

pub fn create_texture_for_image_if_necessary(image: @Image) {
    match image.texture {
        None => {}
        Some(_) => { return; /* Nothing to do. */ }
    }

    #debug("making texture");

    let texture = gen_textures(1 as GLsizei)[0];
    bind_texture(TEXTURE_RECTANGLE_ARB, texture);

    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, CLAMP_TO_EDGE as GLint);
    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_T, CLAMP_TO_EDGE as GLint);
    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MAG_FILTER, LINEAR as GLint);
    tex_parameter_i(TEXTURE_RECTANGLE_ARB, TEXTURE_MIN_FILTER, LINEAR as GLint);

    // These two are needed for DMA on the Mac. Don't touch them unless you know what you're doing!
    let stride = image.data.stride() as GLsizei;
    pixel_store_i(UNPACK_ALIGNMENT, 4);
    pixel_store_i(UNPACK_ROW_LENGTH, stride);
    if stride % 32 != 0 {
        info!("rust-layers: suggest using stride multiples of 32 for DMA on the Mac");
    }

    // FIXME: This makes the lifetime requirements somewhat complex...
    pixel_store_i(UNPACK_CLIENT_STORAGE_APPLE, 1);

    let size = image.data.size();
    match image.data.format() {
        RGB24Format => {
            do image.data.with_data |data| {
                tex_image_2d(TEXTURE_RECTANGLE_ARB, 0 as GLint, RGB as GLint,
                             size.width as GLsizei, size.height as GLsizei, 0 as GLint, RGB,
                             UNSIGNED_BYTE, Some(data));
            }
        }
        ARGB32Format => {
            do image.data.with_data |data| {
                tex_parameter_i(TEXTURE_RECTANGLE_ARB, gl2::TEXTURE_STORAGE_HINT_APPLE,
                                gl2::STORAGE_CACHED_APPLE as GLint);

                tex_image_2d(TEXTURE_RECTANGLE_ARB, 0 as GLint, RGBA as GLint,
                             size.width as GLsizei, size.height as GLsizei, 0 as GLint, BGRA,
                             UNSIGNED_INT_8_8_8_8_REV, Some(data));
            }
        }
    }

    image.texture = Some(texture);
}

pub fn bind_and_render_quad(render_context: RenderContext, size: Size2D<uint>, texture: GLuint) {
    bind_texture(TEXTURE_2D, texture);

    uniform_1i(render_context.sampler_uniform, 0);

    bind_buffer(ARRAY_BUFFER, render_context.vertex_buffer);
    vertex_attrib_pointer_f32(render_context.vertex_position_attr as GLuint, 3, false, 0, 0);

    // Create the texture coordinate array.
    bind_buffer(ARRAY_BUFFER, render_context.texture_coord_buffer);

    let (width, height) = (size.width as f32, size.height as f32);
    let vertices = [
        0.0f32, 0.0f32,
        0.0f32, height,
        width,  0.0f32,
        width,  height
    ];
    buffer_data(ARRAY_BUFFER, vertices, STATIC_DRAW);

    vertex_attrib_pointer_f32(render_context.texture_coord_attr as GLuint, 2, false, 0, 0);

    draw_arrays(TRIANGLE_STRIP, 0, 4);
}

// Layer rendering

pub trait Render {
    fn render(render_context: RenderContext);
}

impl @layers::ImageLayer : Render {
    fn render(render_context: RenderContext) {
        create_texture_for_image_if_necessary(self.image);

        uniform_matrix_4fv(render_context.modelview_uniform, false,
                           self.common.transform.to_array());

        bind_and_render_quad(
            render_context, self.image.data.size(), option::get(self.image.texture));
    }
}

impl @layers::TiledImageLayer : Render {
    fn render(render_context: RenderContext) {
        let tiles_down = self.tiles.len() / self.tiles_across;
        for self.tiles.eachi |i, tile| {
            create_texture_for_image_if_necessary(*tile);

            let x = ((i % self.tiles_across) as f32);
            let y = ((i / self.tiles_across) as f32);

            let transform = self.common.transform.scale(&(1.0f32 / (self.tiles_across as f32)),
                                                        &(1.0f32 / (tiles_down as f32)),
                                                        &1.0f32);
            let transform = transform.translate(&(x * 1.0f32), &(y * 1.0f32), &0.0f32);

            uniform_matrix_4fv(render_context.modelview_uniform, false, transform.to_array());

            bind_and_render_quad(render_context, tile.data.size(), option::get(tile.texture));
        }
    }
}

pub fn render_scene(render_context: RenderContext, scene: &Scene) {
    // Set the viewport.
    viewport(0 as GLint, 0 as GLint, scene.size.width as GLsizei, scene.size.height as GLsizei);

    // Clear the screen.
    clear_color(0.38f32, 0.36f32, 0.36f32, 1.0f32);
    clear(COLOR_BUFFER_BIT);

    // Set the projection matrix.
    let projection_matrix = ortho(0.0f32, copy scene.size.width, copy scene.size.height, 0.0f32,
                                  -10.0f32, 10.0f32);
    uniform_matrix_4fv(render_context.projection_uniform, false, projection_matrix.to_array());

    match copy scene.root {
        ContainerLayerKind(*) => fail ~"container layers unsupported",
        ImageLayerKind(image_layer) => image_layer.render(render_context),
        TiledImageLayerKind(tiled_image_layer) => tiled_image_layer.render(render_context)
    }
}

<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// This build script relies on a number of meson build system environment
// variables:
//    - MESON_SOURCE_ROOT:
//      The full path to the source code top directory.
//    - MESON_BUILD_ROOT:
//      The full path to the build top directory.
//    - OUT_DIR:
//      The full path to the directory where the output(s) must be written.
//
// This script finds all C header files in specified directories by combining
// `MESON_SOURCE_ROOT` with a relative path. It then generates rust bindings
// for the found C header files, the generated file is stored in `OUT_DIR`.
// This script also links against the relevant libraries.

extern crate bindgen;

use std::env;
use std::fs;
use std::path::Path;

static DIF_RELATIVE_PATH: &str = "sw/device/lib/dif";
static LIBBASE_RELATIVE_PATH: &str = "sw/device/lib/base";

fn main() {
    let source_root = env::var("MESON_SOURCE_ROOT").expect("no MESON_SOURCE_ROOT env variable");

    let build_root = env::var("MESON_BUILD_ROOT").expect("no MESON_BUILD_ROOT env variable");

    let out_dir = env::var("OUT_DIR").expect("no OUT_DIR env variable");

    generate_bindings(&source_root, &build_root, &out_dir);

    // Link against specified OT DIF libraries.
    let dif_path = Path::new(&build_root).join(DIF_RELATIVE_PATH);
    let dif_path = dif_path
        .to_str()
        .expect("failed to create DIF libraries path string");

    libraries_link(dif_path, &["uart_ot"]);

    // Link against specified libbase libraries.
    let libbase_path = Path::new(&build_root).join(LIBBASE_RELATIVE_PATH);
    let libbase_path = libbase_path
        .to_str()
        .expect("failed to create libbase libraries path string");

    libraries_link(libbase_path, &["mmio_ot"]);
}

fn libraries_link(path: &str, libs: &[&str]) {
    for lib in libs {
        println!("cargo:rustc-link-search={}", path);
        println!("cargo:rustc-link-lib={}", lib);
    }
}

fn generate_bindings(source_root: &str, build_root: &str, out_dir: &str) {
    let mut binding_builder = bindgen::builder()
        .raw_line("use riscv32_c_types;")
        .ctypes_prefix("riscv32_c_types")
        .clang_arg("--target=riscv32")
        .clang_args(&["-I", source_root])
        .clang_args(&["-I", build_root]);

    let dif_path = Path::new(&source_root).join(DIF_RELATIVE_PATH);
    let dif_build_meson = dif_path.join("meson.build");
    let dif_build_meson = dif_build_meson
        .to_str()
        .expect("failed to create DIF meson.build path string");

    println!("cargo:rerun-if-changed={}", dif_build_meson);

    let dif_files = fs::read_dir(dif_path).expect("failed to create DIF directory path object");

    // Find all of the DIF headers, and add them to the bindgen builder "state".
    for file in dif_files {
        let full_file_path = file.expect("file is not open").path();

        if let Some(extension) = full_file_path.extension() {
            let full_file_name = full_file_path
                .to_str()
                .expect("failed to get the full file name string");

            if extension == "h" {
                binding_builder = binding_builder.header(full_file_name);

                // Rerun the generator script if DIFs headers change.
                println!("cargo:rerun-if-changed={}", full_file_name);
            }
        }
    }

    let out_file = Path::new(&out_dir).join("ot_dif_bindings.rs");
    binding_builder
        .generate()
        .expect("failed to generate the bindings")
        .write_to_file(out_file)
        .expect("failed to create the output file");
}
<commit_msg>[sw, tock] Improve generated DIF bindings<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

// This build script relies on a number of meson build system environment
// variables:
//    - MESON_SOURCE_ROOT:
//      The full path to the source code top directory.
//    - MESON_BUILD_ROOT:
//      The full path to the build top directory.
//    - OUT_DIR:
//      The full path to the directory where the output(s) must be written.
//
// This script finds all C header files in specified directories by combining
// `MESON_SOURCE_ROOT` with a relative path. It then generates rust bindings
// for the found C header files, the generated file is stored in `OUT_DIR`.
// This script also links against the relevant libraries.

extern crate bindgen;

use std::env;
use std::fs;
use std::path::Path;

static DIF_RELATIVE_PATH: &str = "sw/device/lib/dif";
static LIBBASE_RELATIVE_PATH: &str = "sw/device/lib/base";

fn main() {
    let source_root = env::var("MESON_SOURCE_ROOT").expect("no MESON_SOURCE_ROOT env variable");

    let build_root = env::var("MESON_BUILD_ROOT").expect("no MESON_BUILD_ROOT env variable");

    let out_dir = env::var("OUT_DIR").expect("no OUT_DIR env variable");

    generate_bindings(&source_root, &out_dir);

    // Link against specified OT DIF libraries.
    let dif_path = Path::new(&build_root).join(DIF_RELATIVE_PATH);
    let dif_path = dif_path
        .to_str()
        .expect("failed to create DIF libraries path string");

    libraries_link(dif_path, &["uart_ot"]);

    // Link against specified libbase libraries.
    let libbase_path = Path::new(&build_root).join(LIBBASE_RELATIVE_PATH);
    let libbase_path = libbase_path
        .to_str()
        .expect("failed to create libbase libraries path string");

    libraries_link(libbase_path, &["mmio_ot"]);
}

fn libraries_link(path: &str, libs: &[&str]) {
    for lib in libs {
        println!("cargo:rustc-link-search={}", path);
        println!("cargo:rustc-link-lib={}", lib);
    }
}

fn generate_bindings(source_root: &str, out_dir: &str) {
    let mut binding_builder = bindgen::builder()
        .raw_line("use riscv32_c_types;")
        .ctypes_prefix("riscv32_c_types")
        .clang_arg("--target=riscv32")
        .clang_args(&["-I", &source_root])
        .derive_default(true)
        .prepend_enum_name(false)
        .rustfmt_bindings(true)
        .size_t_is_usize(true)
        .use_core();

    let dif_path = Path::new(&source_root).join(DIF_RELATIVE_PATH);
    let dif_build_meson = dif_path.join("meson.build");
    let dif_build_meson = dif_build_meson
        .to_str()
        .expect("failed to create DIF meson.build path string");

    println!("cargo:rerun-if-changed={}", dif_build_meson);

    let dif_files = fs::read_dir(dif_path).expect("failed to create DIF directory path object");

    // Find all of the DIF headers, and add them to the bindgen builder "state".
    for file in dif_files {
        let full_file_path = file.expect("file is not open").path();

        if let Some(extension) = full_file_path.extension() {
            let full_file_name = full_file_path
                .to_str()
                .expect("failed to get the full file name string");

            if extension == "h" {
                binding_builder = binding_builder.header(full_file_name);

                // Rerun the generator script if DIFs headers change.
                println!("cargo:rerun-if-changed={}", full_file_name);
            }
        }
    }

    let out_file = Path::new(&out_dir).join("ot_dif_bindings.rs");
    binding_builder
        .generate()
        .expect("failed to generate the bindings")
        .write_to_file(out_file)
        .expect("failed to create the output file");
}
<|endoftext|>