diff options
author | Bobby Holley <bobbyholley@gmail.com> | 2015-11-20 09:51:05 -0800 |
---|---|---|
committer | Bobby Holley <bobbyholley@gmail.com> | 2015-11-28 18:01:02 -0800 |
commit | cf33f00018c7dc44a09086d6bb68b253153635ae (patch) | |
tree | efa655a0967756601963042f0b321e18ed37ed02 | |
parent | 77a80919967446639141321ba83b3b0b6d1d1665 (diff) | |
download | servo-cf33f00018c7dc44a09086d6bb68b253153635ae.tar.gz servo-cf33f00018c7dc44a09086d6bb68b253153635ae.zip |
Generalize the rest of layout to operate on generic Layout*.
There wasn't a good way to split this up, unfortunately.
With this change, the only remaining usage of the Servo-specific structures is
in layout_task, where the root node is received from the script task. \o/
-rw-r--r-- | components/layout/construct.rs | 87 | ||||
-rw-r--r-- | components/layout/flow.rs | 6 | ||||
-rw-r--r-- | components/layout/fragment.rs | 26 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 4 | ||||
-rw-r--r-- | components/layout/parallel.rs | 65 | ||||
-rw-r--r-- | components/layout/query.rs | 41 | ||||
-rw-r--r-- | components/layout/sequential.rs | 16 | ||||
-rw-r--r-- | components/layout/table_cell.rs | 8 | ||||
-rw-r--r-- | components/layout/traversal.rs | 60 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 43 |
10 files changed, 199 insertions, 157 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 53b2416ee8d..49cc3567d57 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -38,6 +38,7 @@ use script::dom::bindings::inheritance::{HTMLElementTypeId, NodeTypeId}; use script::dom::htmlobjectelement::is_image_data; use std::borrow::ToOwned; use std::collections::LinkedList; +use std::marker::PhantomData; use std::mem; use std::sync::Arc; use std::sync::atomic::Ordering; @@ -57,7 +58,7 @@ use traversal::PostorderNodeMutTraversal; use url::Url; use util::linked_list; use util::opts; -use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; /// The results of flow construction for a DOM node. #[derive(Clone)] @@ -208,7 +209,8 @@ impl InlineFragmentsAccumulator { } } - fn from_inline_node(node: &ServoThreadSafeLayoutNode) -> InlineFragmentsAccumulator { + fn from_inline_node<'ln, N>(node: &N) -> InlineFragmentsAccumulator + where N: ThreadSafeLayoutNode<'ln> { InlineFragmentsAccumulator { fragments: IntermediateInlineFragments::new(), enclosing_node: Some(InlineFragmentNodeInfo { @@ -265,29 +267,35 @@ impl InlineFragmentsAccumulator { } /// An object that knows how to create flows. -pub struct FlowConstructor<'a> { +pub struct FlowConstructor<'a, 'ln, N: ThreadSafeLayoutNode<'ln>> { /// The layout context. pub layout_context: &'a LayoutContext<'a>, + /// Satisfy the compiler about the unused parameters, which we use to improve the ergonomics of + /// the ensuing impl {} by removing the need to parameterize all the methods individually. + phantom1: PhantomData<&'ln ()>, + phantom2: PhantomData<N>, } -impl<'a> FlowConstructor<'a> { +impl<'a, 'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>> + FlowConstructor<'a, 'ln, ConcreteThreadSafeLayoutNode> { /// Creates a new flow constructor. - pub fn new<'b>(layout_context: &'b LayoutContext<'b>) - -> FlowConstructor<'b> { + pub fn new(layout_context: &'a LayoutContext<'a>) -> Self { FlowConstructor { layout_context: layout_context, + phantom1: PhantomData, + phantom2: PhantomData, } } #[inline] fn set_flow_construction_result(&self, - node: &ServoThreadSafeLayoutNode, + node: &ConcreteThreadSafeLayoutNode, 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: &ServoThreadSafeLayoutNode) -> Fragment { + fn build_fragment_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> Fragment { let specific_fragment_info = match node.type_id() { Some(NodeTypeId::Element(ElementTypeId::HTMLElement( HTMLElementTypeId::HTMLIFrameElement))) => { @@ -343,7 +351,7 @@ impl<'a> FlowConstructor<'a> { fn generate_anonymous_table_flows_if_necessary(&mut self, flow: &mut FlowRef, child: &mut FlowRef, - child_node: &ServoThreadSafeLayoutNode) { + child_node: &ConcreteThreadSafeLayoutNode) { if !flow.is_block_flow() { return } @@ -401,7 +409,7 @@ impl<'a> FlowConstructor<'a> { flow: &mut FlowRef, flow_list: &mut Vec<FlowRef>, absolute_descendants: &mut AbsoluteDescendants, - node: &ServoThreadSafeLayoutNode) { + node: &ConcreteThreadSafeLayoutNode) { let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(); if fragments.is_empty() { return @@ -486,8 +494,8 @@ impl<'a> FlowConstructor<'a> { &mut self, flow: &mut FlowRef, consecutive_siblings: &mut Vec<FlowRef>, - node: &ServoThreadSafeLayoutNode, - kid: ServoThreadSafeLayoutNode, + node: &ConcreteThreadSafeLayoutNode, + kid: ConcreteThreadSafeLayoutNode, inline_fragment_accumulator: &mut InlineFragmentsAccumulator, abs_descendants: &mut AbsoluteDescendants) { match kid.swap_out_construction_result() { @@ -595,7 +603,7 @@ impl<'a> FlowConstructor<'a> { fn build_flow_for_block_starting_with_fragments( &mut self, mut flow: FlowRef, - node: &ServoThreadSafeLayoutNode, + node: &ConcreteThreadSafeLayoutNode, initial_fragments: IntermediateInlineFragments) -> ConstructionResult { // Gather up fragments for the inline flows we might need to create. @@ -662,7 +670,7 @@ impl<'a> FlowConstructor<'a> { /// /// FIXME(pcwalton): It is not clear to me that there isn't a cleaner way to handle /// `<textarea>`. - fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ServoThreadSafeLayoutNode) + fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let mut initial_fragments = IntermediateInlineFragments::new(); let node_is_input_or_text_area = @@ -695,7 +703,7 @@ impl<'a> FlowConstructor<'a> { /// Pushes fragments appropriate for the content of the given node onto the given list. fn create_fragments_for_node_text_content(&self, fragments: &mut IntermediateInlineFragments, - node: &ServoThreadSafeLayoutNode, + node: &ConcreteThreadSafeLayoutNode, style: &Arc<ComputedValues>) { // Fast path: If there is no text content, return immediately. let text_content = node.text_content(); @@ -744,7 +752,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly /// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed /// to happen. - fn build_flow_for_block(&mut self, node: &ServoThreadSafeLayoutNode, float_kind: Option<FloatKind>) + fn build_flow_for_block(&mut self, node: &ConcreteThreadSafeLayoutNode, float_kind: Option<FloatKind>) -> ConstructionResult { let fragment = self.build_fragment_for_block(node); let flow: FlowRef = if node.style().is_multicol() { @@ -758,7 +766,7 @@ impl<'a> FlowConstructor<'a> { /// Bubbles up {ib} splits. fn accumulate_inline_block_splits(&mut self, splits: LinkedList<InlineBlockSplit>, - node: &ServoThreadSafeLayoutNode, + node: &ConcreteThreadSafeLayoutNode, fragment_accumulator: &mut InlineFragmentsAccumulator, opt_inline_block_splits: &mut LinkedList<InlineBlockSplit>) { for split in splits { @@ -783,7 +791,7 @@ impl<'a> FlowConstructor<'a> { /// Returns the `InlineFragmentsConstructionResult`, if any. There will be no /// `InlineFragmentsConstructionResult` if this node consisted entirely of ignorable /// whitespace. - fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode) + fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let mut opt_inline_block_splits: LinkedList<InlineBlockSplit> = LinkedList::new(); let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); @@ -897,7 +905,7 @@ impl<'a> FlowConstructor<'a> { /// Creates an `InlineFragmentsConstructionResult` for replaced content. Replaced content /// doesn't render its children, so this just nukes a child's fragments and creates a /// `Fragment`. - fn build_fragments_for_replaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode) + fn build_fragments_for_replaced_inline_content(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { for kid in node.children() { self.set_flow_construction_result(&kid, ConstructionResult::None) @@ -941,7 +949,7 @@ impl<'a> FlowConstructor<'a> { ConstructionResult::ConstructionItem(construction_item) } - fn build_fragment_for_inline_block(&mut self, node: &ServoThreadSafeLayoutNode) + fn build_fragment_for_inline_block(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let block_flow_result = self.build_flow_for_block(node, None); let (block_flow, abs_descendants) = match block_flow_result { @@ -973,7 +981,7 @@ impl<'a> FlowConstructor<'a> { /// This is an annoying case, because the computed `display` value is `block`, but the /// hypothetical box is inline. - fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ServoThreadSafeLayoutNode) + fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let block_flow_result = self.build_flow_for_block(node, None); let (block_flow, abs_descendants) = match block_flow_result { @@ -1005,7 +1013,7 @@ impl<'a> FlowConstructor<'a> { /// Builds one or more fragments for a node with `display: inline`. This yields an /// `InlineFragmentsConstructionResult`. - fn build_fragments_for_inline(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { + fn build_fragments_for_inline(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { // Is this node replaced content? if !node.is_replaced_content() { // Go to a path that concatenates our kids' fragments. @@ -1021,7 +1029,7 @@ impl<'a> FlowConstructor<'a> { /// `caption-side` property is equal to the given `side`. fn place_table_caption_under_table_wrapper_on_side(&mut self, table_wrapper_flow: &mut FlowRef, - node: &ServoThreadSafeLayoutNode, + node: &ConcreteThreadSafeLayoutNode, side: caption_side::T) { // Only flows that are table captions are matched here. for kid in node.children() { @@ -1046,7 +1054,7 @@ impl<'a> FlowConstructor<'a> { fn generate_anonymous_missing_child(&mut self, child_flows: Vec<FlowRef>, flow: &mut FlowRef, - node: &ServoThreadSafeLayoutNode) { + node: &ConcreteThreadSafeLayoutNode) { let mut anonymous_flow = flow.generate_missing_child_flow(node); let mut consecutive_siblings = vec!(); for kid_flow in child_flows { @@ -1072,7 +1080,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: table`. This yields a `TableWrapperFlow` with /// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it. - fn build_flow_for_table_wrapper(&mut self, node: &ServoThreadSafeLayoutNode, float_value: float::T) + fn build_flow_for_table_wrapper(&mut self, node: &ConcreteThreadSafeLayoutNode, float_value: float::T) -> ConstructionResult { let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper); let mut wrapper_flow: FlowRef = Arc::new( @@ -1134,7 +1142,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow` /// with possibly other `BlockFlow`s or `InlineFlow`s underneath it. - fn build_flow_for_table_caption(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { + fn build_flow_for_table_caption(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let fragment = self.build_fragment_for_block(node); let flow = Arc::new(TableCaptionFlow::from_fragment(fragment)); self.build_flow_for_block_like(flow, node) @@ -1142,7 +1150,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow` /// with possibly other `TableRowFlow`s underneath it. - fn build_flow_for_table_rowgroup(&mut self, node: &ServoThreadSafeLayoutNode) + fn build_flow_for_table_rowgroup(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow); let flow = Arc::new(TableRowGroupFlow::from_fragment(fragment)); @@ -1151,7 +1159,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with /// possibly other `TableCellFlow`s underneath it. - fn build_flow_for_table_row(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { + fn build_flow_for_table_row(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow); let flow = Arc::new(TableRowFlow::from_fragment(fragment)); self.build_flow_for_block_like(flow, node) @@ -1159,7 +1167,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with /// possibly other `BlockFlow`s or `InlineFlow`s underneath it. - fn build_flow_for_table_cell(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { + fn build_flow_for_table_cell(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let fragment = Fragment::new(node, SpecificFragmentInfo::TableCell); // Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true @@ -1180,7 +1188,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: list-item`. This yields a `ListItemFlow` with /// possibly other `BlockFlow`s or `InlineFlow`s underneath it. - fn build_flow_for_list_item(&mut self, node: &ServoThreadSafeLayoutNode, flotation: float::T) + fn build_flow_for_list_item(&mut self, node: &ConcreteThreadSafeLayoutNode, flotation: float::T) -> ConstructionResult { let flotation = FloatKind::from_property(flotation); let marker_fragments = match node.style().get_list().list_style_image.0 { @@ -1239,7 +1247,7 @@ impl<'a> FlowConstructor<'a> { } /// Creates a fragment for a node with `display: table-column`. - fn build_fragments_for_table_column(&mut self, node: &ServoThreadSafeLayoutNode) + fn build_fragments_for_table_column(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { // CSS 2.1 § 17.2.1. Treat all child fragments of a `table-column` as `display: none`. for kid in node.children() { @@ -1254,7 +1262,7 @@ impl<'a> FlowConstructor<'a> { /// Builds a flow for a node with `display: table-column-group`. /// This yields a `TableColGroupFlow`. - fn build_flow_for_table_colgroup(&mut self, node: &ServoThreadSafeLayoutNode) + fn build_flow_for_table_colgroup(&mut self, node: &ConcreteThreadSafeLayoutNode) -> ConstructionResult { let fragment = Fragment::new(node, @@ -1283,7 +1291,7 @@ impl<'a> FlowConstructor<'a> { } /// Builds a flow for a node with 'display: flex'. - fn build_flow_for_flex(&mut self, node: &ServoThreadSafeLayoutNode, float_kind: Option<FloatKind>) + fn build_flow_for_flex(&mut self, node: &ConcreteThreadSafeLayoutNode, float_kind: Option<FloatKind>) -> ConstructionResult { let fragment = self.build_fragment_for_block(node); let flow = Arc::new(FlexFlow::from_fragment(fragment, float_kind)); @@ -1295,7 +1303,7 @@ impl<'a> FlowConstructor<'a> { /// /// TODO(pcwalton): Add some more fast paths, like toggling `display: none`, adding block kids /// to block parents with no {ib} splits, adding out-of-flow kids, etc. - pub fn repair_if_possible(&mut self, node: &ServoThreadSafeLayoutNode) -> bool { + pub fn repair_if_possible(&mut self, node: &ConcreteThreadSafeLayoutNode) -> bool { // We can skip reconstructing the flow if we don't have to reconstruct and none of our kids // did either. // @@ -1403,14 +1411,16 @@ impl<'a> FlowConstructor<'a> { } } -impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { +impl<'a, 'ln, ConcreteThreadSafeLayoutNode> PostorderNodeMutTraversal<'ln, ConcreteThreadSafeLayoutNode> + for FlowConstructor<'a, 'ln, ConcreteThreadSafeLayoutNode> + where ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln> { // Construct Flow based on 'display', 'position', and 'float' values. // // CSS 2.1 Section 9.7 // // TODO: This should actually consult the table in that section to get the // final computed value for 'display'. - fn process(&mut self, node: &ServoThreadSafeLayoutNode) -> bool { + fn process(&mut self, node: &ConcreteThreadSafeLayoutNode) -> bool { // Get the `display` property for this node, and determine whether this node is floated. let (display, float, positioning) = match node.type_id() { None => { @@ -1580,7 +1590,8 @@ trait NodeUtils { fn swap_out_construction_result(self) -> ConstructionResult; } -impl<'ln> NodeUtils for ServoThreadSafeLayoutNode<'ln> { +impl<'ln, ConcreteThreadSafeLayoutNode> NodeUtils for ConcreteThreadSafeLayoutNode + where ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln> { fn is_replaced_content(&self) -> bool { match self.type_id() { None | @@ -1639,7 +1650,7 @@ trait ObjectElement<'a> { fn object_data(&self) -> Option<Url>; } -impl<'ln> ObjectElement<'ln> for ServoThreadSafeLayoutNode<'ln> { +impl<'ln, N> ObjectElement<'ln> for N where N: ThreadSafeLayoutNode<'ln> { fn get_type_and_data(&self) -> (Option<&'ln str>, Option<&'ln str>) { let elem = self.as_element(); (elem.get_attr(&ns!(), &atom!("type")), elem.get_attr(&ns!(), &atom!("data"))) diff --git a/components/layout/flow.rs b/components/layout/flow.rs index 80487b7cbb8..3af799fc82e 100644 --- a/components/layout/flow.rs +++ b/components/layout/flow.rs @@ -59,7 +59,7 @@ use table_wrapper::TableWrapperFlow; use util::geometry::ZERO_RECT; use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; use util::print_tree::PrintTree; -use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, ThreadSafeLayoutNode}; /// Virtual methods that make up a float context. /// @@ -435,7 +435,7 @@ pub trait ImmutableFlowUtils { fn need_anonymous_flow(self, child: &Flow) -> bool; /// Generates missing child flow of this flow. - fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> FlowRef; + fn generate_missing_child_flow<'ln, N: ThreadSafeLayoutNode<'ln>>(self, node: &N) -> FlowRef; /// Returns true if this flow contains fragments that are roots of an absolute flow tree. fn contains_roots_of_absolute_flow_tree(&self) -> bool; @@ -1212,7 +1212,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow { /// FIXME(pcwalton): This duplicates some logic in /// `generate_anonymous_table_flows_if_necessary()`. We should remove this function eventually, /// as it's harder to understand. - fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> FlowRef { + fn generate_missing_child_flow<'ln, N: ThreadSafeLayoutNode<'ln>>(self, node: &N) -> FlowRef { let mut style = node.style().clone(); match self.class() { FlowClass::Table | FlowClass::TableRowGroup => { diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 06167c3b59b..5eae8be6891 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, ServoThreadSafeLayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; +use wrapper::{PseudoElementType, ThreadSafeLayoutElement, ThreadSafeLayoutNode}; /// 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 @@ -309,7 +309,7 @@ pub struct CanvasFragmentInfo { } impl CanvasFragmentInfo { - pub fn new(node: &ServoThreadSafeLayoutNode, data: HTMLCanvasData) -> CanvasFragmentInfo { + pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, data: HTMLCanvasData) -> CanvasFragmentInfo { CanvasFragmentInfo { replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, Some(Au::from_px(data.width as i32)), @@ -345,11 +345,10 @@ impl ImageFragmentInfo { /// /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little /// sense to me. - pub fn new(node: &ServoThreadSafeLayoutNode, - url: Option<Url>, - layout_context: &LayoutContext) - -> ImageFragmentInfo { - fn convert_length(node: &ServoThreadSafeLayoutNode, name: &Atom) -> Option<Au> { + pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, url: Option<Url>, + layout_context: &LayoutContext) -> ImageFragmentInfo { + fn convert_length<'ln, N>(node: &N, name: &Atom) -> Option<Au> + where N: ThreadSafeLayoutNode<'ln> { let element = node.as_element(); element.get_attr(&ns!(), name) .and_then(|string| string.parse().ok()) @@ -423,9 +422,10 @@ pub struct ReplacedImageFragmentInfo { } impl ReplacedImageFragmentInfo { - pub fn new(node: &ServoThreadSafeLayoutNode, - dom_width: Option<Au>, - dom_height: Option<Au>) -> ReplacedImageFragmentInfo { + pub fn new<'ln, N>(node: &N, + dom_width: Option<Au>, + dom_height: Option<Au>) -> ReplacedImageFragmentInfo + where N: ThreadSafeLayoutNode<'ln> { let is_vertical = node.style().writing_mode.is_vertical(); ReplacedImageFragmentInfo { computed_inline_size: None, @@ -583,7 +583,7 @@ pub struct IframeFragmentInfo { impl IframeFragmentInfo { /// Creates the information specific to an iframe fragment. - pub fn new(node: &ServoThreadSafeLayoutNode) -> IframeFragmentInfo { + pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N) -> IframeFragmentInfo { let pipeline_id = node.iframe_pipeline_id(); IframeFragmentInfo { pipeline_id: pipeline_id, @@ -758,7 +758,7 @@ pub struct TableColumnFragmentInfo { impl TableColumnFragmentInfo { /// Create the information specific to an table column fragment. - pub fn new(node: &ServoThreadSafeLayoutNode) -> TableColumnFragmentInfo { + pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N) -> TableColumnFragmentInfo { let element = node.as_element(); let span = element.get_attr(&ns!(), &atom!("span")) .and_then(|string| string.parse().ok()) @@ -771,7 +771,7 @@ impl TableColumnFragmentInfo { impl Fragment { /// Constructs a new `Fragment` instance. - pub fn new(node: &ServoThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment { + pub fn new<'ln, N: ThreadSafeLayoutNode<'ln>>(node: &N, specific: SpecificFragmentInfo) -> Fragment { let style = node.style().clone(); let writing_mode = style.writing_mode; diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 9aac21f7a88..cf7ca56da00 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -758,7 +758,7 @@ impl LayoutTask { possibly_locked_rw_data.block(rw_data); } - fn try_get_layout_root(&self, node: ServoLayoutNode) -> Option<FlowRef> { + fn try_get_layout_root<'ln, N: LayoutNode<'ln>>(&self, node: N) -> Option<FlowRef> { let mut layout_data_ref = node.mutate_layout_data(); let layout_data = match layout_data_ref.as_mut() { @@ -1271,7 +1271,7 @@ impl LayoutTask { } } - unsafe fn dirty_all_nodes(node: ServoLayoutNode) { + unsafe fn dirty_all_nodes<'ln, N: LayoutNode<'ln>>(node: N) { for node in node.traverse_preorder() { // TODO(cgaebel): mark nodes which are sensitive to media queries as // "changed": diff --git a/components/layout/parallel.rs b/components/layout/parallel.rs index c8549c37eb6..4023ed9fbf3 100644 --- a/components/layout/parallel.rs +++ b/components/layout/parallel.rs @@ -22,8 +22,7 @@ use traversal::{ConstructFlows, RecalcStyleForNode}; use traversal::{PostorderDomTraversal, PreorderDomTraversal}; use util::opts; use util::workqueue::{WorkQueue, WorkUnit, WorkerProxy}; -use wrapper::UnsafeLayoutNode; -use wrapper::{LayoutNode, ServoLayoutNode, layout_node_from_unsafe_layout_node, layout_node_to_unsafe_layout_node}; +use wrapper::{LayoutNode, UnsafeLayoutNode}; const CHUNK_SIZE: usize = 64; @@ -88,7 +87,9 @@ pub type ChunkedFlowTraversalFunction = pub type FlowTraversalFunction = extern "Rust" fn(UnsafeFlow, &SharedLayoutContext); /// A parallel top-down DOM traversal. -pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { +pub trait ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode> + : PreorderDomTraversal<'ln, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'ln> { fn run_parallel(&self, nodes: UnsafeLayoutNodeList, proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>); @@ -103,9 +104,7 @@ pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { let mut discovered_child_nodes = Vec::new(); for unsafe_node in *unsafe_nodes.0 { // Get a real layout node. - let node: ServoLayoutNode = unsafe { - layout_node_from_unsafe_layout_node(&unsafe_node) - }; + let node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) }; // Perform the appropriate traversal. self.process(node); @@ -123,7 +122,7 @@ pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { // Possibly enqueue the children. if child_count != 0 { for kid in node.children() { - discovered_child_nodes.push(layout_node_to_unsafe_layout_node(&kid)) + discovered_child_nodes.push(kid.to_unsafe()) } } else { // If there were no more children, start walking back up. @@ -141,7 +140,9 @@ pub trait ParallelPreorderDomTraversal : PreorderDomTraversal { } /// A parallel bottom-up DOM traversal. -trait ParallelPostorderDomTraversal : PostorderDomTraversal { +trait ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode> + : PostorderDomTraversal<'ln, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'ln> { fn root(&self) -> OpaqueNode; /// Process current node and potentially traverse its ancestors. @@ -157,9 +158,7 @@ trait ParallelPostorderDomTraversal : PostorderDomTraversal { /// fetch-and-subtract the parent's children count. fn run_parallel(&self, unsafe_node: UnsafeLayoutNode) { // Get a real layout node. - let mut node: ServoLayoutNode = unsafe { - layout_node_from_unsafe_layout_node(&unsafe_node) - }; + let mut node = unsafe { ConcreteLayoutNode::from_unsafe(&unsafe_node) }; loop { // Perform the appropriate operation. self.process(node); @@ -349,41 +348,59 @@ impl<'a> ParallelPreorderFlowTraversal for ComputeAbsolutePositions<'a> { impl<'a> ParallelPostorderFlowTraversal for BuildDisplayList<'a> {} -impl<'a> ParallelPostorderDomTraversal for ConstructFlows<'a> { +impl<'a, 'ln, ConcreteLayoutNode> ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode> + for ConstructFlows<'a> + where ConcreteLayoutNode: LayoutNode<'ln> { fn root(&self) -> OpaqueNode { self.root } } -impl <'a> ParallelPreorderDomTraversal for RecalcStyleForNode<'a> { +impl<'a, 'ln, ConcreteLayoutNode> ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode> + for RecalcStyleForNode<'a> + where ConcreteLayoutNode: LayoutNode<'ln> { fn run_parallel(&self, unsafe_nodes: UnsafeLayoutNodeList, proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) { - self.run_parallel_helper(unsafe_nodes, proxy, recalc_style, construct_flows) + // Not exactly sure why we need UFCS here, but we seem to. + <RecalcStyleForNode<'a> as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>> + ::run_parallel_helper(self, unsafe_nodes, proxy, + recalc_style::<'ln, ConcreteLayoutNode>, + construct_flows::<'ln, ConcreteLayoutNode>) } } -fn recalc_style(unsafe_nodes: UnsafeLayoutNodeList, - proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) { +fn recalc_style<'ln, ConcreteLayoutNode>(unsafe_nodes: UnsafeLayoutNodeList, + proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) + where ConcreteLayoutNode: LayoutNode<'ln> { let shared_layout_context = proxy.user_data(); let layout_context = LayoutContext::new(shared_layout_context); let recalc_style_for_node_traversal = RecalcStyleForNode { layout_context: &layout_context, root: unsafe_nodes.1, }; - recalc_style_for_node_traversal.run_parallel(unsafe_nodes, proxy) + + // The UFCS is necessary here to select the proper set of generic routines which + // will eventually cast the UnsafeNode to a concrete LayoutNode implementation. + <RecalcStyleForNode as ParallelPreorderDomTraversal<'ln, ConcreteLayoutNode>> + ::run_parallel(&recalc_style_for_node_traversal, unsafe_nodes, proxy) } -fn construct_flows(root: OpaqueNode, - unsafe_node: UnsafeLayoutNode, - proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) { +fn construct_flows<'ln, ConcreteLayoutNode: LayoutNode<'ln>>( + root: OpaqueNode, + unsafe_node: UnsafeLayoutNode, + proxy: &mut WorkerProxy<SharedLayoutContext, UnsafeLayoutNodeList>) { let shared_layout_context = proxy.user_data(); let layout_context = LayoutContext::new(shared_layout_context); let construct_flows_traversal = ConstructFlows { layout_context: &layout_context, root: root, }; - construct_flows_traversal.run_parallel(unsafe_node) + + // The UFCS is necessary here to select the proper set of generic routines which + // will eventually cast the UnsafeNode to a concrete LayoutNode implementation. + <ConstructFlows as ParallelPostorderDomTraversal<'ln, ConcreteLayoutNode>> + ::run_parallel(&construct_flows_traversal, unsafe_node) } fn assign_inline_sizes(unsafe_flows: UnsafeFlowList, @@ -440,13 +457,13 @@ fn run_queue_with_custom_work_data_type<To, F>( queue.run(shared_layout_context); } -pub fn traverse_dom_preorder(root: ServoLayoutNode, +pub fn traverse_dom_preorder<'ln, ConcreteLayoutNode: LayoutNode<'ln>>(root: ConcreteLayoutNode, shared_layout_context: &SharedLayoutContext, queue: &mut WorkQueue<SharedLayoutContext, WorkQueueData>) { run_queue_with_custom_work_data_type(queue, |queue| { queue.push(WorkUnit { - fun: recalc_style, - data: (box vec![layout_node_to_unsafe_layout_node(&root)], root.opaque()), + fun: recalc_style::<'ln, ConcreteLayoutNode>, + data: (box vec![root.to_unsafe()], root.opaque()), }); }, shared_layout_context); } diff --git a/components/layout/query.rs b/components/layout/query.rs index 1a00ffbdb55..076b972061d 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, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode}; +use wrapper::{LayoutNode, ThreadSafeLayoutNode}; pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>); @@ -292,9 +292,8 @@ impl FragmentBorderBoxIterator for MarginRetrievingFragmentBorderBoxIterator { } } -pub fn process_content_box_request(requested_node: ServoLayoutNode, - layout_root: &mut FlowRef) - -> Rect<Au> { +pub fn process_content_box_request<'ln, N: LayoutNode<'ln>>( + requested_node: N, layout_root: &mut FlowRef) -> Rect<Au> { // FIXME(pcwalton): This has not been updated to handle the stacking context relative // stuff. So the position is wrong in most cases. let mut iterator = UnioningFragmentBorderBoxIterator::new(requested_node.opaque()); @@ -305,9 +304,8 @@ pub fn process_content_box_request(requested_node: ServoLayoutNode, } } -pub fn process_content_boxes_request(requested_node: ServoLayoutNode, - layout_root: &mut FlowRef) - -> Vec<Rect<Au>> { +pub fn process_content_boxes_request<'ln, N: LayoutNode<'ln>>(requested_node: N, layout_root: &mut FlowRef) + -> Vec<Rect<Au>> { // FIXME(pcwalton): This has not been updated to handle the stacking context relative // stuff. So the position is wrong in most cases. let mut iterator = CollectingFragmentBorderBoxIterator::new(requested_node.opaque()); @@ -431,9 +429,8 @@ impl FragmentBorderBoxIterator for ParentOffsetBorderBoxIterator { } } -pub fn process_node_geometry_request(requested_node: ServoLayoutNode, - layout_root: &mut FlowRef) - -> Rect<i32> { +pub fn process_node_geometry_request<'ln, N: LayoutNode<'ln>>(requested_node: N, layout_root: &mut FlowRef) + -> Rect<i32> { let mut iterator = FragmentLocatingFragmentIterator::new(requested_node.opaque()); sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); iterator.client_rect @@ -441,12 +438,10 @@ pub fn process_node_geometry_request(requested_node: ServoLayoutNode, /// Return the resolved value of property for a given (pseudo)element. /// https://drafts.csswg.org/cssom/#resolved-value -pub fn process_resolved_style_request(requested_node: ServoLayoutNode, - pseudo: &Option<PseudoElement>, - property: &Atom, - layout_root: &mut FlowRef) - -> Option<String> { - let layout_node = ServoThreadSafeLayoutNode::new(&requested_node); +pub fn process_resolved_style_request<'ln, N: LayoutNode<'ln>>( + requested_node: N, pseudo: &Option<PseudoElement>, + property: &Atom, layout_root: &mut FlowRef) -> Option<String> { + let layout_node = requested_node.to_threadsafe(); let layout_node = match pseudo { &Some(PseudoElement::Before) => layout_node.get_before_pseudo(), &Some(PseudoElement::After) => layout_node.get_after_pseudo(), @@ -480,10 +475,11 @@ pub fn process_resolved_style_request(requested_node: ServoLayoutNode, // There are probably other quirks. let applies = true; - fn used_value_for_position_property(layout_node: ServoThreadSafeLayoutNode, - layout_root: &mut FlowRef, - requested_node: ServoLayoutNode, - property: &Atom) -> Option<String> { + fn used_value_for_position_property<'ln, N: LayoutNode<'ln>>( + layout_node: N::ConcreteThreadSafeLayoutNode, + layout_root: &mut FlowRef, + requested_node: N, + property: &Atom) -> Option<String> { let layout_data = layout_node.borrow_layout_data(); let position = layout_data.as_ref().map(|layout_data| { match layout_data.data.flow_construction_result { @@ -560,9 +556,8 @@ pub fn process_resolved_style_request(requested_node: ServoLayoutNode, } } -pub fn process_offset_parent_query(requested_node: ServoLayoutNode, - layout_root: &mut FlowRef) - -> OffsetParentResponse { +pub fn process_offset_parent_query<'ln, N: LayoutNode<'ln>>(requested_node: N, layout_root: &mut FlowRef) + -> OffsetParentResponse { let mut iterator = ParentOffsetBorderBoxIterator::new(requested_node.opaque()); sequential::iterate_through_flow_tree_fragment_border_boxes(layout_root, &mut iterator); let parent_info_index = iterator.parent_nodes.iter().rposition(|info| info.is_some()); diff --git a/components/layout/sequential.rs b/components/layout/sequential.rs index 36f754a2cf5..275f4ed0429 100644 --- a/components/layout/sequential.rs +++ b/components/layout/sequential.rs @@ -19,11 +19,15 @@ use traversal::{BuildDisplayList, ComputeAbsolutePositions}; use traversal::{PostorderDomTraversal, PreorderDomTraversal}; use util::geometry::ZERO_POINT; use util::opts; -use wrapper::{LayoutNode, ServoLayoutNode}; - -pub fn traverse_dom_preorder(root: ServoLayoutNode, - shared_layout_context: &SharedLayoutContext) { - fn doit(node: ServoLayoutNode, recalc_style: RecalcStyleForNode, construct_flows: ConstructFlows) { +use wrapper::LayoutNode; + +pub fn traverse_dom_preorder<'le, N>(root: N, + shared_layout_context: &SharedLayoutContext) + where N: LayoutNode<'le> { + fn doit<'le, N>(node: N, + recalc_style: RecalcStyleForNode, + construct_flows: ConstructFlows) + where N: LayoutNode<'le> { recalc_style.process(node); for kid in node.children() { @@ -43,7 +47,7 @@ pub fn traverse_dom_preorder(root: ServoLayoutNode, root: root.opaque(), }; - doit(root, recalc_style, construct_flows); + doit::<'le, N>(root, recalc_style, construct_flows); } pub fn resolve_generated_content(root: &mut FlowRef, shared_layout_context: &SharedLayoutContext) { diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index 2b89c693599..ad6d2ca1804 100644 --- a/components/layout/table_cell.rs +++ b/components/layout/table_cell.rs @@ -25,7 +25,7 @@ use table::InternalTable; use table_row::{CollapsedBorder, CollapsedBorderProvenance}; use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode}; use util::print_tree::PrintTree; -use wrapper::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode}; +use wrapper::{ThreadSafeLayoutNode}; /// A table formatting context. #[derive(RustcEncodable)] @@ -45,10 +45,8 @@ pub struct TableCellFlow { } impl TableCellFlow { - pub fn from_node_fragment_and_visibility_flag(node: &ServoThreadSafeLayoutNode, - fragment: Fragment, - visible: bool) - -> TableCellFlow { + pub fn from_node_fragment_and_visibility_flag<'ln, N: ThreadSafeLayoutNode<'ln>>( + node: &N, fragment: Fragment, visible: bool) -> TableCellFlow { TableCellFlow { block_flow: BlockFlow::from_fragment(fragment, None), collapsed_borders: CollapsedBordersForCell::new(), diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index a224f57feb1..cf3be1b9d94 100644 --- a/components/layout/traversal.rs +++ b/components/layout/traversal.rs @@ -17,8 +17,8 @@ use std::cell::RefCell; use std::mem; use util::opts; use util::tid::tid; -use wrapper::{LayoutNode, ServoLayoutNode, layout_node_to_unsafe_layout_node}; -use wrapper::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode, UnsafeLayoutNode}; +use wrapper::{LayoutNode, UnsafeLayoutNode}; +use wrapper::{ThreadSafeLayoutNode}; /// Every time we do another layout, the old bloom filters are invalid. This is /// detected by ticking a generation number every layout. @@ -51,10 +51,11 @@ thread_local!( /// /// If one does not exist, a new one will be made for you. If it is out of date, /// it will be cleared and reused. -fn take_task_local_bloom_filter(parent_node: Option<ServoLayoutNode>, - root: OpaqueNode, - layout_context: &LayoutContext) - -> Box<BloomFilter> { +fn take_task_local_bloom_filter<'ln, N>(parent_node: Option<N>, + root: OpaqueNode, + layout_context: &LayoutContext) + -> Box<BloomFilter> + where N: LayoutNode<'ln> { STYLE_BLOOM.with(|style_bloom| { match (parent_node, style_bloom.borrow_mut().take()) { // Root node. Needs new bloom filter. @@ -70,7 +71,7 @@ fn take_task_local_bloom_filter(parent_node: Option<ServoLayoutNode>, } // Found cached bloom filter. (Some(parent), Some((mut bloom_filter, old_node, old_generation))) => { - if old_node == layout_node_to_unsafe_layout_node(&parent) && + if old_node == parent.to_unsafe() && old_generation == layout_context.shared.generation { // Hey, the cached parent is our parent! We can reuse the bloom filter. debug!("[{}] Parent matches (={}). Reusing bloom filter.", tid(), old_node.0); @@ -97,9 +98,10 @@ fn put_task_local_bloom_filter(bf: Box<BloomFilter>, } /// "Ancestors" in this context is inclusive of ourselves. -fn insert_ancestors_into_bloom_filter(bf: &mut Box<BloomFilter>, - mut n: ServoLayoutNode, - root: OpaqueNode) { +fn insert_ancestors_into_bloom_filter<'ln, N>(bf: &mut Box<BloomFilter>, + mut n: N, + root: OpaqueNode) + where N: LayoutNode<'ln> { debug!("[{}] Inserting ancestors.", tid()); let mut ancestors = 0; loop { @@ -116,21 +118,21 @@ fn insert_ancestors_into_bloom_filter(bf: &mut Box<BloomFilter>, /// A top-down traversal. -pub trait PreorderDomTraversal { +pub trait PreorderDomTraversal<'ln, ConcreteLayoutNode: LayoutNode<'ln>> { /// The operation to perform. Return true to continue or false to stop. - fn process(&self, node: ServoLayoutNode); + fn process(&self, node: ConcreteLayoutNode); } /// A bottom-up traversal, with a optional in-order pass. -pub trait PostorderDomTraversal { +pub trait PostorderDomTraversal<'ln, ConcreteLayoutNode: LayoutNode<'ln>> { /// The operation to perform. Return true to continue or false to stop. - fn process(&self, node: ServoLayoutNode); + fn process(&self, node: ConcreteLayoutNode); } /// A bottom-up, parallelizable traversal. -pub trait PostorderNodeMutTraversal { +pub trait PostorderNodeMutTraversal<'ln, ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>> { /// The operation to perform. Return true to continue or false to stop. - fn process<'a>(&'a mut self, node: &ServoThreadSafeLayoutNode<'a>) -> bool; + fn process(&mut self, node: &ConcreteThreadSafeLayoutNode) -> bool; } /// The recalc-style-for-node traversal, which styles each node and must run before @@ -141,10 +143,12 @@ pub struct RecalcStyleForNode<'a> { pub root: OpaqueNode, } -impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { +impl<'a, 'ln, ConcreteLayoutNode> PreorderDomTraversal<'ln, ConcreteLayoutNode> + for RecalcStyleForNode<'a> + where ConcreteLayoutNode: LayoutNode<'ln> { #[inline] #[allow(unsafe_code)] - fn process(&self, node: ServoLayoutNode) { + fn process(&self, node: ConcreteLayoutNode) { // Initialize layout data. // // FIXME(pcwalton): Stop allocating here. Ideally this should just be done by the HTML @@ -162,7 +166,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { // Remove existing CSS styles from nodes whose content has changed (e.g. text changed), // to force non-incremental reflow. if node.has_changed() { - let node = ServoThreadSafeLayoutNode::new(&node); + let node = node.to_threadsafe(); node.unstyle(); } @@ -199,7 +203,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { }, None => { if node.has_changed() { - ServoThreadSafeLayoutNode::new(&node).set_restyle_damage( + node.to_threadsafe().set_restyle_damage( incremental::rebuild_and_reflow()) } None @@ -222,12 +226,12 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { } StyleSharingResult::StyleWasShared(index, damage) => { style_sharing_candidate_cache.touch(index); - ServoThreadSafeLayoutNode::new(&node).set_restyle_damage(damage); + node.to_threadsafe().set_restyle_damage(damage); } } } - let unsafe_layout_node = layout_node_to_unsafe_layout_node(&node); + let unsafe_layout_node = node.to_unsafe(); // Before running the children, we need to insert our nodes into the bloom // filter. @@ -246,13 +250,15 @@ pub struct ConstructFlows<'a> { pub root: OpaqueNode, } -impl<'a> PostorderDomTraversal for ConstructFlows<'a> { +impl<'a, 'ln, ConcreteLayoutNode> PostorderDomTraversal<'ln, ConcreteLayoutNode> + for ConstructFlows<'a> + where ConcreteLayoutNode: LayoutNode<'ln> { #[inline] #[allow(unsafe_code)] - fn process(&self, node: ServoLayoutNode) { + fn process(&self, node: ConcreteLayoutNode) { // Construct flows for this node. { - let tnode = ServoThreadSafeLayoutNode::new(&node); + let tnode = node.to_threadsafe(); // Always reconstruct if incremental layout is turned off. let nonincremental_layout = opts::get().nonincremental_layout; @@ -277,7 +283,7 @@ impl<'a> PostorderDomTraversal for ConstructFlows<'a> { node.set_dirty_descendants(false); } - let unsafe_layout_node = layout_node_to_unsafe_layout_node(&node); + let unsafe_layout_node = node.to_unsafe(); let (mut bf, old_node, old_generation) = STYLE_BLOOM.with(|style_bloom| { @@ -296,7 +302,7 @@ impl<'a> PostorderDomTraversal for ConstructFlows<'a> { Some(parent) => { // Otherwise, put it back, but remove this node. node.remove_from_bloom_filter(&mut *bf); - let unsafe_parent = layout_node_to_unsafe_layout_node(&parent); + let unsafe_parent = parent.to_unsafe(); put_task_local_bloom_filter(bf, &unsafe_parent, self.layout_context); }, }; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 0a31ccfc429..be9f48703e3 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -71,15 +71,25 @@ use style::restyle_hints::{ElementSnapshot, RESTYLE_DESCENDANTS, RESTYLE_LATER_S use url::Url; use util::str::{is_whitespace, search_index}; +/// Opaque type stored in type-unsafe work queues for parallel layout. +/// Must be transmutable to and from LayoutNode. +pub type UnsafeLayoutNode = (usize, usize); + /// 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<'ln> : Sized + Copy + Clone { + type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'ln>; type ConcreteLayoutElement: LayoutElement<'ln, ConcreteLayoutNode = Self, ConcreteLayoutDocument = Self::ConcreteLayoutDocument>; type ConcreteLayoutDocument: LayoutDocument<'ln, ConcreteLayoutNode = Self, ConcreteLayoutElement = Self::ConcreteLayoutElement>; + fn to_unsafe(&self) -> UnsafeLayoutNode; + unsafe fn from_unsafe(&UnsafeLayoutNode) -> Self; + + fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode; + /// Returns the type ID of this node. fn type_id(&self) -> NodeTypeId; @@ -268,9 +278,26 @@ impl<'ln> ServoLayoutNode<'ln> { } impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> { + type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'ln>; type ConcreteLayoutElement = ServoLayoutElement<'ln>; type ConcreteLayoutDocument = ServoLayoutDocument<'ln>; + fn to_unsafe(&self) -> UnsafeLayoutNode { + unsafe { + let ptr: usize = mem::transmute_copy(self); + (ptr, 0) + } + } + + unsafe fn from_unsafe(n: &UnsafeLayoutNode) -> Self { + let (node, _) = *n; + mem::transmute(node) + } + + fn to_threadsafe(&self) -> Self::ConcreteThreadSafeLayoutNode { + ServoThreadSafeLayoutNode::new(self) + } + fn type_id(&self) -> NodeTypeId { unsafe { self.node.type_id_for_layout() @@ -1281,22 +1308,6 @@ impl<'le> ThreadSafeLayoutElement<'le> for ServoThreadSafeLayoutElement<'le> { } } -/// Opaque type stored in type-unsafe work queues for parallel layout. -/// Must be transmutable to and from LayoutNode. -pub type UnsafeLayoutNode = (usize, usize); - -pub fn layout_node_to_unsafe_layout_node(node: &ServoLayoutNode) -> UnsafeLayoutNode { - unsafe { - let ptr: usize = mem::transmute_copy(node); - (ptr, 0) - } -} - -pub unsafe fn layout_node_from_unsafe_layout_node(node: &UnsafeLayoutNode) -> ServoLayoutNode { - let (node, _) = *node; - mem::transmute(node) -} - pub enum TextContent { Text(String), GeneratedContent(Vec<ContentItem>), |