aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/layout/construct.rs57
-rw-r--r--components/layout/fragment.rs7
-rw-r--r--components/layout/wrapper.rs10
-rw-r--r--tests/ref/after_block_iteration.html19
-rw-r--r--tests/ref/after_block_iteration_ref.html11
-rw-r--r--tests/ref/basic.list1
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