diff options
-rw-r--r-- | components/layout/construct.rs | 57 | ||||
-rw-r--r-- | components/layout/fragment.rs | 7 | ||||
-rw-r--r-- | components/layout/wrapper.rs | 10 | ||||
-rw-r--r-- | tests/ref/after_block_iteration.html | 19 | ||||
-rw-r--r-- | tests/ref/after_block_iteration_ref.html | 11 | ||||
-rw-r--r-- | tests/ref/basic.list | 1 |
6 files changed, 86 insertions, 19 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs index f730a08bf85..0cf5adf3254 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -212,14 +212,24 @@ impl<'a> FlowConstructor<'a> { Some(url) => { // FIXME(pcwalton): The fact that image fragments store the cache within them makes // little sense to me. - ImageFragment(ImageFragmentInfo::new(node, url, self.layout_context.shared.image_cache.clone())) + ImageFragment(ImageFragmentInfo::new(node, + url, + self.layout_context + .shared + .image_cache + .clone())) } } } /// Builds specific `Fragment` info for the given node. + /// + /// This does *not* construct the text for generated content (but, for generated content with + /// `display: block`, it does construct the generic fragment corresponding to the block). + /// Construction of the text fragment is done specially by `build_flow_using_children()` and + /// `build_fragments_for_replaced_inline_content()`. pub fn build_specific_fragment_info_for_node(&mut self, node: &ThreadSafeLayoutNode) - -> SpecificFragmentInfo { + -> SpecificFragmentInfo { match node.type_id() { Some(ElementNodeTypeId(HTMLImageElementTypeId)) => { self.build_fragment_info_for_image(node, node.image_url()) @@ -239,8 +249,11 @@ impl<'a> FlowConstructor<'a> { Some(ElementNodeTypeId(HTMLTableHeaderCellElementTypeId)) => TableCellFragment, Some(ElementNodeTypeId(HTMLTableRowElementTypeId)) | Some(ElementNodeTypeId(HTMLTableSectionElementTypeId)) => TableRowFragment, - None | Some(TextNodeTypeId) => UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)), - _ => GenericFragment, + Some(TextNodeTypeId) => UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)), + _ => { + // This includes pseudo-elements. + GenericFragment + } } } @@ -431,6 +444,15 @@ impl<'a> FlowConstructor<'a> { let mut consecutive_siblings = vec!(); let mut first_fragment = true; + // Special case: If this is generated content, then we need to initialize the accumulator + // with the fragment corresponding to that content. + if node.get_pseudo_element_type() != Normal { + let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)); + let mut fragment = Fragment::new_from_specific_info(node, fragment_info); + inline_fragment_accumulator.fragments.push(&mut fragment, node.style().clone()); + first_fragment = false; + } + // List of absolute descendants, in tree order. let mut abs_descendants = Descendants::new(); for kid in node.children() { @@ -587,8 +609,9 @@ 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`. + /// 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) -> ConstructionResult { for kid in node.children() { @@ -605,8 +628,18 @@ impl<'a> FlowConstructor<'a> { node.style().clone())) } + // If this is generated content, then we need to initialize the accumulator with the + // fragment corresponding to that content. Otherwise, just initialize with the ordinary + // fragment that needs to be generated for this inline node. + let mut fragment = if node.get_pseudo_element_type() != Normal { + let fragment_info = UnscannedTextFragment(UnscannedTextFragmentInfo::new(node)); + Fragment::new_from_specific_info(node, fragment_info) + } else { + Fragment::new(self, node) + }; + let mut fragments = InlineFragments::new(); - fragments.push(&mut Fragment::new(self, node), node.style().clone()); + fragments.push(&mut fragment, node.style().clone()); let construction_item = InlineFragmentsConstructionItem(InlineFragmentsConstructionResult { splits: Vec::new(), @@ -853,17 +886,17 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> { // // TODO: This should actually consult the table in that section to get the // final computed value for 'display'. - // - // `#[inline(always)]` because this is always called from the traversal function and for some - // reason LLVM's inlining heuristics go awry here. - #[inline(always)] fn process(&mut self, node: &ThreadSafeLayoutNode) -> bool { // Get the `display` property for this node, and determine whether this node is floated. let (display, float, positioning) = match node.type_id() { None => { // Pseudo-element. let style = node.style(); - (display::inline, style.get_box().float, style.get_box().position) + let display = match node.get_pseudo_element_type() { + Normal | Before | After => display::inline, + BeforeBlock | AfterBlock => display::block, + }; + (display, style.get_box().float, style.get_box().position) } Some(ElementNodeTypeId(_)) => { let style = node.style(); diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs index 841ed1f6b1c..0335fab7f5a 100644 --- a/components/layout/fragment.rs +++ b/components/layout/fragment.rs @@ -351,10 +351,12 @@ impl TableColumnFragmentInfo { impl Fragment { /// Constructs a new `Fragment` instance for the given node. /// + /// This does *not* construct the text for generated content. See comments in + /// `FlowConstructor::build_specific_fragment_info_for_node()` for more details. + /// /// Arguments: /// /// * `constructor`: The flow constructor. - /// /// * `node`: The node to create a fragment for. pub fn new(constructor: &mut FlowConstructor, node: &ThreadSafeLayoutNode) -> Fragment { let style = node.style().clone(); @@ -373,7 +375,8 @@ impl Fragment { } /// Constructs a new `Fragment` instance from a specific info. - pub fn new_from_specific_info(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment { + pub fn new_from_specific_info(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo) + -> Fragment { let style = node.style().clone(); let writing_mode = style.writing_mode; Fragment { diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index c27cfe924d8..8b360452122 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -495,7 +495,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { /// Returns `None` if this is a pseudo-element. fn type_id(&self) -> Option<NodeTypeId> { - if self.pseudo == Before || self.pseudo == After { + if self.pseudo != Normal { return None } @@ -511,7 +511,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { } fn first_child(&self) -> Option<ThreadSafeLayoutNode<'ln>> { - if self.pseudo == Before || self.pseudo == After { + if self.pseudo != Normal { return None } @@ -531,11 +531,11 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { } fn text(&self) -> String { - if self.pseudo == Before || self.pseudo == After { + if self.pseudo != Normal { let layout_data_ref = self.borrow_layout_data(); let node_layout_data_wrapper = layout_data_ref.get_ref(); - if self.pseudo == Before { + if self.pseudo == Before || self.pseudo == BeforeBlock { let before_style = node_layout_data_wrapper.data.before_style.get_ref(); return get_content(&before_style.get_box().content) } else { @@ -748,7 +748,7 @@ impl<'a> Iterator<ThreadSafeLayoutNode<'a>> for ThreadSafeLayoutNodeChildrenIter let pseudo_after_node = if parent_node.is_block(After) && parent_node.pseudo == Normal { let pseudo_after_node = parent_node.with_pseudo(AfterBlock); Some(pseudo_after_node) - } else if parent_node.pseudo == Normal || parent_node.pseudo == AfterBlock { + } else if parent_node.pseudo == Normal { let pseudo_after_node = parent_node.with_pseudo(After); Some(pseudo_after_node) } else { diff --git a/tests/ref/after_block_iteration.html b/tests/ref/after_block_iteration.html new file mode 100644 index 00000000000..12c67f80b1f --- /dev/null +++ b/tests/ref/after_block_iteration.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<!-- + Although this test may seem (and is) trivial, it ensures that iteration with generated content + with `display: block` is correct during flow construction. Before this commit, this could hang + when combined with incremental reflow, since the parallel traversal counters would become + corrupted. +--> +<title>ack</title> +<style> +div.after-portlet-lang:after { + display: block; +} +</style> +<body> + <div class='after-portlet-lang'><div>x</div></div> +</body> +</html> diff --git a/tests/ref/after_block_iteration_ref.html b/tests/ref/after_block_iteration_ref.html new file mode 100644 index 00000000000..e85c4b7cd02 --- /dev/null +++ b/tests/ref/after_block_iteration_ref.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<head> +<title>ack</title> +<style> +</style> +<body> + <div>x</div> +</body> +</html> + diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 7f5a9ee7fa6..5b61597f035 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -134,3 +134,4 @@ flaky_gpu,flaky_linux == acid2_noscroll.html acid2_ref_broken.html == inline_block_with_margin_a.html inline_block_with_margin_ref.html == table_padding_a.html table_padding_ref.html == img_block_display_a.html img_block_display_ref.html +== after_block_iteration.html after_block_iteration_ref.html |