diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2015-11-24 04:01:32 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2015-11-24 04:01:32 +0530 |
commit | 711f516d80c9c0026744cd373d398dc294f14d2a (patch) | |
tree | eaca2f68cede9642add82670bdc884e39fead10c /components/layout | |
parent | 6449cd09ebd7f7e3545039c26bcbe9a6ca7a5621 (diff) | |
parent | afa3834f3be849cd4e6745b9fe763df512e4f9fc (diff) | |
download | servo-711f516d80c9c0026744cd373d398dc294f14d2a.tar.gz servo-711f516d80c9c0026744cd373d398dc294f14d2a.zip |
Auto merge of #8639 - bholley:generalize_wrappers2, r=pcwalton
Use associated types for layout wrapper trait, and generalized ThreadSafeLayoutFoo
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8639)
<!-- Reviewable:end -->
Diffstat (limited to 'components/layout')
-rw-r--r-- | components/layout/construct.rs | 66 | ||||
-rw-r--r-- | components/layout/flow.rs | 6 | ||||
-rw-r--r-- | components/layout/fragment.rs | 16 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 3 | ||||
-rw-r--r-- | components/layout/query.rs | 6 | ||||
-rw-r--r-- | components/layout/table_cell.rs | 4 | ||||
-rw-r--r-- | components/layout/traversal.rs | 12 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 553 |
8 files changed, 370 insertions, 296 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs index c2427b63b69..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}; +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<FlowRef>, 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<FlowRef>, - 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 /// `<textarea>`. - fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode) + fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { let mut initial_fragments = IntermediateInlineFragments::new(); let node_is_input_or_text_area = @@ -695,7 +695,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: &ThreadSafeLayoutNode, + node: &ServoThreadSafeLayoutNode, style: &Arc<ComputedValues>) { // Fast path: If there is no text content, return immediately. let text_content = node.text_content(); @@ -744,7 +744,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: &ThreadSafeLayoutNode, float_kind: Option<FloatKind>) + fn build_flow_for_block(&mut self, node: &ServoThreadSafeLayoutNode, float_kind: Option<FloatKind>) -> ConstructionResult { let fragment = self.build_fragment_for_block(node); let flow: FlowRef = if node.style().is_multicol() { @@ -758,7 +758,7 @@ impl<'a> FlowConstructor<'a> { /// Bubbles up {ib} splits. fn accumulate_inline_block_splits(&mut self, splits: LinkedList<InlineBlockSplit>, - node: &ThreadSafeLayoutNode, + node: &ServoThreadSafeLayoutNode, fragment_accumulator: &mut InlineFragmentsAccumulator, opt_inline_block_splits: &mut LinkedList<InlineBlockSplit>) { for split in splits { @@ -783,7 +783,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: &ThreadSafeLayoutNode) + fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { let mut opt_inline_block_splits: LinkedList<InlineBlockSplit> = LinkedList::new(); let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); @@ -897,7 +897,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: &ThreadSafeLayoutNode) + fn build_fragments_for_replaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { for kid in node.children() { self.set_flow_construction_result(&kid, ConstructionResult::None) @@ -941,7 +941,7 @@ impl<'a> FlowConstructor<'a> { ConstructionResult::ConstructionItem(construction_item) } - fn build_fragment_for_inline_block(&mut self, node: &ThreadSafeLayoutNode) + fn build_fragment_for_inline_block(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { let block_flow_result = self.build_flow_for_block(node, None); let (block_flow, abs_descendants) = match block_flow_result { @@ -973,7 +973,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: &ThreadSafeLayoutNode) + fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { let block_flow_result = self.build_flow_for_block(node, None); let (block_flow, abs_descendants) = match block_flow_result { @@ -1005,7 +1005,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: &ThreadSafeLayoutNode) -> ConstructionResult { + fn build_fragments_for_inline(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { // Is this node replaced content? if !node.is_replaced_content() { // Go to a path that concatenates our kids' fragments. @@ -1021,7 +1021,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: &ThreadSafeLayoutNode, + node: &ServoThreadSafeLayoutNode, side: caption_side::T) { // Only flows that are table captions are matched here. for kid in node.children() { @@ -1046,7 +1046,7 @@ impl<'a> FlowConstructor<'a> { fn generate_anonymous_missing_child(&mut self, child_flows: Vec<FlowRef>, flow: &mut FlowRef, - node: &ThreadSafeLayoutNode) { + node: &ServoThreadSafeLayoutNode) { let mut anonymous_flow = flow.generate_missing_child_flow(node); let mut consecutive_siblings = vec!(); for kid_flow in child_flows { @@ -1072,7 +1072,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: &ThreadSafeLayoutNode, float_value: float::T) + fn build_flow_for_table_wrapper(&mut self, node: &ServoThreadSafeLayoutNode, float_value: float::T) -> ConstructionResult { let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper); let mut wrapper_flow: FlowRef = Arc::new( @@ -1134,7 +1134,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: &ThreadSafeLayoutNode) -> ConstructionResult { + fn build_flow_for_table_caption(&mut self, node: &ServoThreadSafeLayoutNode) -> 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 +1142,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: &ThreadSafeLayoutNode) + fn build_flow_for_table_rowgroup(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow); let flow = Arc::new(TableRowGroupFlow::from_fragment(fragment)); @@ -1151,7 +1151,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: &ThreadSafeLayoutNode) -> ConstructionResult { + fn build_flow_for_table_row(&mut self, node: &ServoThreadSafeLayoutNode) -> 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 +1159,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: &ThreadSafeLayoutNode) -> ConstructionResult { + fn build_flow_for_table_cell(&mut self, node: &ServoThreadSafeLayoutNode) -> 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 +1180,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: &ThreadSafeLayoutNode, flotation: float::T) + fn build_flow_for_list_item(&mut self, node: &ServoThreadSafeLayoutNode, flotation: float::T) -> ConstructionResult { let flotation = FloatKind::from_property(flotation); let marker_fragments = match node.style().get_list().list_style_image.0 { @@ -1239,7 +1239,7 @@ impl<'a> FlowConstructor<'a> { } /// Creates a fragment for a node with `display: table-column`. - fn build_fragments_for_table_column(&mut self, node: &ThreadSafeLayoutNode) + fn build_fragments_for_table_column(&mut self, node: &ServoThreadSafeLayoutNode) -> 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 +1254,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: &ThreadSafeLayoutNode) + fn build_flow_for_table_colgroup(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult { let fragment = Fragment::new(node, @@ -1283,7 +1283,7 @@ impl<'a> FlowConstructor<'a> { } /// Builds a flow for a node with 'display: flex'. - fn build_flow_for_flex(&mut self, node: &ThreadSafeLayoutNode, float_kind: Option<FloatKind>) + fn build_flow_for_flex(&mut self, node: &ServoThreadSafeLayoutNode, 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 +1295,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: &ThreadSafeLayoutNode) -> bool { + pub fn repair_if_possible(&mut self, node: &ServoThreadSafeLayoutNode) -> bool { // We can skip reconstructing the flow if we don't have to reconstruct and none of our kids // did either. // @@ -1410,7 +1410,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { // // TODO: This should actually consult the table in that section to get the // final computed value for 'display'. - fn process(&mut self, node: &ThreadSafeLayoutNode) -> bool { + fn process(&mut self, node: &ServoThreadSafeLayoutNode) -> 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 +1580,7 @@ trait NodeUtils { fn swap_out_construction_result(self) -> ConstructionResult; } -impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> { +impl<'ln> NodeUtils for ServoThreadSafeLayoutNode<'ln> { fn is_replaced_content(&self) -> bool { match self.type_id() { None | @@ -1639,7 +1639,7 @@ trait ObjectElement<'a> { fn object_data(&self) -> Option<Url>; } -impl<'ln> ObjectElement<'ln> for ThreadSafeLayoutNode<'ln> { +impl<'ln> ObjectElement<'ln> for ServoThreadSafeLayoutNode<'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 8251bd88b6c..fba998d759e 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, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode}; /// Virtual methods that make up a float context. /// @@ -428,7 +428,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: &ThreadSafeLayoutNode) -> FlowRef; + fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> 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; @@ -1186,7 +1186,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: &ThreadSafeLayoutNode) -> FlowRef { + fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> 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 70fcffffe3f..df49117d626 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, ServoThreadSafeLayoutNode, 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: &ThreadSafeLayoutNode, data: HTMLCanvasData) -> CanvasFragmentInfo { + pub fn new(node: &ServoThreadSafeLayoutNode, data: HTMLCanvasData) -> CanvasFragmentInfo { CanvasFragmentInfo { replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node, Some(Au::from_px(data.width as i32)), @@ -345,11 +345,11 @@ impl ImageFragmentInfo { /// /// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little /// sense to me. - pub fn new(node: &ThreadSafeLayoutNode, + pub fn new(node: &ServoThreadSafeLayoutNode, url: Option<Url>, layout_context: &LayoutContext) -> ImageFragmentInfo { - fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option<Au> { + fn convert_length(node: &ServoThreadSafeLayoutNode, name: &Atom) -> Option<Au> { let element = node.as_element(); element.get_attr(&ns!(""), name) .and_then(|string| string.parse().ok()) @@ -423,7 +423,7 @@ pub struct ReplacedImageFragmentInfo { } impl ReplacedImageFragmentInfo { - pub fn new(node: &ThreadSafeLayoutNode, + pub fn new(node: &ServoThreadSafeLayoutNode, dom_width: Option<Au>, dom_height: Option<Au>) -> ReplacedImageFragmentInfo { let is_vertical = node.style().writing_mode.is_vertical(); @@ -583,7 +583,7 @@ pub struct IframeFragmentInfo { impl IframeFragmentInfo { /// Creates the information specific to an iframe fragment. - pub fn new(node: &ThreadSafeLayoutNode) -> IframeFragmentInfo { + pub fn new(node: &ServoThreadSafeLayoutNode) -> 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: &ThreadSafeLayoutNode) -> TableColumnFragmentInfo { + pub fn new(node: &ServoThreadSafeLayoutNode) -> 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: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment { + pub fn new(node: &ServoThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment { let style = node.style().clone(); let writing_mode = style.writing_mode; Fragment { diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 60a0ec80120..d9bbc2b78cc 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -73,7 +73,8 @@ 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}; +use wrapper::{ServoLayoutNode, ThreadSafeLayoutNode}; /// 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 7c789c76cac..cdb0c7da0eb 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, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode}; pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>); @@ -446,7 +446,7 @@ pub fn process_resolved_style_request(requested_node: ServoLayoutNode, property: &Atom, layout_root: &mut FlowRef) -> Option<String> { - let layout_node = ThreadSafeLayoutNode::new(&requested_node); + let layout_node = ServoThreadSafeLayoutNode::new(&requested_node); let layout_node = match pseudo { &Some(PseudoElement::Before) => layout_node.get_before_pseudo(), &Some(PseudoElement::After) => layout_node.get_after_pseudo(), @@ -480,7 +480,7 @@ 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: ThreadSafeLayoutNode, + fn used_value_for_position_property(layout_node: ServoThreadSafeLayoutNode, layout_root: &mut FlowRef, requested_node: ServoLayoutNode, property: &Atom) -> Option<String> { diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs index eda755f177c..ed5c878c9f5 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::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode}; /// A table formatting context. #[derive(RustcEncodable)] @@ -44,7 +44,7 @@ pub struct TableCellFlow { } impl TableCellFlow { - pub fn from_node_fragment_and_visibility_flag(node: &ThreadSafeLayoutNode, + pub fn from_node_fragment_and_visibility_flag(node: &ServoThreadSafeLayoutNode, fragment: Fragment, visible: bool) -> TableCellFlow { diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs index 2a25b01df95..a224f57feb1 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::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode, UnsafeLayoutNode}; /// Every time we do another layout, the old bloom filters are invalid. This is /// detected by ticking a generation number every layout. @@ -130,7 +130,7 @@ pub trait PostorderDomTraversal { /// A bottom-up, parallelizable traversal. pub trait PostorderNodeMutTraversal { /// The operation to perform. Return true to continue or false to stop. - fn process<'a>(&'a mut self, node: &ThreadSafeLayoutNode<'a>) -> bool; + fn process<'a>(&'a mut self, node: &ServoThreadSafeLayoutNode<'a>) -> bool; } /// The recalc-style-for-node traversal, which styles each node and must run before @@ -162,7 +162,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 = ThreadSafeLayoutNode::new(&node); + let node = ServoThreadSafeLayoutNode::new(&node); node.unstyle(); } @@ -199,7 +199,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { }, None => { if node.has_changed() { - ThreadSafeLayoutNode::new(&node).set_restyle_damage( + ServoThreadSafeLayoutNode::new(&node).set_restyle_damage( incremental::rebuild_and_reflow()) } None @@ -222,7 +222,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> { } StyleSharingResult::StyleWasShared(index, damage) => { style_sharing_candidate_cache.touch(index); - ThreadSafeLayoutNode::new(&node).set_restyle_damage(damage); + ServoThreadSafeLayoutNode::new(&node).set_restyle_damage(damage); } } } @@ -252,7 +252,7 @@ impl<'a> PostorderDomTraversal for ConstructFlows<'a> { fn process(&self, node: ServoLayoutNode) { // Construct flows for this node. { - let tnode = ThreadSafeLayoutNode::new(&node); + let tnode = ServoThreadSafeLayoutNode::new(&node); // Always reconstruct if incremental layout is turned off. let nonincremental_layout = opts::get().nonincremental_layout; diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index f158dfb386d..5c1622c3295 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<Wrappers::Element>; + fn as_element(&self) -> Option<Self::ConcreteLayoutElement>; - fn as_document(&self) -> Option<Wrappers::Document>; + fn as_document(&self) -> Option<Self::ConcreteLayoutDocument>; 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<Option<LayoutDataWrapper>>; - fn parent_node(&self) -> Option<Wrappers::Node>; + fn parent_node(&self) -> Option<Self>; - fn first_child(&self) -> Option<Wrappers::Node>; + fn first_child(&self) -> Option<Self>; - fn last_child(&self) -> Option<Wrappers::Node>; + fn last_child(&self) -> Option<Self>; - fn prev_sibling(&self) -> Option<Wrappers::Node>; + fn prev_sibling(&self) -> Option<Self>; - fn next_sibling(&self) -> Option<Wrappers::Node>; + fn next_sibling(&self) -> Option<Self>; } -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 as_node(&self) -> Self::ConcreteLayoutNode; - fn root_node(&self) -> Option<Wrappers::Node>; + fn root_node(&self) -> Option<Self::ConcreteLayoutNode>; - fn drain_modified_elements(&self) -> Vec<(Wrappers::Element, ElementSnapshot)>; + fn drain_modified_elements(&self) -> Vec<(Self::ConcreteLayoutElement, ElementSnapshot)>; } -pub trait LayoutElement<'le, Wrappers> : Sized + Copy + Clone + ::selectors::Element - 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<PropertyDeclarationBlock>; @@ -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<Wrappers::Node>, +pub struct LayoutNodeChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> { + current: Option<ConcreteLayoutNode>, + // 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<Wrappers::Node> { +impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeChildrenIterator<'a, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'a> { + type Item = ConcreteLayoutNode; + fn next(&mut self) -> Option<ConcreteLayoutNode> { let node = self.current; self.current = node.and_then(|node| node.next_sibling()); node } } -pub struct LayoutNodeReverseChildrenIterator<'a, Wrappers: WrapperTypes<'a>> { - current: Option<Wrappers::Node>, +pub struct LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> { + current: Option<ConcreteLayoutNode>, + // 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<Wrappers::Node> { +impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'a> { + type Item = ConcreteLayoutNode; + fn next(&mut self) -> Option<ConcreteLayoutNode> { let node = self.current; self.current = node.and_then(|node| node.prev_sibling()); node } } -pub struct LayoutTreeIterator<'a, Wrappers: WrapperTypes<'a>> { - stack: Vec<Wrappers::Node>, +pub struct LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> { + stack: Vec<ConcreteLayoutNode>, + // 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<Wrappers::Node> { +impl<'a, ConcreteLayoutNode> Iterator for LayoutTreeIterator<'a, ConcreteLayoutNode> + where ConcreteLayoutNode: LayoutNode<'a> { + type Item = ConcreteLayoutNode; + fn next(&mut self) -> Option<ConcreteLayoutNode> { 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()) } @@ -782,35 +792,203 @@ impl<T> PseudoElementType<T> { /// A thread-safe version of `LayoutNode`, used during flow construction. This type of layout /// node does not allow any parents or siblings of nodes to be accessed, to avoid races. + +pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized { + type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<'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<NodeTypeId>; + + 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<display::T>; + + #[inline] + fn get_before_pseudo(&self) -> Option<Self>; + + #[inline] + fn get_after_pseudo(&self) -> Option<Self>; + + /// 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<Option<LayoutDataWrapper>>; + + /// 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<Option<LayoutDataWrapper>>; + + /// Returns the style results for the given node. If CSS selector matching + /// has not yet been performed, fails. + #[inline] + fn style(&self) -> Ref<Arc<ComputedValues>> { + 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<CharIndex>; + + /// 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>; + + /// 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> : ThreadSafeLayoutNode<'ln> { + unsafe fn dangerous_first_child(&self) -> Option<Self>; + unsafe fn dangerous_next_sibling(&self) -> Option<Self>; +} + +pub trait ThreadSafeLayoutElement<'le> { + type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'le>; + + #[inline] + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str>; +} + #[derive(Copy, Clone)] -pub struct ThreadSafeLayoutNode<'ln> { +pub struct ServoThreadSafeLayoutNode<'ln> { /// The wrapped node. node: ServoLayoutNode<'ln>, pseudo: PseudoElementType<display::T>, } -impl<'ln> ThreadSafeLayoutNode<'ln> { +impl<'ln> DangerousThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> { + unsafe fn dangerous_first_child(&self) -> Option<Self> { + self.get_jsmanaged().first_child_ref() + .map(|node| self.new_with_this_lifetime(&node)) + } + unsafe fn dangerous_next_sibling(&self) -> Option<Self> { + self.get_jsmanaged().next_sibling_ref() + .map(|node| self.new_with_this_lifetime(&node)) + } +} + +impl<'ln> ServoThreadSafeLayoutNode<'ln> { /// Creates a new layout node with the same lifetime as this layout node. - pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ThreadSafeLayoutNode<'ln> { - ThreadSafeLayoutNode { + pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ServoThreadSafeLayoutNode<'ln> { + ServoThreadSafeLayoutNode { node: self.node.new_with_this_lifetime(node), pseudo: PseudoElementType::Normal, } } - /// Creates a new `ThreadSafeLayoutNode` from the given `LayoutNode`. - pub fn new<'a>(node: &ServoLayoutNode<'a>) -> ThreadSafeLayoutNode<'a> { - ThreadSafeLayoutNode { + /// Creates a new `ServoThreadSafeLayoutNode` from the given `ServoLayoutNode`. + pub fn new<'a>(node: &ServoLayoutNode<'a>) -> ServoThreadSafeLayoutNode<'a> { + ServoThreadSafeLayoutNode { node: node.clone(), pseudo: PseudoElementType::Normal, } } - /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode` + /// Creates a new `ServoThreadSafeLayoutNode` for the same `LayoutNode` /// with a different pseudo-element type. - fn with_pseudo(&self, pseudo: PseudoElementType<display::T>) -> ThreadSafeLayoutNode<'ln> { - ThreadSafeLayoutNode { + fn with_pseudo(&self, pseudo: PseudoElementType<display::T>) -> ServoThreadSafeLayoutNode<'ln> { + ServoThreadSafeLayoutNode { node: self.node.clone(), pseudo: pseudo, } @@ -822,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<LayoutDataWrapper> { + unsafe { + self.node.borrow_layout_data_unchecked() + } + } +} + +impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> { + type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'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<NodeTypeId> { + fn type_id(&self) -> Option<NodeTypeId> { if self.pseudo != PseudoElementType::Normal { return None } @@ -837,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) -> ServoThreadSafeLayoutElement<'ln> { unsafe { let element = match self.get_jsmanaged().downcast() { Some(e) => e.unsafe_get(), @@ -860,19 +1044,17 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { }; // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on // implementations. - ThreadSafeLayoutElement { + ServoThreadSafeLayoutElement { element: &*element, } } } - #[inline] - pub fn get_pseudo_element_type(&self) -> PseudoElementType<display::T> { + fn get_pseudo_element_type(&self) -> PseudoElementType<display::T> { self.pseudo } - #[inline] - pub fn get_before_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> { + fn get_before_pseudo(&self) -> Option<ServoThreadSafeLayoutNode<'ln>> { 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| { @@ -880,8 +1062,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { }) } - #[inline] - pub fn get_after_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> { + fn get_after_pseudo(&self) -> Option<ServoThreadSafeLayoutNode<'ln>> { 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| { @@ -889,61 +1070,15 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { }) } - /// Borrows the layout data without checking. - #[inline(always)] - fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> { - 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<Option<LayoutDataWrapper>> { + fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> { 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<Option<LayoutDataWrapper>> { + fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> { 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<Arc<ComputedValues>> { - 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<Text> = match self.get_jsmanaged().downcast() { Some(text) => text, @@ -964,24 +1099,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!(), @@ -990,38 +1108,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; @@ -1058,8 +1145,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<CharIndex> { + fn insertion_point(&self) -> Option<CharIndex> { let this = unsafe { self.get_jsmanaged() }; @@ -1078,10 +1164,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<Url> { + fn image_url(&self) -> Option<Url> { unsafe { self.get_jsmanaged().downcast() .expect("not an image!") @@ -1089,16 +1172,14 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } - pub fn canvas_data(&self) -> Option<HTMLCanvasData> { + fn canvas_data(&self) -> Option<HTMLCanvasData> { 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::<HTMLIFrameElement>() @@ -1107,65 +1188,56 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { } } - pub fn get_colspan(&self) -> u32 { + fn get_colspan(&self) -> u32 { unsafe { self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan() } } } -pub struct ThreadSafeLayoutNodeChildrenIterator<'a> { - current_node: Option<ThreadSafeLayoutNode<'a>>, - parent_node: ThreadSafeLayoutNode<'a>, +pub struct ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode: ThreadSafeLayoutNode<'ln>> { + current_node: Option<ConcreteNode>, + 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<ThreadSafeLayoutNode> { - 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<ConcreteNode> = 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<ThreadSafeLayoutNode<'a>> { +impl<'ln, ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode> + where ConcreteNode: DangerousThreadSafeLayoutNode<'ln> { + type Item = ConcreteNode; + fn next(&mut self) -> Option<ConcreteNode> { 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(), } }, @@ -1181,13 +1253,14 @@ impl<'a> Iterator for ThreadSafeLayoutNodeChildrenIterator<'a> { /// A wrapper around elements that ensures layout can only ever access safe properties and cannot /// race on elements. -pub struct ThreadSafeLayoutElement<'le> { +pub struct ServoThreadSafeLayoutElement<'le> { element: &'le Element, } -impl<'le> ThreadSafeLayoutElement<'le> { - #[inline] - pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> { +impl<'le> ThreadSafeLayoutElement<'le> for ServoThreadSafeLayoutElement<'le> { + type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'le>; + + fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> { unsafe { self.element.get_attr_val_for_layout(namespace, name) } |