diff options
Diffstat (limited to 'components/script_layout_interface/wrapper_traits.rs')
-rw-r--r-- | components/script_layout_interface/wrapper_traits.rs | 246 |
1 files changed, 134 insertions, 112 deletions
diff --git a/components/script_layout_interface/wrapper_traits.rs b/components/script_layout_interface/wrapper_traits.rs index 200aeaa03af..669a3e331be 100644 --- a/components/script_layout_interface/wrapper_traits.rs +++ b/components/script_layout_interface/wrapper_traits.rs @@ -25,7 +25,7 @@ use style::properties::ServoComputedValues; use style::selector_impl::{PseudoElement, PseudoElementCascadeType, ServoSelectorImpl}; use url::Url; -#[derive(Copy, PartialEq, Clone)] +#[derive(Copy, PartialEq, Clone, Debug)] pub enum PseudoElementType<T> { Normal, Before(T), @@ -70,9 +70,14 @@ impl<T> PseudoElementType<T> { } } +/// Trait to abstract access to layout data across various data structures. +pub trait GetLayoutData { + fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; +} + /// 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: GetLayoutData + TNode { type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode; fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; @@ -86,7 +91,6 @@ pub trait LayoutNode: TNode { fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>; fn init_style_and_layout_data(&self, data: OpaqueStyleAndLayoutData); - fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; fn rev_children(self) -> LayoutIterator<ReverseChildrenIterator<Self>> { LayoutIterator(ReverseChildrenIterator { @@ -144,16 +148,12 @@ impl<ConcreteNode> Iterator for TreeIterator<ConcreteNode> /// 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 + NodeInfo + PartialEq + Sized { +pub trait ThreadSafeLayoutNode: Clone + Copy + GetLayoutData + NodeInfo + PartialEq + Sized { type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<ConcreteThreadSafeLayoutNode = Self> + ::selectors::Element<Impl=ServoSelectorImpl>; type ChildrenIterator: Iterator<Item = Self> + Sized; - /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` - /// with a different pseudo-element type. - fn with_pseudo(&self, pseudo: PseudoElementType<Option<display::T>>) -> Self; - /// Converts self into an `OpaqueNode`. fn opaque(&self) -> OpaqueNode; @@ -183,22 +183,126 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } + fn get_before_pseudo(&self) -> Option<Self> { + self.as_element().and_then(|el| el.get_before_pseudo()).map(|el| el.as_node()) + } + + fn get_after_pseudo(&self) -> Option<Self> { + self.as_element().and_then(|el| el.get_after_pseudo()).map(|el| el.as_node()) + } + + fn get_details_summary_pseudo(&self) -> Option<Self> { + self.as_element().and_then(|el| el.get_details_summary_pseudo()).map(|el| el.as_node()) + } + + fn get_details_content_pseudo(&self) -> Option<Self> { + self.as_element().and_then(|el| el.get_details_content_pseudo()).map(|el| el.as_node()) + } + fn debug_id(self) -> usize; /// Returns an iterator over this node's children. fn children(&self) -> LayoutIterator<Self::ChildrenIterator>; - /// If this is an element, accesses the element data. Fails if this is not an element node. + /// Returns a ThreadSafeLayoutElement if this is an element, None otherwise. + #[inline] + fn as_element(&self) -> Option<Self::ConcreteThreadSafeLayoutElement>; + + #[inline] + fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>> { + self.as_element().map_or(PseudoElementType::Normal, |el| el.get_pseudo_element_type()) + } + + fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; + + fn style(&self, context: &SharedStyleContext) -> Arc<ServoComputedValues> { + if let Some(el) = self.as_element() { + el.style(context) + } else { + debug_assert!(self.is_text_node()); + self.style_for_text_node() + } + } + + fn selected_style(&self) -> Arc<ServoComputedValues> { + if let Some(el) = self.as_element() { + el.selected_style() + } else { + debug_assert!(self.is_text_node()); + self.style_for_text_node() + } + } + + fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool; + + fn restyle_damage(self) -> RestyleDamage; + + fn clear_restyle_damage(self); + + /// Returns true if this node contributes content. This is used in the implementation of + /// `empty_cells` per CSS 2.1 § 17.6.1.1. + fn is_content(&self) -> bool { + self.type_id().is_some() + } + + fn can_be_fragmented(&self) -> bool; + + fn node_text_content(&self) -> String; + + /// If the insertion point is within this node, returns it. Otherwise, returns `None`. + fn selection(&self) -> Option<Range<ByteIndex>>; + + /// If this is an image element, returns its URL. If this is not an image element, fails. + /// + /// FIXME(pcwalton): Don't copy URLs. + fn image_url(&self) -> Option<Url>; + + fn canvas_data(&self) -> Option<HTMLCanvasData>; + + fn svg_data(&self) -> Option<SVGSVGData>; + + /// If this node is an iframe element, returns its pipeline ID. If this node is + /// not an iframe element, fails. + fn iframe_pipeline_id(&self) -> PipelineId; + + fn get_colspan(&self) -> u32; +} + +// 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! +#[allow(unsafe_code)] +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 + Debug + + ::selectors::Element<Impl=ServoSelectorImpl> + + GetLayoutData + + PresentationalHintsSynthetizer { + type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>; + + fn as_node(&self) -> Self::ConcreteThreadSafeLayoutNode; + + /// Creates a new `ThreadSafeLayoutElement` for the same `LayoutElement` + /// with a different pseudo-element type. + fn with_pseudo(&self, pseudo: PseudoElementType<Option<display::T>>) -> Self; + + /// Returns the type ID of this node. + /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. + fn type_id(&self) -> Option<LayoutNodeType>; + #[inline] - fn as_element(&self) -> Self::ConcreteThreadSafeLayoutElement; + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>; + + fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>; #[inline] fn get_pseudo_element_type(&self) -> PseudoElementType<Option<display::T>>; #[inline] fn get_before_pseudo(&self) -> Option<Self> { - if self.is_element() && - self.get_style_data() + if self.get_style_data() .unwrap() .borrow() .current_styles().pseudos @@ -211,8 +315,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn get_after_pseudo(&self) -> Option<Self> { - if self.is_element() && - self.get_style_data() + if self.get_style_data() .unwrap() .borrow() .current_styles().pseudos @@ -225,9 +328,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn get_details_summary_pseudo(&self) -> Option<Self> { - if self.is_element() && - self.as_element().get_local_name() == &atom!("details") && - self.as_element().get_namespace() == &ns!(html) { + if self.get_local_name() == &atom!("details") && + self.get_namespace() == &ns!(html) { Some(self.with_pseudo(PseudoElementType::DetailsSummary(None))) } else { None @@ -236,10 +338,9 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn get_details_content_pseudo(&self) -> Option<Self> { - if self.is_element() && - self.as_element().get_local_name() == &atom!("details") && - self.as_element().get_namespace() == &ns!(html) { - let display = if self.as_element().get_attr(&ns!(), &atom!("open")).is_some() { + if self.get_local_name() == &atom!("details") && + self.get_namespace() == &ns!(html) { + let display = if self.get_attr(&ns!(), &atom!("open")).is_some() { None // Specified by the stylesheet } else { Some(display::T::none) @@ -250,8 +351,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } - fn get_style_and_layout_data(&self) -> Option<OpaqueStyleAndLayoutData>; - /// Returns the style results for the given node. If CSS selector matching /// has not yet been performed, fails. /// @@ -259,13 +358,8 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { #[inline] fn style(&self, context: &SharedStyleContext) -> Arc<ServoComputedValues> { match self.get_pseudo_element_type() { - PseudoElementType::Normal => { - match self.type_id().unwrap() { - LayoutNodeType::Text => self.style_for_text_node(), - LayoutNodeType::Element(_) => self.get_style_data().unwrap().borrow() - .current_styles().primary.clone(), - } - }, + PseudoElementType::Normal => self.get_style_data().unwrap().borrow() + .current_styles().primary.clone(), other => { // Precompute non-eagerly-cascaded pseudo-element styles if not // cached before. @@ -289,7 +383,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } PseudoElementCascadeType::Lazy => { - debug_assert!(self.is_element_or_elements_pseudo()); if !self.get_style_data() .unwrap() .borrow() @@ -298,7 +391,7 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { let new_style = context.stylist .lazily_compute_pseudo_element_style( - &self.as_element(), + self, &style_pseudo, &data.current_styles().primary); data.current_pseudos_mut() @@ -314,6 +407,15 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } + #[inline] + fn selected_style(&self) -> Arc<ServoComputedValues> { + let data = self.get_style_data().unwrap().borrow(); + data.current_styles().pseudos + .get(&PseudoElement::Selection) + .unwrap_or(&data.current_styles().primary) + .clone() + } + /// Returns the already resolved style of the node. /// /// This differs from `style(ctx)` in that if the pseudo-element has not yet @@ -323,11 +425,6 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { /// element style is precomputed, not from general layout itself. #[inline] fn resolved_style(&self) -> Arc<ServoComputedValues> { - // FIXME(bholley): This should move to Element and lose the text node check. - if self.is_text_node() { - return self.style_for_text_node(); - } - let data = self.get_style_data().unwrap().borrow(); match self.get_pseudo_element_type() { PseudoElementType::Normal @@ -337,79 +434,4 @@ pub trait ThreadSafeLayoutNode: Clone + Copy + NodeInfo + PartialEq + Sized { } } - #[inline] - fn selected_style(&self, _context: &SharedStyleContext) -> Arc<ServoComputedValues> { - // FIXME(bholley): This should move to Element and lose the text node check. - if self.is_text_node() { - return self.style_for_text_node(); - } - - let data = self.get_style_data().unwrap().borrow(); - data.current_styles().pseudos - .get(&PseudoElement::Selection) - .unwrap_or(&data.current_styles().primary) - .clone() - } - - fn is_ignorable_whitespace(&self, context: &SharedStyleContext) -> bool; - - fn restyle_damage(self) -> RestyleDamage; - - fn clear_restyle_damage(self); - - /// Returns true if this node contributes content. This is used in the implementation of - /// `empty_cells` per CSS 2.1 § 17.6.1.1. - fn is_content(&self) -> bool { - match self.type_id() { - Some(LayoutNodeType::Element(..)) | Some(LayoutNodeType::Text) => true, - _ => false - } - } - - fn can_be_fragmented(&self) -> bool; - - fn node_text_content(&self) -> String; - - /// If the insertion point is within this node, returns it. Otherwise, returns `None`. - fn selection(&self) -> Option<Range<ByteIndex>>; - - /// If this is an image element, returns its URL. If this is not an image element, fails. - /// - /// FIXME(pcwalton): Don't copy URLs. - fn image_url(&self) -> Option<Url>; - - fn canvas_data(&self) -> Option<HTMLCanvasData>; - - fn svg_data(&self) -> Option<SVGSVGData>; - - /// If this node is an iframe element, returns its pipeline ID. If this node is - /// not an iframe element, fails. - fn iframe_pipeline_id(&self) -> PipelineId; - - fn get_colspan(&self) -> u32; - - fn get_style_data(&self) -> Option<&AtomicRefCell<NodeData>>; -} - -// 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! -#[allow(unsafe_code)] -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 + Debug + - ::selectors::Element<Impl=ServoSelectorImpl> + - PresentationalHintsSynthetizer { - type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<ConcreteThreadSafeLayoutElement = Self>; - - #[inline] - fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&str>; - - #[inline] - fn get_local_name(&self) -> &Atom; - - #[inline] - fn get_namespace(&self) -> &Namespace; } |