diff options
-rw-r--r-- | components/layout/wrapper.rs | 180 | ||||
-rw-r--r-- | components/style/dom.rs | 10 | ||||
-rw-r--r-- | components/style/selector_impl.rs | 12 | ||||
-rw-r--r-- | components/style/selector_matching.rs | 7 | ||||
-rw-r--r-- | ports/geckolib/selector_impl.rs | 3 | ||||
-rw-r--r-- | ports/geckolib/wrapper.rs | 17 |
6 files changed, 172 insertions, 57 deletions
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 29ebb919368..928ae1777ac 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -66,7 +66,7 @@ use std::sync::Arc; use string_cache::{Atom, Namespace}; use style::computed_values::content::ContentItem; use style::computed_values::{content, display}; -use style::dom::{TDocument, TElement, TNode, UnsafeNode}; +use style::dom::{PresentationalHintsSynthetizer, TDocument, TElement, TNode, UnsafeNode}; use style::element_state::*; use style::properties::{ComputedValues, ServoComputedValues}; use style::properties::{PropertyDeclaration, PropertyDeclarationBlock}; @@ -81,7 +81,7 @@ pub type NonOpaqueStyleAndLayoutData = *mut RefCell<PrivateLayoutData>; /// A wrapper so that layout can access only the methods that it should have access to. Layout must /// only ever see these and must never see instances of `LayoutJS`. -pub trait LayoutNode : TNode { +pub trait LayoutNode: TNode { type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; @@ -401,6 +401,16 @@ pub struct ServoLayoutElement<'le> { chain: PhantomData<&'le ()>, } +impl<'le> PresentationalHintsSynthetizer for ServoLayoutElement<'le> { + fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V) + where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> + { + unsafe { + self.element.synthesize_presentational_hints_for_legacy_attributes(hints); + } + } +} + impl<'le> TElement for ServoLayoutElement<'le> { type ConcreteNode = ServoLayoutNode<'le>; type ConcreteDocument = ServoLayoutDocument<'le>; @@ -419,14 +429,6 @@ impl<'le> TElement for ServoLayoutElement<'le> { self.element.get_state_for_layout() } - fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V) - where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> - { - unsafe { - self.element.synthesize_presentational_hints_for_legacy_attributes(hints); - } - } - #[inline] fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str> { unsafe { @@ -665,8 +667,10 @@ impl<T> PseudoElementType<T> { /// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout /// node does not allow any parents or siblings of nodes to be accessed, to avoid races. -pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { - type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self>; +pub trait ThreadSafeLayoutNode: Clone + Copy + Sized + PartialEq { + type ConcreteThreadSafeLayoutElement: + ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self> + + ::selectors::Element<Impl=ServoSelectorImpl>; type ChildrenIterator: Iterator<Item = Self> + Sized; /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` @@ -680,6 +684,18 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. fn type_id(&self) -> Option<NodeTypeId>; + /// Returns the type ID of this node, without discarding pseudo-elements as + /// `type_id` does. + fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId; + + #[inline] + fn is_element_or_elements_pseudo(&self) -> bool { + match self.type_id_without_excluding_pseudo_elements() { + NodeTypeId::Element(..) => true, + _ => false, + } + } + fn debug_id(self) -> usize; fn flow_debug_id(self) -> usize; @@ -791,23 +807,20 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { } } PseudoElementCascadeType::Lazy => { - panic!("Lazy pseudo-elements can't be used in Servo \ - since accessing the DOM tree during layout \ - could be unsafe.") - // debug_assert!(self.is_element()); - // if !self.borrow_layout_data() - // .unwrap().style_data - // .per_pseudo.contains_key(&style_pseudo) { - // let mut data = self.mutate_layout_data().unwrap(); - // let new_style = - // context.stylist - // .lazily_compute_pseudo_element_style( - // &self.as_element(), - // &style_pseudo, - // data.style_data.style.as_ref().unwrap()); - // data.style_data.per_pseudo - // .insert(style_pseudo.clone(), new_style.unwrap()) - // } + debug_assert!(self.is_element_or_elements_pseudo()); + if !self.borrow_layout_data() + .unwrap().style_data + .per_pseudo.contains_key(&style_pseudo) { + let mut data = self.mutate_layout_data().unwrap(); + let new_style = + context.stylist + .lazily_compute_pseudo_element_style( + &self.as_element(), + &style_pseudo, + data.style_data.style.as_ref().unwrap()); + data.style_data.per_pseudo + .insert(style_pseudo.clone(), new_style.unwrap()); + } } } @@ -932,12 +945,14 @@ pub trait ThreadSafeLayoutNode : Clone + Copy + Sized + PartialEq { // This trait is only public so that it can be implemented by the gecko wrapper. // It can be used to violate thread-safety, so don't use it elsewhere in layout! -pub trait DangerousThreadSafeLayoutNode : ThreadSafeLayoutNode { +pub trait DangerousThreadSafeLayoutNode: ThreadSafeLayoutNode { unsafe fn dangerous_first_child(&self) -> Option<Self>; unsafe fn dangerous_next_sibling(&self) -> Option<Self>; } -pub trait ThreadSafeLayoutElement: Clone + Copy + Sized { +pub trait ThreadSafeLayoutElement: Clone + Copy + Sized + + ::selectors::Element<Impl=ServoSelectorImpl> + + PresentationalHintsSynthetizer { type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>; #[inline] @@ -1027,6 +1042,11 @@ impl<'ln> ThreadSafeLayoutNode for ServoThreadSafeLayoutNode<'ln> { Some(self.node.type_id()) } + #[inline] + fn type_id_without_excluding_pseudo_elements(&self) -> NodeTypeId { + self.node.type_id() + } + fn debug_id(self) -> usize { self.node.debug_id() } @@ -1320,3 +1340,101 @@ impl TextContent { } } } + +impl <'le> ::selectors::Element for ServoThreadSafeLayoutElement<'le> { + type Impl = ServoSelectorImpl; + + fn parent_element(&self) -> Option<Self> { + warn!("ServoThreadSafeLayoutElement::parent_element called"); + None + } + + fn first_child_element(&self) -> Option<Self> { + warn!("ServoThreadSafeLayoutElement::first_child_element called"); + None + } + + // Skips non-element nodes + fn last_child_element(&self) -> Option<Self> { + warn!("ServoThreadSafeLayoutElement::last_child_element called"); + None + } + + // Skips non-element nodes + fn prev_sibling_element(&self) -> Option<Self> { + warn!("ServoThreadSafeLayoutElement::prev_sibling_element called"); + None + } + + // Skips non-element nodes + fn next_sibling_element(&self) -> Option<Self> { + warn!("ServoThreadSafeLayoutElement::next_sibling_element called"); + None + } + + fn is_html_element_in_html_document(&self) -> bool { + warn!("ServoThreadSafeLayoutElement::is_html_element_in_html_document called"); + true + } + + #[inline] + fn get_local_name(&self) -> &Atom { + ThreadSafeLayoutElement::get_local_name(self) + } + + #[inline] + fn get_namespace(&self) -> &Namespace { + ThreadSafeLayoutElement::get_namespace(self) + } + + fn match_non_ts_pseudo_class(&self, _: NonTSPseudoClass) -> bool { + // NB: This could maybe be implemented + warn!("ServoThreadSafeLayoutElement::match_non_ts_pseudo_class called"); + false + } + + fn get_id(&self) -> Option<Atom> { + warn!("ServoThreadSafeLayoutElement::get_id called"); + None + } + + fn has_class(&self, _name: &Atom) -> bool { + warn!("ServoThreadSafeLayoutElement::has_class called"); + false + } + + fn match_attr<F>(&self, attr: &AttrSelector, test: F) -> bool + where F: Fn(&str) -> bool { + match attr.namespace { + NamespaceConstraint::Specific(ref ns) => { + self.get_attr(ns, &attr.name).map_or(false, |attr| test(attr)) + }, + NamespaceConstraint::Any => { + unsafe { + self.element.get_attr_vals_for_layout(&attr.name).iter() + .any(|attr| test(*attr)) + } + } + } + } + + fn is_empty(&self) -> bool { + warn!("ServoThreadSafeLayoutElement::is_empty called"); + false + } + + fn is_root(&self) -> bool { + warn!("ServoThreadSafeLayoutElement::is_root called"); + false + } + + fn each_class<F>(&self, _callback: F) + where F: FnMut(&Atom) { + warn!("ServoThreadSafeLayoutElement::each_class called"); + } +} + +impl<'le> PresentationalHintsSynthetizer for ServoThreadSafeLayoutElement<'le> { + fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V) + where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> {} +} diff --git a/components/style/dom.rs b/components/style/dom.rs index fed1597c627..badd4f31065 100644 --- a/components/style/dom.rs +++ b/components/style/dom.rs @@ -195,7 +195,12 @@ pub trait TDocument : Sized + Copy + Clone { fn drain_modified_elements(&self) -> Vec<(Self::ConcreteElement, ElementSnapshot)>; } -pub trait TElement : Sized + Copy + Clone + ElementExt { +pub trait PresentationalHintsSynthetizer { + fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, hints: &mut V) + where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>; +} + +pub trait TElement : Sized + Copy + Clone + ElementExt + PresentationalHintsSynthetizer { type ConcreteNode: TNode<ConcreteElement = Self, ConcreteDocument = Self::ConcreteDocument>; type ConcreteDocument: TDocument<ConcreteNode = Self::ConcreteNode, ConcreteElement = Self>; @@ -205,9 +210,6 @@ pub trait TElement : Sized + Copy + Clone + ElementExt { fn get_state(&self) -> ElementState; - fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, &mut V) - where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>>; - fn get_attr<'a>(&'a self, namespace: &Namespace, attr: &Atom) -> Option<&'a str>; fn get_attrs<'a>(&'a self, attr: &Atom) -> Vec<&'a str>; diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs index e0c1b2c3f98..b424affb101 100644 --- a/components/style/selector_impl.rs +++ b/components/style/selector_impl.rs @@ -104,19 +104,11 @@ pub enum PseudoElement { impl PseudoElement { #[inline] pub fn cascade_type(&self) -> PseudoElementCascadeType { - // TODO: Make PseudoElementCascadeType::Lazy work for Servo. - // - // This can't be done right now since it would require - // ServoThreadSafeLayoutElement to implement ::selectors::Element, - // and it might not be thread-safe. - // - // After that, we'd probably want ::selection and - // ::-servo-details-summary to be lazy. match *self { PseudoElement::Before | PseudoElement::After | - PseudoElement::Selection | - PseudoElement::DetailsSummary => PseudoElementCascadeType::Eager, + PseudoElement::Selection => PseudoElementCascadeType::Eager, + PseudoElement::DetailsSummary => PseudoElementCascadeType::Lazy, PseudoElement::DetailsContent => PseudoElementCascadeType::Precomputed, } } diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index e59955f3a0e..4faf9aa0eb4 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -5,7 +5,7 @@ // For lazy_static #![allow(unsafe_code)] -use dom::TElement; +use dom::PresentationalHintsSynthetizer; use element_state::*; use error_reporting::{ParseErrorReporter, StdoutErrorReporter}; use media_queries::{Device, MediaType}; @@ -281,7 +281,8 @@ impl<Impl: SelectorImplExt> Stylist<Impl> { pseudo: &Impl::PseudoElement, parent: &Arc<Impl::ComputedValues>) -> Option<Arc<Impl::ComputedValues>> - where E: Element<Impl=Impl> + TElement { + where E: Element<Impl=Impl> + + PresentationalHintsSynthetizer { debug_assert!(Impl::pseudo_element_cascade_type(pseudo).is_lazy()); if self.pseudos_map.get(pseudo).is_none() { return None; @@ -358,7 +359,7 @@ impl<Impl: SelectorImplExt> Stylist<Impl> { pseudo_element: Option<&Impl::PseudoElement>, applicable_declarations: &mut V) -> bool - where E: Element<Impl=Impl> + TElement, + where E: Element<Impl=Impl> + PresentationalHintsSynthetizer, V: VecLike<DeclarationBlock> { assert!(!self.is_device_dirty); assert!(style_attribute.is_none() || pseudo_element.is_none(), diff --git a/ports/geckolib/selector_impl.rs b/ports/geckolib/selector_impl.rs index bedac08a025..ddc26f6c541 100644 --- a/ports/geckolib/selector_impl.rs +++ b/ports/geckolib/selector_impl.rs @@ -23,7 +23,6 @@ pub enum PseudoElement { // TODO: Probably a few more are missing here AnonBox(AnonBoxPseudoElement), - } // https://mxr.mozilla.org/mozilla-central/source/layout/style/nsCSSAnonBoxList.h @@ -262,8 +261,8 @@ impl SelectorImplExt for GeckoSelectorImpl { #[inline] fn each_pseudo_element<F>(mut fun: F) where F: FnMut(PseudoElement) { - use self::PseudoElement::*; use self::AnonBoxPseudoElement::*; + use self::PseudoElement::*; fun(Before); fun(After); diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs index edf007a0016..f27cf770bf0 100644 --- a/ports/geckolib/wrapper.rs +++ b/ports/geckolib/wrapper.rs @@ -32,7 +32,8 @@ use std::slice; use std::str::from_utf8_unchecked; use std::sync::Arc; use string_cache::{Atom, Namespace}; -use style::dom::{OpaqueNode, TDocument, TElement, TNode, TRestyleDamage, UnsafeNode}; +use style::dom::{OpaqueNode, PresentationalHintsSynthetizer}; +use style::dom::{TDocument, TElement, TNode, TRestyleDamage, UnsafeNode}; use style::element_state::ElementState; #[allow(unused_imports)] // Used in commented-out code. use style::error_reporting::StdoutErrorReporter; @@ -339,12 +340,6 @@ impl<'le> TElement for GeckoElement<'le> { } } - fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V) - where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> - { - // FIXME(bholley) - Need to implement this. - } - #[inline] fn get_attr<'a>(&'a self, namespace: &Namespace, name: &Atom) -> Option<&'a str> { unsafe { @@ -360,6 +355,14 @@ impl<'le> TElement for GeckoElement<'le> { } } +impl<'le> PresentationalHintsSynthetizer for GeckoElement<'le> { + fn synthesize_presentational_hints_for_legacy_attributes<V>(&self, _hints: &mut V) + where V: VecLike<DeclarationBlock<Vec<PropertyDeclaration>>> + { + // FIXME(bholley) - Need to implement this. + } +} + impl<'le> ::selectors::Element for GeckoElement<'le> { type Impl = GeckoSelectorImpl; |