From 84f24a04a4f99c60fe35485d5eb12ea8c2070239 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Tue, 12 Jan 2016 11:14:55 -0800 Subject: [PATCH] Basic wrappers and glue for GeckoLib. --- components/layout/wrapper.rs | 6 +- components/style/traversal.rs | 5 - ports/geckolib/Cargo.lock | 7 + ports/geckolib/Cargo.toml | 13 +- ports/geckolib/bindings.rs | 81 ++++++ ports/geckolib/glue.rs | 92 +++++++ ports/geckolib/lib.rs | 24 ++ ports/geckolib/wrapper.rs | 475 ++++++++++++++++++++++++++++++++++ python/tidy.py | 1 + 9 files changed, 693 insertions(+), 11 deletions(-) create mode 100644 ports/geckolib/bindings.rs create mode 100644 ports/geckolib/glue.rs create mode 100644 ports/geckolib/wrapper.rs diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 5bd1406c27a..8d4f818d2b6 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -292,7 +292,7 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { unsafe fn borrow_layout_data_unchecked(&self) -> Option<*const PrivateLayoutData> { self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { - let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr); + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; &(*(*container).as_unsafe_cell().get()) as *const PrivateLayoutData }) } @@ -300,7 +300,7 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { fn borrow_layout_data(&self) -> Option> { unsafe { self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { - let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr); + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; (*container).borrow() }) } @@ -309,7 +309,7 @@ impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { fn mutate_layout_data(&self) -> Option> { unsafe { self.get_jsmanaged().get_style_and_layout_data().map(|opaque| { - let container: NonOpaqueStyleAndLayoutData = transmute(opaque.ptr); + let container = *opaque.ptr as NonOpaqueStyleAndLayoutData; (*container).borrow_mut() }) } diff --git a/components/style/traversal.rs b/components/style/traversal.rs index d20ecbc103c..d39da40f03e 100644 --- a/components/style/traversal.rs +++ b/components/style/traversal.rs @@ -115,10 +115,6 @@ pub trait DomTraversalContext<'ln, N: TNode<'ln>> { fn process_postorder(&self, node: N); } -/// FIXME(bholley): I added this now to demonstrate the usefulness of the new design. -/// This is currently unused, but will be used shortly. - -#[allow(dead_code)] pub struct StandaloneStyleContext<'a> { pub shared: &'a SharedStyleContext, cached_local_style_context: Rc, @@ -138,7 +134,6 @@ impl<'a> StyleContext<'a> for StandaloneStyleContext<'a> { } } -#[allow(dead_code)] pub struct RecalcStyleOnly<'lc> { context: StandaloneStyleContext<'lc>, root: OpaqueNode, diff --git a/ports/geckolib/Cargo.lock b/ports/geckolib/Cargo.lock index dc494e3be30..7be03f87b20 100644 --- a/ports/geckolib/Cargo.lock +++ b/ports/geckolib/Cargo.lock @@ -2,9 +2,16 @@ name = "geckoservo" version = "0.0.1" dependencies = [ + "app_units 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "selectors 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "style 0.0.1", "url 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", diff --git a/ports/geckolib/Cargo.toml b/ports/geckolib/Cargo.toml index 8f64ebda122..d9ccd382362 100644 --- a/ports/geckolib/Cargo.toml +++ b/ports/geckolib/Cargo.toml @@ -9,10 +9,17 @@ path = "lib.rs" crate-type = ["staticlib"] [dependencies] -log = "0.3" -url = "0.5.2" -libc = "0.2" +app_units = {version = "0.1", features = ["plugins"]} +bitflags = "0.3" +cssparser = { version = "0.4", features = [ "serde-serialization" ] } euclid = {version = "0.4", features = ["plugins"]} +libc = "0.2" +log = "0.3" +num_cpus = "0.2.2" +selectors = "0.2" +smallvec = "0.1" +string_cache = "0.2" +url = "0.5.2" [dependencies.util] path = "../../components/util" diff --git a/ports/geckolib/bindings.rs b/ports/geckolib/bindings.rs new file mode 100644 index 00000000000..96a5cb40705 --- /dev/null +++ b/ports/geckolib/bindings.rs @@ -0,0 +1,81 @@ +/* automatically generated by rust-bindgen */ + +pub type int64_t = ::libc::c_longlong; +pub type uint64_t = ::libc::c_ulonglong; +pub type int_least64_t = int64_t; +pub type uint_least64_t = uint64_t; +pub type int_fast64_t = int64_t; +pub type uint_fast64_t = uint64_t; +pub type int32_t = ::libc::c_int; +pub type uint32_t = ::libc::c_uint; +pub type int_least32_t = int32_t; +pub type uint_least32_t = uint32_t; +pub type int_fast32_t = int32_t; +pub type uint_fast32_t = uint32_t; +pub type int16_t = ::libc::c_short; +pub type uint16_t = ::libc::c_ushort; +pub type int_least16_t = int16_t; +pub type uint_least16_t = uint16_t; +pub type int_fast16_t = int16_t; +pub type uint_fast16_t = uint16_t; +pub type int8_t = ::libc::c_char; +pub type uint8_t = ::libc::c_uchar; +pub type int_least8_t = int8_t; +pub type uint_least8_t = uint8_t; +pub type int_fast8_t = int8_t; +pub type uint_fast8_t = uint8_t; +pub type intptr_t = int64_t; +pub type uintptr_t = uint64_t; +pub type intmax_t = ::libc::c_long; +pub type uintmax_t = ::libc::c_ulong; +pub type Enum_NodeType = ::libc::c_uint; +pub const ELEMENT_NODE: ::libc::c_uint = 1; +pub const ATTRIBUTE_NODE: ::libc::c_uint = 2; +pub const TEXT_NODE: ::libc::c_uint = 3; +pub const CDATA_SECTION_NODE: ::libc::c_uint = 4; +pub const ENTITY_REFERENCE_NODE: ::libc::c_uint = 5; +pub const ENTITY_NODE: ::libc::c_uint = 6; +pub const PROCESSING_INSTRUCTION_NODE: ::libc::c_uint = 7; +pub const COMMENT_NODE: ::libc::c_uint = 8; +pub const DOCUMENT_NODE: ::libc::c_uint = 9; +pub const DOCUMENT_TYPE_NODE: ::libc::c_uint = 10; +pub const DOCUMENT_FRAGMENT_NODE: ::libc::c_uint = 11; +pub const NOTATION_NODE: ::libc::c_uint = 12; +pub enum Struct_RawGeckoNode { } +pub type RawGeckoNode = Struct_RawGeckoNode; +pub enum Struct_RawGeckoElement { } +pub type RawGeckoElement = Struct_RawGeckoElement; +pub enum Struct_RawGeckoDocument { } +pub type RawGeckoDocument = Struct_RawGeckoDocument; +pub enum Struct_ServoNodeData { } +pub type ServoNodeData = Struct_ServoNodeData; +extern "C" { + pub fn Gecko_ElementState(element: *mut RawGeckoElement) -> uint8_t; + pub fn Gecko_GetAttrAsUTF8(element: *mut RawGeckoElement, ns: *const uint8_t, + name: *const uint8_t, length: *mut uint32_t) + -> *const ::libc::c_char; + pub fn Gecko_ChildrenCount(node: *mut RawGeckoNode) -> uint32_t; + pub fn Gecko_GetDocumentElement(document: *mut RawGeckoDocument) + -> *mut RawGeckoElement; + pub fn Gecko_GetFirstChild(node: *mut RawGeckoNode) -> *mut RawGeckoNode; + pub fn Gecko_GetLastChild(node: *mut RawGeckoNode) -> *mut RawGeckoNode; + pub fn Gecko_GetPrevSibling(node: *mut RawGeckoNode) -> *mut RawGeckoNode; + pub fn Gecko_GetNextSibling(node: *mut RawGeckoNode) -> *mut RawGeckoNode; + pub fn Gecko_GetNodeData(node: *mut RawGeckoNode) -> *mut ServoNodeData; + pub fn Gecko_GetParentNode(node: *mut RawGeckoNode) -> *mut RawGeckoNode; + pub fn Gecko_LocalName(element: *mut RawGeckoElement, length: *mut uint32_t) + -> *const uint16_t; + pub fn Gecko_IsHTMLElementInHTMLDocument(element: *mut RawGeckoElement) + -> ::libc::c_int; + pub fn Gecko_IsLink(element: *mut RawGeckoElement) -> ::libc::c_int; + pub fn Gecko_IsTextNode(node: *mut RawGeckoNode) -> ::libc::c_int; + pub fn Gecko_IsVisitedLink(element: *mut RawGeckoElement) -> ::libc::c_int; + pub fn Gecko_IsUnvisitedLink(element: *mut RawGeckoElement) -> ::libc::c_int; + pub fn Gecko_Namespace(element: *mut RawGeckoElement, length: *mut uint32_t) + -> *const uint16_t; + pub fn Gecko_NodeIsElement(node: *mut RawGeckoNode) -> ::libc::c_int; + pub fn Gecko_SetNodeData(node: *mut RawGeckoNode, + data: *mut ServoNodeData) -> (); + pub fn Servo_RestyleDocument(aDoc: *mut RawGeckoDocument) -> (); + pub fn Servo_DropNodeData(data: *mut ServoNodeData) -> (); +} diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs new file mode 100644 index 00000000000..bb1d6bcae3e --- /dev/null +++ b/ports/geckolib/glue.rs @@ -0,0 +1,92 @@ +/* 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/. */ + +#![allow(unsafe_code)] + +use app_units::Au; +use bindings::RawGeckoDocument; +use bindings::ServoNodeData; +use euclid::Size2D; +use euclid::size::TypedSize2D; +use num_cpus; +use std::cmp; +use std::collections::HashMap; +use std::sync::mpsc::{channel, Sender}; +use std::sync::{Arc, Mutex, RwLock}; +use style::animation::Animation; +use style::context::{ReflowGoal, SharedStyleContext, StylistWrapper}; +use style::dom::{TDocument, TNode}; +use style::error_reporting::StdoutErrorReporter; +use style::media_queries::{Device, MediaType}; +use style::parallel::{self, WorkQueueData}; +use style::selector_matching::Stylist; +use style::stylesheets::Stylesheet; +use style::traversal::RecalcStyleOnly; +use util::geometry::ViewportPx; +use util::resource_files::set_resources_path; +use util::thread_state; +use util::workqueue::WorkQueue; +use wrapper::{GeckoDocument, GeckoNode, NonOpaqueStyleData}; + +/* + * For Gecko->Servo function calls, we need to redeclare the same signature that was declared in + * the C header in Gecko. In order to catch accidental mismatches, we run rust-bindgen against + * those signatures as well, giving us a second declaration of all the Servo_* functions in this + * crate. If there's a mismatch, LLVM will assert and abort, which is a rather awful thing to + * depend on but good enough for our purposes. + */ + +#[no_mangle] +pub extern "C" fn Servo_RestyleDocument(doc: *mut RawGeckoDocument) -> () { + let document = unsafe { GeckoDocument::from_raw(doc) }; + let node = match document.root_node() { + Some(x) => x, + None => return, + }; + + // FIXME(bholley): Don't hardcode resources path. We may want to use Gecko's UA stylesheets + // anyway. + set_resources_path(Some("/files/mozilla/stylo/servo/resources/".to_owned())); + + // FIXME(bholley): Real window size. + let window_size: TypedSize2D = Size2D::typed(800.0, 600.0); + let device = Device::new(MediaType::Screen, window_size); + + // FIXME(bholley): Real stylist and stylesheets. + let stylesheets: Vec> = Vec::new(); + let mut stylist = Box::new(Stylist::new(device)); + let _needs_dirtying = stylist.update(&stylesheets, false); + + // FIXME(bholley): Hook this up to something. + let new_animations_sender: Sender = channel().0; + + let shared_style_context = SharedStyleContext { + viewport_size: Size2D::new(Au(0), Au(0)), + screen_size_changed: false, + generation: 0, + goal: ReflowGoal::ForScriptQuery, + stylist: StylistWrapper(&*stylist), + new_animations_sender: Mutex::new(new_animations_sender), + running_animations: Arc::new(RwLock::new(HashMap::new())), + expired_animations: Arc::new(RwLock::new(HashMap::new())), + error_reporter: Box::new(StdoutErrorReporter), + }; + + let num_threads = cmp::max(num_cpus::get() * 3 / 4, 1); + let mut parallel_traversal: WorkQueue = + WorkQueue::new("StyleWorker", thread_state::LAYOUT, num_threads); + + if node.is_dirty() || node.has_dirty_descendants() { + parallel::traverse_dom::(node, &shared_style_context, &mut parallel_traversal); + } + + parallel_traversal.shutdown(); +} + +#[no_mangle] +pub extern "C" fn Servo_DropNodeData(data: *mut ServoNodeData) -> () { + unsafe { + let _ = Box::::from_raw(data as *mut NonOpaqueStyleData); + } +} diff --git a/ports/geckolib/lib.rs b/ports/geckolib/lib.rs index febe56558f9..64be8072437 100644 --- a/ports/geckolib/lib.rs +++ b/ports/geckolib/lib.rs @@ -2,4 +2,28 @@ * 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/. */ +#![feature(as_unsafe_cell)] +#![feature(box_syntax)] +#![feature(ptr_as_ref)] + +extern crate app_units; +#[macro_use] +extern crate bitflags; +extern crate cssparser; +extern crate euclid; +extern crate libc; +extern crate num_cpus; +#[macro_use(state_pseudo_classes)] +extern crate selectors; +extern crate smallvec; +#[macro_use(atom, ns)] +extern crate string_cache; extern crate style; +extern crate url; +extern crate util; + +#[allow(dead_code, non_camel_case_types)] +mod bindings; +#[allow(non_snake_case)] +pub mod glue; +mod wrapper; diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs new file mode 100644 index 00000000000..1c71181e795 --- /dev/null +++ b/ports/geckolib/wrapper.rs @@ -0,0 +1,475 @@ +/* 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/. */ + +#![allow(unsafe_code)] + +use bindings::{Gecko_ChildrenCount}; +use bindings::{Gecko_ElementState, Gecko_GetAttrAsUTF8, Gecko_GetDocumentElement}; +use bindings::{Gecko_GetFirstChild, Gecko_GetLastChild, Gecko_GetNodeData}; +use bindings::{Gecko_GetParentNode, Gecko_GetPrevSibling, Gecko_GetNextSibling}; +use bindings::{Gecko_IsHTMLElementInHTMLDocument, Gecko_IsLink, Gecko_IsTextNode}; +use bindings::{Gecko_IsUnvisitedLink, Gecko_IsVisitedLink}; +#[allow(unused_imports)] // Used in commented-out code. +use bindings::{Gecko_LocalName, Gecko_Namespace, Gecko_NodeIsElement, Gecko_SetNodeData}; +use bindings::{RawGeckoDocument, RawGeckoElement, RawGeckoNode}; +use bindings::{ServoNodeData}; +use libc::uintptr_t; +use selectors::matching::DeclarationBlock; +use selectors::parser::{AttrSelector, NamespaceConstraint}; +use selectors::states::*; +use smallvec::VecLike; +use std::cell::{Ref, RefCell, RefMut}; +use std::marker::PhantomData; +use std::ops::BitOr; +use std::slice; +use std::str::from_utf8_unchecked; +use std::sync::Arc; +use string_cache::{Atom, Namespace}; +use style::data::PrivateStyleData; +use style::dom::{OpaqueNode, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode}; +#[allow(unused_imports)] // Used in commented-out code. +use style::error_reporting::StdoutErrorReporter; +use style::properties::{ComputedValues, PropertyDeclaration, PropertyDeclarationBlock}; +#[allow(unused_imports)] // Used in commented-out code. +use style::properties::{parse_style_attribute}; +use style::restyle_hints::ElementSnapshot; +#[allow(unused_imports)] // Used in commented-out code. +use url::Url; + +pub type NonOpaqueStyleData = *mut RefCell; + +// Important: We don't currently refcount the DOM, because the wrapper lifetime +// magic guarantees that our LayoutFoo references won't outlive the root, and +// we don't mutate any of the references on the Gecko side during restyle. We +// could implement refcounting if need be (at a potentially non-trivial +// performance cost) by implementing Drop and making LayoutFoo non-Copy. +#[derive(Clone, Copy)] +pub struct GeckoNode<'ln> { + node: *mut RawGeckoNode, + chain: PhantomData<&'ln ()>, +} + +impl<'ln> GeckoNode<'ln> { + unsafe fn from_raw(n: *mut RawGeckoNode) -> GeckoNode<'ln> { + GeckoNode { + node: n, + chain: PhantomData, + } + } + + unsafe fn from_ref(n: &RawGeckoNode) -> GeckoNode<'ln> { + GeckoNode::from_raw(n as *const RawGeckoNode as *mut RawGeckoNode) + } + + fn get_node_data(&self) -> NonOpaqueStyleData { + unsafe { + Gecko_GetNodeData(self.node) as NonOpaqueStyleData + } + } +} + +#[derive(Clone, Copy)] +pub struct DummyRestyleDamage; +impl TRestyleDamage for DummyRestyleDamage { + fn compute(_: &Option>, _: &ComputedValues) -> Self { DummyRestyleDamage } + fn rebuild_and_reflow() -> Self { DummyRestyleDamage } +} +impl BitOr for DummyRestyleDamage { + type Output = Self; + fn bitor(self, _: Self) -> Self { DummyRestyleDamage } +} + + + +impl<'ln> TNode<'ln> for GeckoNode<'ln> { + type ConcreteDocument = GeckoDocument<'ln>; + type ConcreteElement = GeckoElement<'ln>; + type ConcreteRestyleDamage = DummyRestyleDamage; + + fn to_unsafe(&self) -> UnsafeNode { + (self.node as usize, 0) + } + + unsafe fn from_unsafe(n: &UnsafeNode) -> Self { + GeckoNode::from_raw(n.0 as *mut RawGeckoNode) + } + + fn is_text_node(&self) -> bool { + unsafe { + Gecko_IsTextNode(self.node) != 0 + } + } + + fn is_element(&self) -> bool { + unsafe { + Gecko_NodeIsElement(self.node) != 0 + } + } + + fn dump(self) { + unimplemented!() + } + + fn opaque(&self) -> OpaqueNode { + let ptr: uintptr_t = self.node as uintptr_t; + OpaqueNode(ptr) + } + + fn initialize_data(self) { + unsafe { + if self.get_node_data().is_null() { + let ptr: NonOpaqueStyleData = Box::into_raw(box RefCell::new(PrivateStyleData::new())); + Gecko_SetNodeData(self.node, ptr as *mut ServoNodeData); + } + } + } + + fn layout_parent_node(self, reflow_root: OpaqueNode) -> Option> { + if self.opaque() == reflow_root { + None + } else { + self.parent_node() + } + } + + fn debug_id(self) -> usize { + unimplemented!() + } + + fn children_count(&self) -> u32 { + unsafe { + Gecko_ChildrenCount(self.node) + } + } + + fn as_element(&self) -> Option> { + if self.is_element() { + unsafe { Some(GeckoElement::from_raw(self.node as *mut RawGeckoElement)) } + } else { + None + } + } + + fn as_document(&self) -> Option> { + unimplemented!() + } + + fn has_changed(&self) -> bool { + // FIXME(bholley) - Implement this to allow incremental reflows! + true + } + + unsafe fn set_changed(&self, _value: bool) { + unimplemented!() + } + + fn is_dirty(&self) -> bool { + // FIXME(bholley) + true + } + + unsafe fn set_dirty(&self, _value: bool) { + unimplemented!() + } + + fn has_dirty_descendants(&self) -> bool { + // FIXME(bholley) + true + } + + unsafe fn set_dirty_descendants(&self, _value: bool) { + unimplemented!() + } + + #[inline(always)] + unsafe fn borrow_data_unchecked(&self) -> Option<*const PrivateStyleData> { + self.get_node_data().as_ref().map(|d| d.as_unsafe_cell().get() as *const PrivateStyleData) + } + + #[inline(always)] + fn borrow_data(&self) -> Option> { + unsafe { + self.get_node_data().as_ref().map(|d| d.borrow()) + } + } + + #[inline(always)] + fn mutate_data(&self) -> Option> { + unsafe { + self.get_node_data().as_ref().map(|d| d.borrow_mut()) + } + } + + fn restyle_damage(self) -> Self::ConcreteRestyleDamage { DummyRestyleDamage } + + fn set_restyle_damage(self, _: Self::ConcreteRestyleDamage) {} + + fn parent_node(&self) -> Option> { + unsafe { + Gecko_GetParentNode(self.node).as_ref().map(|n| GeckoNode::from_ref(n)) + } + } + + fn first_child(&self) -> Option> { + unsafe { + Gecko_GetFirstChild(self.node).as_ref().map(|n| GeckoNode::from_ref(n)) + } + } + + fn last_child(&self) -> Option> { + unsafe { + Gecko_GetLastChild(self.node).as_ref().map(|n| GeckoNode::from_ref(n)) + } + } + + fn prev_sibling(&self) -> Option> { + unsafe { + Gecko_GetPrevSibling(self.node).as_ref().map(|n| GeckoNode::from_ref(n)) + } + } + + fn next_sibling(&self) -> Option> { + unsafe { + Gecko_GetNextSibling(self.node).as_ref().map(|n| GeckoNode::from_ref(n)) + } + } +} + +#[derive(Clone, Copy)] +pub struct GeckoDocument<'ld> { + document: *mut RawGeckoDocument, + chain: PhantomData<&'ld ()>, +} + +impl<'ld> GeckoDocument<'ld> { + pub unsafe fn from_raw(doc: *mut RawGeckoDocument) -> GeckoDocument<'ld> { + GeckoDocument { + document: doc, + chain: PhantomData, + } + } +} + +impl<'ld> TDocument<'ld> for GeckoDocument<'ld> { + type ConcreteNode = GeckoNode<'ld>; + type ConcreteElement = GeckoElement<'ld>; + + fn as_node(&self) -> GeckoNode<'ld> { + unsafe { GeckoNode::from_raw(self.document as *mut RawGeckoNode) } + } + + fn root_node(&self) -> Option> { + unsafe { + Gecko_GetDocumentElement(self.document).as_ref().map(|el| GeckoElement::from_ref(el).as_node()) + } + } + + fn drain_modified_elements(&self) -> Vec<(GeckoElement<'ld>, ElementSnapshot)> { + unimplemented!() + /* + let elements = unsafe { self.document.drain_modified_elements() }; + elements.into_iter().map(|(el, snapshot)| (ServoLayoutElement::from_layout_js(el), snapshot)).collect()*/ + } +} + +#[derive(Clone, Copy)] +pub struct GeckoElement<'le> { + element: *mut RawGeckoElement, + chain: PhantomData<&'le ()>, +} + +impl<'le> GeckoElement<'le> { + unsafe fn from_raw(el: *mut RawGeckoElement) -> GeckoElement<'le> { + GeckoElement { + element: el, + chain: PhantomData, + } + } + + unsafe fn from_ref(el: &RawGeckoElement) -> GeckoElement<'le> { + GeckoElement::from_raw(el as *const RawGeckoElement as *mut RawGeckoElement) + } +} + +impl<'le> TElement<'le> for GeckoElement<'le> { + type ConcreteNode = GeckoNode<'le>; + type ConcreteDocument = GeckoDocument<'le>; + + fn as_node(&self) -> Self::ConcreteNode { + unsafe { GeckoNode::from_raw(self.element as *mut RawGeckoNode) } + } + + fn style_attribute(&self) -> &'le Option { + panic!("Requires signature modification - only implemented in stylo branch"); + /* + // FIXME(bholley): We should do what Servo does here. Gecko needs to + // call into the Servo CSS parser and then cache the resulting block + // in the nsAttrValue. That will allow us to borrow it from here. + let attr = self.get_attr(&ns!(), &atom!("style")); + // FIXME(bholley): Real base URL and error reporter. + let base_url = Url::parse("http://www.example.org").unwrap(); + attr.map(|v| parse_style_attribute(&v, &base_url, Box::new(StdoutErrorReporter))) + */ + } + + fn get_state(&self) -> ElementState { + unsafe { + ElementState::from_bits_truncate(Gecko_ElementState(self.element)) + } + } + + fn synthesize_presentational_hints_for_legacy_attributes(&self, _hints: &mut V) + where V: VecLike>> + { + unimplemented!() + } + + #[inline] + fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> { + unsafe { + let mut length: u32 = 0; + let ptr = Gecko_GetAttrAsUTF8(self.element, namespace.0.as_ptr(), name.as_ptr(), &mut length); + reinterpret_string(ptr, length) + } + } + + #[inline] + fn get_attrs<'a>(&'a self, _name: &Atom) -> Vec<&'a str> { + unimplemented!() + } +} + +macro_rules! state_getter { + ($( + $(#[$Flag_attr: meta])* + state $css: expr => $variant: ident / $method: ident / + $flag: ident = $value: expr, + )+) => { + $( fn $method(&self) -> bool { self.get_state().contains($flag) } )+ + } +} + +impl<'le> ::selectors::Element for GeckoElement<'le> { + fn parent_element(&self) -> Option { + unimplemented!() + } + + fn first_child_element(&self) -> Option { + unimplemented!() + } + + fn last_child_element(&self) -> Option { + unimplemented!() + } + + fn prev_sibling_element(&self) -> Option { + unimplemented!() + } + + fn next_sibling_element(&self) -> Option { + unimplemented!() + } + + fn is_root(&self) -> bool { + unimplemented!() + } + + fn is_empty(&self) -> bool { + unimplemented!() + } + + fn get_local_name(&self) -> &Atom { + panic!("Requires signature modification - only implemented in stylo branch"); + /* + unsafe { + let mut length: u32 = 0; + let p = Gecko_LocalName(self.element, &mut length); + Atom::from(&*String::from_utf16(slice::from_raw_parts(p, length as usize)).unwrap()) + } + */ + } + + fn get_namespace(&self) -> &Namespace { + panic!("Requires signature modification - only implemented in stylo branch"); + /* + unsafe { + let mut length: u32 = 0; + let p = Gecko_Namespace(self.element, &mut length); + Namespace(Atom::from(&*String::from_utf16(slice::from_raw_parts(p, length as usize)).unwrap())) + } + */ + } + + fn is_link(&self) -> bool { + unsafe { + Gecko_IsLink(self.element) != 0 + } + } + + fn is_unvisited_link(&self) -> bool { + unsafe { + Gecko_IsUnvisitedLink(self.element) != 0 + } + } + + fn is_visited_link(&self) -> bool { + unsafe { + Gecko_IsVisitedLink(self.element) != 0 + } + } + + state_pseudo_classes!(state_getter); + + fn get_id(&self) -> Option { + // FIXME(bholley): Servo caches the id atom directly on the element to + // make this blazing fast. Assuming that was a measured optimization, doing + // the dumb thing like we do below will almost certainly be a bottleneck. + self.get_attr(&ns!(), &atom!("id")).map(|s| Atom::from(s)) + } + + fn has_class(&self, _name: &Atom) -> bool { + unimplemented!() + } + + fn each_class(&self, mut callback: F) where F: FnMut(&Atom) { + // FIXME(bholley): Synergize with the DOM to stop splitting strings here. + if let Some(classes) = self.get_attr(&ns!(), &atom!("class")) { + for c in classes.split(" ") { + callback(&Atom::from(c)); + } + } + } + + fn has_servo_nonzero_border(&self) -> bool { + unimplemented!() + } + + fn match_attr(&self, attr: &AttrSelector, test: F) -> bool where F: Fn(&str) -> bool { + // FIXME(bholley): This is copy-pasted from the servo wrapper's version. + // We should find a way to share it. + let name = if self.is_html_element_in_html_document() { + &attr.lower_name + } else { + &attr.name + }; + match attr.namespace { + NamespaceConstraint::Specific(ref ns) => { + self.get_attr(ns, name).map_or(false, |attr| test(attr)) + }, + NamespaceConstraint::Any => { + self.get_attrs(name).iter().any(|attr| test(*attr)) + } + } + } + + fn is_html_element_in_html_document(&self) -> bool { + unsafe { + Gecko_IsHTMLElementInHTMLDocument(self.element) != 0 + } + } +} + +unsafe fn reinterpret_string<'a>(ptr: *const ::libc::c_char, length: u32) -> Option<&'a str> { + (ptr as *const u8).as_ref().map(|p| from_utf8_unchecked(slice::from_raw_parts(p, length as usize))) +} diff --git a/python/tidy.py b/python/tidy.py index 0b7c96c9896..b46a6c78587 100644 --- a/python/tidy.py +++ b/python/tidy.py @@ -39,6 +39,7 @@ ignored_files = [ os.path.join(".", "target", "*"), os.path.join(".", "ports", "gonk", "src", "native_window_glue.cpp"), os.path.join(".", "ports", "cef", "*"), + os.path.join(".", "ports", "geckolib", "bindings.rs"), # MIT license os.path.join(".", "components", "util", "deque", "mod.rs"),