From 516619b23049729342132696fb0df51d4f844a6e Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 18 Nov 2015 18:34:27 -0800 Subject: [PATCH 1/4] Make the LayoutElement trait implement TElementAttributes. --- components/layout/wrapper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index a38009f7a52..5432eff0673 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -174,7 +174,7 @@ pub trait LayoutDocument<'ld, Wrappers> : Sized + Copy + Clone fn drain_modified_elements(&self) -> Vec<(Wrappers::Element, ElementSnapshot)>; } -pub trait LayoutElement<'le, Wrappers> : Sized + Copy + Clone + ::selectors::Element +pub trait LayoutElement<'le, Wrappers> : Sized + Copy + Clone + ::selectors::Element + TElementAttributes where Wrappers: WrapperTypes<'le> { fn as_node(&self) -> Wrappers::Node; From 05db7b3652fa61ed3643b52c402dd31aa427d83f Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Wed, 18 Nov 2015 19:51:11 -0800 Subject: [PATCH 2/4] Use associated types instead of wrapper types. --- components/layout/wrapper.rs | 132 +++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 5432eff0673..811258fa0f7 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -74,14 +74,10 @@ use util::str::{is_whitespace, search_index}; /// 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 WrapperTypes<'a> : Sized { - type Node: LayoutNode<'a, Self>; - type Document: LayoutDocument<'a, Self>; - type Element: LayoutElement<'a, Self>; -} +pub trait LayoutNode<'ln> : Sized + Copy + Clone { + type ConcreteLayoutElement: LayoutElement<'ln>; + type ConcreteLayoutDocument: LayoutDocument<'ln>; -pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone - where Wrappers: WrapperTypes<'ln> { /// Returns the type ID of this node. fn type_id(&self) -> NodeTypeId; @@ -89,12 +85,12 @@ pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone fn dump(self); - fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Wrappers>; + fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Self>; /// Returns an iterator over this node's children. - fn children(self) -> LayoutNodeChildrenIterator<'ln, Wrappers>; + fn children(self) -> LayoutNodeChildrenIterator<'ln, Self>; - fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Wrappers>; + fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Self>; /// Converts self into an `OpaqueNode`. fn opaque(&self) -> OpaqueNode; @@ -110,9 +106,9 @@ pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone fn debug_id(self) -> usize; - fn as_element(&self) -> Option; + fn as_element(&self) -> Option; - fn as_document(&self) -> Option; + fn as_document(&self) -> Option; fn children_count(&self) -> u32; @@ -154,29 +150,33 @@ pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone #[inline(always)] fn mutate_layout_data(&self) -> RefMut>; - fn parent_node(&self) -> Option; + fn parent_node(&self) -> Option; - fn first_child(&self) -> Option; + fn first_child(&self) -> Option; - fn last_child(&self) -> Option; + fn last_child(&self) -> Option; - fn prev_sibling(&self) -> Option; + fn prev_sibling(&self) -> Option; - fn next_sibling(&self) -> Option; + fn next_sibling(&self) -> Option; } -pub trait LayoutDocument<'ld, Wrappers> : Sized + Copy + Clone - where Wrappers: WrapperTypes<'ld> { - fn as_node(&self) -> Wrappers::Node; +pub trait LayoutDocument<'ld> : Sized + Copy + Clone { + type ConcreteLayoutNode: LayoutNode<'ld>; + type ConcreteLayoutElement: LayoutElement<'ld>; - fn root_node(&self) -> Option; + fn as_node(&self) -> Self::ConcreteLayoutNode; - fn drain_modified_elements(&self) -> Vec<(Wrappers::Element, ElementSnapshot)>; + fn root_node(&self) -> Option; + + fn drain_modified_elements(&self) -> Vec<(Self::ConcreteLayoutElement, ElementSnapshot)>; } -pub trait LayoutElement<'le, Wrappers> : Sized + Copy + Clone + ::selectors::Element + TElementAttributes - where Wrappers: WrapperTypes<'le> { - fn as_node(&self) -> Wrappers::Node; +pub trait LayoutElement<'le> : Sized + Copy + Clone + ::selectors::Element + TElementAttributes { + type ConcreteLayoutNode: LayoutNode<'le>; + type ConcreteLayoutDocument: LayoutDocument<'le>; + + fn as_node(&self) -> Self::ConcreteLayoutNode; fn style_attribute(&self) -> &'le Option; @@ -224,17 +224,6 @@ pub trait LayoutElement<'le, Wrappers> : Sized + Copy + Clone + ::selectors::Ele } } -pub struct ServoWrapperTypes<'a> { - // Satisfy the compiler about the unused lifetime. - phantom: PhantomData<&'a ()>, -} - -impl<'a> WrapperTypes<'a> for ServoWrapperTypes<'a> { - type Node = ServoLayoutNode<'a>; - type Element = ServoLayoutElement<'a>; - type Document = ServoLayoutDocument<'a>; -} - #[derive(Copy, Clone)] pub struct ServoLayoutNode<'a> { /// The wrapped node. @@ -272,7 +261,10 @@ impl<'ln> ServoLayoutNode<'ln> { } } -impl<'ln> LayoutNode<'ln, ServoWrapperTypes<'ln>> for ServoLayoutNode<'ln> { +impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { + type ConcreteLayoutElement = ServoLayoutElement<'ln>; + type ConcreteLayoutDocument = ServoLayoutDocument<'ln>; + fn type_id(&self) -> NodeTypeId { unsafe { self.node.type_id_for_layout() @@ -289,19 +281,21 @@ impl<'ln> LayoutNode<'ln, ServoWrapperTypes<'ln>> for ServoLayoutNode<'ln> { self.dump_indent(0); } - fn traverse_preorder(self) -> LayoutTreeIterator<'ln, ServoWrapperTypes<'ln>> { + fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Self> { LayoutTreeIterator::new(self) } - fn children(self) -> LayoutNodeChildrenIterator<'ln, ServoWrapperTypes<'ln>> { + fn children(self) -> LayoutNodeChildrenIterator<'ln, Self> { LayoutNodeChildrenIterator { current: self.first_child(), + phantom: PhantomData, } } - fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, ServoWrapperTypes<'ln>> { + fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Self> { LayoutNodeReverseChildrenIterator { - current: self.last_child() + current: self.last_child(), + phantom: PhantomData, } } @@ -452,49 +446,59 @@ impl<'ln> ServoLayoutNode<'ln> { } } -pub struct LayoutNodeChildrenIterator<'a, Wrappers: WrapperTypes<'a>> { - current: Option, +pub struct LayoutNodeChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> { + current: Option, + // Satisfy the compiler about the unused lifetime. + phantom: PhantomData<&'a ()>, } -impl<'a, Wrappers: WrapperTypes<'a>> Iterator for LayoutNodeChildrenIterator<'a, Wrappers> { - type Item = Wrappers::Node; - fn next(&mut self) -> Option { +impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeChildrenIterator<'a, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'a> { + type Item = ConcreteLayoutNode; + fn next(&mut self) -> Option { let node = self.current; self.current = node.and_then(|node| node.next_sibling()); node } } -pub struct LayoutNodeReverseChildrenIterator<'a, Wrappers: WrapperTypes<'a>> { - current: Option, +pub struct LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> { + current: Option, + // Satisfy the compiler about the unused lifetime. + phantom: PhantomData<&'a ()>, } -impl<'a, Wrappers: WrapperTypes<'a>> Iterator for LayoutNodeReverseChildrenIterator<'a, Wrappers> { - type Item = Wrappers::Node; - fn next(&mut self) -> Option { +impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'a> { + type Item = ConcreteLayoutNode; + fn next(&mut self) -> Option { let node = self.current; self.current = node.and_then(|node| node.prev_sibling()); node } } -pub struct LayoutTreeIterator<'a, Wrappers: WrapperTypes<'a>> { - stack: Vec, +pub struct LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> { + stack: Vec, + // Satisfy the compiler about the unused lifetime. + phantom: PhantomData<&'a ()>, } -impl<'a, Wrappers> LayoutTreeIterator<'a, Wrappers> where Wrappers: WrapperTypes<'a> { - fn new(root: Wrappers::Node) -> LayoutTreeIterator<'a, Wrappers> { +impl<'a, ConcreteLayoutNode> LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> { + fn new(root: ConcreteLayoutNode) -> LayoutTreeIterator<'a, ConcreteLayoutNode> { let mut stack = vec!(); stack.push(root); LayoutTreeIterator { - stack: stack + stack: stack, + phantom: PhantomData, } } } -impl<'a, Wrappers> Iterator for LayoutTreeIterator<'a, Wrappers> where Wrappers: WrapperTypes<'a> { - type Item = Wrappers::Node; - fn next(&mut self) -> Option { +impl<'a, ConcreteLayoutNode> Iterator for LayoutTreeIterator<'a, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'a> { + type Item = ConcreteLayoutNode; + fn next(&mut self) -> Option { let ret = self.stack.pop(); ret.map(|node| self.stack.extend(node.rev_children())); ret @@ -508,7 +512,10 @@ pub struct ServoLayoutDocument<'ld> { chain: PhantomData<&'ld ()>, } -impl<'ld> LayoutDocument<'ld, ServoWrapperTypes<'ld>> for ServoLayoutDocument<'ld> { +impl<'ld> LayoutDocument<'ld> for ServoLayoutDocument<'ld> { + type ConcreteLayoutNode = ServoLayoutNode<'ld>; + type ConcreteLayoutElement = ServoLayoutElement<'ld>; + fn as_node(&self) -> ServoLayoutNode<'ld> { ServoLayoutNode::from_layout_js(self.document.upcast()) } @@ -539,7 +546,10 @@ pub struct ServoLayoutElement<'le> { chain: PhantomData<&'le ()>, } -impl<'le> LayoutElement<'le, ServoWrapperTypes<'le>> for ServoLayoutElement<'le> { +impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> { + type ConcreteLayoutNode = ServoLayoutNode<'le>; + type ConcreteLayoutDocument = ServoLayoutDocument<'le>; + fn as_node(&self) -> ServoLayoutNode<'le> { ServoLayoutNode::from_layout_js(self.element.upcast()) } From a85ae24c516a0e69f53a5664c1451ca2da3424e0 Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Fri, 20 Nov 2015 19:12:04 -0800 Subject: [PATCH 3/4] Hoist exported ThreadSafeLayoutFoo functionality into traits. --- components/layout/construct.rs | 2 +- components/layout/flow.rs | 2 +- components/layout/fragment.rs | 2 +- components/layout/layout_task.rs | 2 +- components/layout/query.rs | 2 +- components/layout/table_cell.rs | 2 +- components/layout/traversal.rs | 2 +- components/layout/wrapper.rs | 397 ++++++++++++++++++------------- 8 files changed, 237 insertions(+), 174 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index c2427b63b69..8fcd4b2c5db 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -57,7 +57,7 @@ use traversal::PostorderNodeMutTraversal; use url::Url; use util::linked_list; use util::opts; -use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutNode, TThreadSafeLayoutElement, TThreadSafeLayoutNode}; /// The results of flow construction for a DOM node. #[derive(Clone)] diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 8251bd88b6c..177b8f67135 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -58,7 +58,7 @@ use table_rowgroup::TableRowGroupFlow; use table_wrapper::TableWrapperFlow; use util::geometry::ZERO_RECT; use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; -use wrapper::{PseudoElementType, ThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, ThreadSafeLayoutNode, TThreadSafeLayoutNode}; /// Virtual methods that make up a float context. /// diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 1814e1ad664..f3f22fbcfc6 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -50,7 +50,7 @@ use util::geometry::ZERO_POINT; use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode}; use util::range::*; use util::str::slice_chars; -use wrapper::{PseudoElementType, ThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, ThreadSafeLayoutNode, TThreadSafeLayoutElement, TThreadSafeLayoutNode}; /// Fragments (`struct Fragment`) are the leaves of the layout tree. They cannot position /// themselves. In general, fragments do not have a simple correspondence with CSS fragments in the diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 60a0ec80120..480fbc24c0a 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -73,7 +73,7 @@ use util::opts; use util::task; use util::task_state; use util::workqueue::WorkQueue; -use wrapper::{LayoutDocument, LayoutElement, LayoutNode, ServoLayoutNode}; +use wrapper::{LayoutDocument, LayoutElement, LayoutNode, ServoLayoutNode, TThreadSafeLayoutNode}; /// The number of screens of data we're allowed to generate display lists for in each direction. pub const DISPLAY_PORT_SIZE_FACTOR: i32 = 8; diff --git a/components/layout/query.rs b/components/layout/query.rs index b0a6ba7eb6b..7a4fcea57c9 100644 --- a/components/layout/query.rs +++ b/components/layout/query.rs @@ -31,7 +31,7 @@ use style::values::AuExtensionMethods; use util::cursor::Cursor; use util::geometry::ZERO_POINT; use util::logical_geometry::WritingMode; -use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode, TThreadSafeLayoutNode}; pub struct LayoutRPCImpl(pub Arc>); diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index eda755f177c..944100747d3 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -24,7 +24,7 @@ use style::properties::ComputedValues; use table::InternalTable; use table_row::{CollapsedBorder, CollapsedBorderProvenance}; use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode}; -use wrapper::ThreadSafeLayoutNode; +use wrapper::{ThreadSafeLayoutNode, TThreadSafeLayoutNode}; /// A table formatting context. #[derive(RustcEncodable)] diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 2a25b01df95..49301da8490 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -18,7 +18,7 @@ use std::mem; use util::opts; use util::tid::tid; use wrapper::{LayoutNode, ServoLayoutNode, layout_node_to_unsafe_layout_node}; -use wrapper::{ThreadSafeLayoutNode, UnsafeLayoutNode}; +use wrapper::{ThreadSafeLayoutNode, TThreadSafeLayoutNode, UnsafeLayoutNode}; /// Every time we do another layout, the old bloom filters are invalid. This is /// detected by ticking a generation number every layout. diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 811258fa0f7..31b6035f3b7 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -792,6 +792,163 @@ impl PseudoElementType { /// 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 TThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { + type ConcreteThreadSafeLayoutElement: TThreadSafeLayoutElement<'ln>; + + /// Converts self into an `OpaqueNode`. + fn opaque(&self) -> OpaqueNode; + + /// Returns the type ID of this node. + /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. + fn type_id(&self) -> Option; + + fn debug_id(self) -> usize; + + fn flow_debug_id(self) -> usize; + + /// Returns an iterator over this node's children. + fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln, Self>; + + /// If this is an element, accesses the element data. Fails if this is not an element node. + #[inline] + fn as_element(&self) -> Self::ConcreteThreadSafeLayoutElement; + + #[inline] + fn get_pseudo_element_type(&self) -> PseudoElementType; + + #[inline] + fn get_before_pseudo(&self) -> Option; + + #[inline] + fn get_after_pseudo(&self) -> Option; + + /// Borrows the layout data immutably. Fails on a conflicting borrow. + /// + /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. + #[inline(always)] + fn borrow_layout_data(&self) -> Ref>; + + /// Borrows the layout data mutably. Fails on a conflicting borrow. + /// + /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. + #[inline(always)] + fn mutate_layout_data(&self) -> RefMut>; + + /// Returns the style results for the given node. If CSS selector matching + /// has not yet been performed, fails. + #[inline] + fn style(&self) -> Ref> { + Ref::map(self.borrow_layout_data(), |layout_data_ref| { + let layout_data = layout_data_ref.as_ref().expect("no layout data"); + let style = match self.get_pseudo_element_type() { + PseudoElementType::Before(_) => &layout_data.data.before_style, + PseudoElementType::After(_) => &layout_data.data.after_style, + PseudoElementType::Normal => &layout_data.shared_data.style, + }; + style.as_ref().unwrap() + }) + } + + /// Removes the style from this node. + fn unstyle(self) { + let mut layout_data_ref = self.mutate_layout_data(); + let layout_data = layout_data_ref.as_mut().expect("no layout data"); + + let style = + match self.get_pseudo_element_type() { + PseudoElementType::Before(_) => &mut layout_data.data.before_style, + PseudoElementType::After (_) => &mut layout_data.data.after_style, + PseudoElementType::Normal => &mut layout_data.shared_data.style, + }; + + *style = None; + } + + fn is_ignorable_whitespace(&self) -> bool; + + /// Get the description of how to account for recent style changes. + /// This is a simple bitfield and fine to copy by value. + fn restyle_damage(self) -> RestyleDamage { + let layout_data_ref = self.borrow_layout_data(); + layout_data_ref.as_ref().unwrap().data.restyle_damage + } + + /// Set the restyle damage field. + fn set_restyle_damage(self, damage: RestyleDamage) { + let mut layout_data_ref = self.mutate_layout_data(); + match *layout_data_ref { + Some(ref mut layout_data) => layout_data.data.restyle_damage = damage, + _ => panic!("no layout data for this node"), + } + } + + /// Returns the layout data flags for this node. + fn flags(self) -> LayoutDataFlags; + + /// Adds the given flags to this node. + fn insert_flags(self, new_flags: LayoutDataFlags) { + let mut layout_data_ref = self.mutate_layout_data(); + match *layout_data_ref { + Some(ref mut layout_data) => layout_data.data.flags.insert(new_flags), + _ => panic!("no layout data for this node"), + } + } + + /// Removes the given flags from this node. + fn remove_flags(self, flags: LayoutDataFlags) { + let mut layout_data_ref = self.mutate_layout_data(); + match *layout_data_ref { + Some(ref mut layout_data) => layout_data.data.flags.remove(flags), + _ => panic!("no layout data for this node"), + } + } + + /// 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(NodeTypeId::Element(..)) | Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text(..))) => true, + _ => false + } + } + + /// If this is a text node, generated content, or a form element, copies out + /// its content. Otherwise, panics. + /// + /// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this. + fn text_content(&self) -> TextContent; + + /// If the insertion point is within this node, returns it. Otherwise, returns `None`. + fn insertion_point(&self) -> Option; + + /// 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; + + fn canvas_data(&self) -> Option; + + /// 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; +} + +// These can violate the thread-safety and therefore are not public. +trait DangerousThreadSafeLayoutNode<'ln> : TThreadSafeLayoutNode<'ln> { + unsafe fn dangerous_first_child(&self) -> Option; + unsafe fn dangerous_next_sibling(&self) -> Option; +} + +pub trait TThreadSafeLayoutElement<'le> { + type ConcreteThreadSafeLayoutNode: TThreadSafeLayoutNode<'le>; + + #[inline] + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str>; +} + #[derive(Copy, Clone)] pub struct ThreadSafeLayoutNode<'ln> { /// The wrapped node. @@ -800,6 +957,17 @@ pub struct ThreadSafeLayoutNode<'ln> { pseudo: PseudoElementType, } +impl<'ln> DangerousThreadSafeLayoutNode<'ln> for ThreadSafeLayoutNode<'ln> { + unsafe fn dangerous_first_child(&self) -> Option { + self.get_jsmanaged().first_child_ref() + .map(|node| self.new_with_this_lifetime(&node)) + } + unsafe fn dangerous_next_sibling(&self) -> Option { + self.get_jsmanaged().next_sibling_ref() + .map(|node| self.new_with_this_lifetime(&node)) + } +} + impl<'ln> ThreadSafeLayoutNode<'ln> { /// Creates a new layout node with the same lifetime as this layout node. pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS) -> ThreadSafeLayoutNode<'ln> { @@ -832,14 +1000,23 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { self.node.get_jsmanaged() } - /// Converts self into an `OpaqueNode`. - pub fn opaque(&self) -> OpaqueNode { + /// Borrows the layout data without checking. + #[inline(always)] + fn borrow_layout_data_unchecked(&self) -> *const Option { + unsafe { + self.node.borrow_layout_data_unchecked() + } + } +} + +impl<'ln> TThreadSafeLayoutNode<'ln> for ThreadSafeLayoutNode<'ln> { + type ConcreteThreadSafeLayoutElement = ThreadSafeLayoutElement<'ln>; + + fn opaque(&self) -> OpaqueNode { OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() }) } - /// Returns the type ID of this node. - /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`. - pub fn type_id(&self) -> Option { + fn type_id(&self) -> Option { if self.pseudo != PseudoElementType::Normal { return None } @@ -847,22 +1024,19 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { Some(self.node.type_id()) } - pub fn debug_id(self) -> usize { + fn debug_id(self) -> usize { self.node.debug_id() } - pub fn flow_debug_id(self) -> usize { + fn flow_debug_id(self) -> usize { self.node.flow_debug_id() } - /// Returns an iterator over this node's children. - pub fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln> { + fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln, Self> { ThreadSafeLayoutNodeChildrenIterator::new(*self) } - /// If this is an element, accesses the element data. Fails if this is not an element node. - #[inline] - pub fn as_element(&self) -> ThreadSafeLayoutElement<'ln> { + fn as_element(&self) -> ThreadSafeLayoutElement<'ln> { unsafe { let element = match self.get_jsmanaged().downcast() { Some(e) => e.unsafe_get(), @@ -876,13 +1050,11 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } - #[inline] - pub fn get_pseudo_element_type(&self) -> PseudoElementType { + fn get_pseudo_element_type(&self) -> PseudoElementType { self.pseudo } - #[inline] - pub fn get_before_pseudo(&self) -> Option> { + fn get_before_pseudo(&self) -> Option> { let layout_data_ref = self.borrow_layout_data(); let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap(); node_layout_data_wrapper.data.before_style.as_ref().map(|style| { @@ -890,8 +1062,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { }) } - #[inline] - pub fn get_after_pseudo(&self) -> Option> { + fn get_after_pseudo(&self) -> Option> { let layout_data_ref = self.borrow_layout_data(); let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap(); node_layout_data_wrapper.data.after_style.as_ref().map(|style| { @@ -899,61 +1070,15 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { }) } - /// Borrows the layout data without checking. - #[inline(always)] - fn borrow_layout_data_unchecked(&self) -> *const Option { - unsafe { - self.node.borrow_layout_data_unchecked() - } - } - - /// Borrows the layout data immutably. Fails on a conflicting borrow. - /// - /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. - #[inline(always)] - pub fn borrow_layout_data(&self) -> Ref> { + fn borrow_layout_data(&self) -> Ref> { self.node.borrow_layout_data() } - /// Borrows the layout data mutably. Fails on a conflicting borrow. - /// - /// TODO(pcwalton): Make this private. It will let us avoid borrow flag checks in some cases. - #[inline(always)] - pub fn mutate_layout_data(&self) -> RefMut> { + fn mutate_layout_data(&self) -> RefMut> { self.node.mutate_layout_data() } - /// Returns the style results for the given node. If CSS selector matching - /// has not yet been performed, fails. - #[inline] - pub fn style(&self) -> Ref> { - Ref::map(self.borrow_layout_data(), |layout_data_ref| { - let layout_data = layout_data_ref.as_ref().expect("no layout data"); - let style = match self.get_pseudo_element_type() { - PseudoElementType::Before(_) => &layout_data.data.before_style, - PseudoElementType::After(_) => &layout_data.data.after_style, - PseudoElementType::Normal => &layout_data.shared_data.style, - }; - style.as_ref().unwrap() - }) - } - - /// Removes the style from this node. - pub fn unstyle(self) { - let mut layout_data_ref = self.mutate_layout_data(); - let layout_data = layout_data_ref.as_mut().expect("no layout data"); - - let style = - match self.get_pseudo_element_type() { - PseudoElementType::Before(_) => &mut layout_data.data.before_style, - PseudoElementType::After (_) => &mut layout_data.data.after_style, - PseudoElementType::Normal => &mut layout_data.shared_data.style, - }; - - *style = None; - } - - pub fn is_ignorable_whitespace(&self) -> bool { + fn is_ignorable_whitespace(&self) -> bool { unsafe { let text: LayoutJS = match self.get_jsmanaged().downcast() { Some(text) => text, @@ -980,24 +1105,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } - /// Get the description of how to account for recent style changes. - /// This is a simple bitfield and fine to copy by value. - pub fn restyle_damage(self) -> RestyleDamage { - let layout_data_ref = self.borrow_layout_data(); - layout_data_ref.as_ref().unwrap().data.restyle_damage - } - - /// Set the restyle damage field. - pub fn set_restyle_damage(self, damage: RestyleDamage) { - let mut layout_data_ref = self.mutate_layout_data(); - match *layout_data_ref { - Some(ref mut layout_data) => layout_data.data.restyle_damage = damage, - _ => panic!("no layout data for this node"), - } - } - - /// Returns the layout data flags for this node. - pub fn flags(self) -> LayoutDataFlags { + fn flags(self) -> LayoutDataFlags { unsafe { match *self.borrow_layout_data_unchecked() { None => panic!(), @@ -1006,38 +1114,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } - /// Adds the given flags to this node. - pub fn insert_flags(self, new_flags: LayoutDataFlags) { - let mut layout_data_ref = self.mutate_layout_data(); - match *layout_data_ref { - Some(ref mut layout_data) => layout_data.data.flags.insert(new_flags), - _ => panic!("no layout data for this node"), - } - } - - /// Removes the given flags from this node. - pub fn remove_flags(self, flags: LayoutDataFlags) { - let mut layout_data_ref = self.mutate_layout_data(); - match *layout_data_ref { - Some(ref mut layout_data) => layout_data.data.flags.remove(flags), - _ => panic!("no layout data for this node"), - } - } - - /// Returns true if this node contributes content. This is used in the implementation of - /// `empty_cells` per CSS 2.1 § 17.6.1.1. - pub fn is_content(&self) -> bool { - match self.type_id() { - Some(NodeTypeId::Element(..)) | Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text(..))) => true, - _ => false - } - } - - /// If this is a text node, generated content, or a form element, copies out - /// its content. Otherwise, panics. - /// - /// FIXME(pcwalton): This might have too much copying and/or allocation. Profile this. - pub fn text_content(&self) -> TextContent { + fn text_content(&self) -> TextContent { if self.pseudo != PseudoElementType::Normal { let layout_data_ref = self.borrow_layout_data(); let data = &layout_data_ref.as_ref().unwrap().data; @@ -1074,8 +1151,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { panic!("not text!") } - /// If the insertion point is within this node, returns it. Otherwise, returns `None`. - pub fn insertion_point(&self) -> Option { + fn insertion_point(&self) -> Option { let this = unsafe { self.get_jsmanaged() }; @@ -1094,10 +1170,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { None } - /// If this is an image element, returns its URL. If this is not an image element, fails. - /// - /// FIXME(pcwalton): Don't copy URLs. - pub fn image_url(&self) -> Option { + fn image_url(&self) -> Option { unsafe { self.get_jsmanaged().downcast() .expect("not an image!") @@ -1105,16 +1178,14 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } - pub fn canvas_data(&self) -> Option { + fn canvas_data(&self) -> Option { unsafe { let canvas_element = self.get_jsmanaged().downcast(); canvas_element.map(|canvas| canvas.data()) } } - /// If this node is an iframe element, returns its pipeline ID. If this node is - /// not an iframe element, fails. - pub fn iframe_pipeline_id(&self) -> PipelineId { + fn iframe_pipeline_id(&self) -> PipelineId { use script::dom::htmliframeelement::HTMLIFrameElementLayoutMethods; unsafe { let iframe_element = self.get_jsmanaged().downcast::() @@ -1123,65 +1194,56 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } - pub fn get_colspan(&self) -> u32 { + fn get_colspan(&self) -> u32 { unsafe { self.get_jsmanaged().downcast::().unwrap().get_colspan() } } } -pub struct ThreadSafeLayoutNodeChildrenIterator<'a> { - current_node: Option>, - parent_node: ThreadSafeLayoutNode<'a>, +pub struct ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode: TThreadSafeLayoutNode<'ln>> { + current_node: Option, + parent_node: ConcreteNode, + // Satisfy the compiler about the unused lifetime. + phantom: PhantomData<&'ln ()>, } -impl<'a> ThreadSafeLayoutNodeChildrenIterator<'a> { - fn new(parent: ThreadSafeLayoutNode<'a>) -> ThreadSafeLayoutNodeChildrenIterator<'a> { - fn first_child(parent: ThreadSafeLayoutNode) - -> Option { - if parent.pseudo != PseudoElementType::Normal { - return None - } - - parent.get_before_pseudo().or_else(|| { - unsafe { - parent.get_jsmanaged().first_child_ref() - .map(|node| parent.new_with_this_lifetime(&node)) - } - }) - } - +impl<'ln, ConcreteNode> ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode> + where ConcreteNode: DangerousThreadSafeLayoutNode<'ln> { + fn new(parent: ConcreteNode) -> Self { + let first_child: Option = match parent.get_pseudo_element_type() { + PseudoElementType::Normal => { + parent.get_before_pseudo().or_else(|| { + unsafe { parent.dangerous_first_child() } + }) + }, + _ => None, + }; ThreadSafeLayoutNodeChildrenIterator { - current_node: first_child(parent), + current_node: first_child, parent_node: parent, + phantom: PhantomData, } } } -impl<'a> Iterator for ThreadSafeLayoutNodeChildrenIterator<'a> { - type Item = ThreadSafeLayoutNode<'a>; - fn next(&mut self) -> Option> { +impl<'ln, ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode> + where ConcreteNode: DangerousThreadSafeLayoutNode<'ln> { + type Item = ConcreteNode; + fn next(&mut self) -> Option { let node = self.current_node.clone(); if let Some(ref node) = node { - self.current_node = match node.pseudo { + self.current_node = match node.get_pseudo_element_type() { PseudoElementType::Before(_) => { - match unsafe { self.parent_node.get_jsmanaged().first_child_ref() } { - Some(first) => { - Some(unsafe { - self.parent_node.new_with_this_lifetime(&first) - }) - }, + match unsafe { self.parent_node.dangerous_first_child() } { + Some(first) => Some(first), None => self.parent_node.get_after_pseudo(), } }, PseudoElementType::Normal => { - match unsafe { node.get_jsmanaged().next_sibling_ref() } { - Some(next) => { - Some(unsafe { - self.parent_node.new_with_this_lifetime(&next) - }) - }, + match unsafe { node.dangerous_next_sibling() } { + Some(next) => Some(next), None => self.parent_node.get_after_pseudo(), } }, @@ -1201,9 +1263,10 @@ pub struct ThreadSafeLayoutElement<'le> { element: &'le Element, } -impl<'le> ThreadSafeLayoutElement<'le> { - #[inline] - pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> { +impl<'le> TThreadSafeLayoutElement<'le> for ThreadSafeLayoutElement<'le> { + type ConcreteThreadSafeLayoutNode = ThreadSafeLayoutNode<'le>; + + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> { unsafe { self.element.get_attr_val_for_layout(namespace, name) } From afa3834f3be849cd4e6745b9fe763df512e4f9fc Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Sat, 21 Nov 2015 09:12:43 -0800 Subject: [PATCH 4/4] Rename ThreadSafeLayoutFoo to ServoThreadSafeLayoutFoo and TThreadSafeLayoutFoo to ThreadSafeLayoutFoo. --- components/layout/construct.rs | 66 ++++++++++++++++---------------- components/layout/flow.rs | 6 +-- components/layout/fragment.rs | 16 ++++---- components/layout/layout_task.rs | 3 +- components/layout/query.rs | 6 +-- components/layout/table_cell.rs | 4 +- components/layout/traversal.rs | 12 +++--- components/layout/wrapper.rs | 52 ++++++++++++------------- 8 files changed, 83 insertions(+), 82 deletions(-) diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 8fcd4b2c5db..c09ecc7b173 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -57,7 +57,7 @@ use traversal::PostorderNodeMutTraversal; use url::Url; use util::linked_list; use util::opts; -use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutNode, TThreadSafeLayoutElement, TThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; /// The results of flow construction for a DOM node. #[derive(Clone)] @@ -208,7 +208,7 @@ impl InlineFragmentsAccumulator { } } - fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator { + fn from_inline_node(node: &ServoThreadSafeLayoutNode) -> InlineFragmentsAccumulator { InlineFragmentsAccumulator { fragments: IntermediateInlineFragments::new(), enclosing_node: Some(InlineFragmentNodeInfo { @@ -281,13 +281,13 @@ impl<'a> FlowConstructor<'a> { #[inline] fn set_flow_construction_result(&self, - node: &ThreadSafeLayoutNode, + node: &ServoThreadSafeLayoutNode, result: ConstructionResult) { node.set_flow_construction_result(result); } /// Builds the fragment for the given block or subclass thereof. - fn build_fragment_for_block(&mut self, node: &ThreadSafeLayoutNode) -> Fragment { + fn build_fragment_for_block(&mut self, node: &ServoThreadSafeLayoutNode) -> Fragment { let specific_fragment_info = match node.type_id() { Some(NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLIFrameElement))) => { @@ -343,7 +343,7 @@ impl<'a> FlowConstructor<'a> { fn generate_anonymous_table_flows_if_necessary(&mut self, flow: &mut FlowRef, child: &mut FlowRef, - child_node: &ThreadSafeLayoutNode) { + child_node: &ServoThreadSafeLayoutNode) { if !flow.is_block_flow() { return } @@ -401,7 +401,7 @@ impl<'a> FlowConstructor<'a> { flow: &mut FlowRef, flow_list: &mut Vec, absolute_descendants: &mut AbsoluteDescendants, - node: &ThreadSafeLayoutNode) { + node: &ServoThreadSafeLayoutNode) { let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(); if fragments.is_empty() { return @@ -486,8 +486,8 @@ impl<'a> FlowConstructor<'a> { &mut self, flow: &mut FlowRef, consecutive_siblings: &mut Vec, - node: &ThreadSafeLayoutNode, - kid: ThreadSafeLayoutNode, + node: &ServoThreadSafeLayoutNode, + kid: ServoThreadSafeLayoutNode, inline_fragment_accumulator: &mut InlineFragmentsAccumulator, abs_descendants: &mut AbsoluteDescendants) { match kid.swap_out_construction_result() { @@ -595,7 +595,7 @@ impl<'a> FlowConstructor<'a> { fn build_flow_for_block_starting_with_fragments( &mut self, mut flow: FlowRef, - node: &ThreadSafeLayoutNode, + node: &ServoThreadSafeLayoutNode, initial_fragments: IntermediateInlineFragments) -> ConstructionResult { // Gather up fragments for the inline flows we might need to create. @@ -662,7 +662,7 @@ impl<'a> FlowConstructor<'a> { /// /// FIXME(pcwalton): It is not clear to me that there isn't a cleaner way to handle /// `