diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index 59b8d019236..b3ebd81d2b8 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -58,6 +58,8 @@ pub mod optimizer; /// items that involve a blur. This ensures that the display item boundaries include all the ink. pub static BLUR_INFLATION_FACTOR: i32 = 3; +const MIN_INDENTATION_LENGTH: usize = 4; + /// An opaque handle to a node. The only safe operation that can be performed on this node is to /// compare it to another opaque handle or to another node. /// @@ -172,20 +174,7 @@ impl DisplayList { } // Print the display list. Only makes sense to call it after performing reflow. - pub fn print_items(&self, mut indentation: String) { - let min_length = 4; - // We cover the case of an empty string. - if indentation.len() == 0 { - indentation = String::from_str("####"); - } - - // We grow the indentation by 4 characters if needed. - // I wish to push it all as a slice, but it won't work if the string is a single char. - while indentation.len() < min_length { - let c = indentation.char_at(0); - indentation.push(c); - } - + pub fn print_items(&self, indentation: String) { // Closures are so nice! let doit = |items: &Vec| { for item in items.iter() { @@ -221,8 +210,9 @@ impl DisplayList { println!("{} Children stacking contexts list length: {}", indentation, self.children.len()); - for sublist in self.children.iter() { - sublist.display_list.print_items(indentation.clone()+&indentation[0..min_length]); + for stacking_context in self.children.iter() { + stacking_context.print(indentation.clone() + + &indentation[0..MIN_INDENTATION_LENGTH]); } } } @@ -250,6 +240,7 @@ pub struct StackingContext { /// The position and size of this stacking context. pub bounds: Rect, + /// The overflow rect for this stacking context in its coordinate system. pub overflow: Rect, @@ -571,6 +562,27 @@ impl StackingContext { topmost_only, self.display_list.background_and_borders.iter().rev()) } + + pub fn print(&self, mut indentation: String) { + // We cover the case of an empty string. + if indentation.len() == 0 { + indentation = String::from_str("####"); + } + + // We grow the indentation by 4 characters if needed. + // I wish to push it all as a slice, but it won't work if the string is a single char. + while indentation.len() < MIN_INDENTATION_LENGTH { + let c = indentation.char_at(0); + indentation.push(c); + } + + println!("{:?} Stacking context at {:?} with overflow {:?}:", + indentation, + self.bounds, + self.overflow); + + self.display_list.print_items(indentation); + } } impl HeapSizeOf for StackingContext { diff --git a/components/layout/block.rs b/components/layout/block.rs index 490e94a0a68..895809f6dae 100644 --- a/components/layout/block.rs +++ b/components/layout/block.rs @@ -33,7 +33,7 @@ use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode}; use display_list_builder::{FragmentDisplayListBuilding}; use floats::{ClearType, FloatKind, Floats, PlacementInfo}; use flow::{self, AbsolutePositionInfo, BaseFlow, ForceNonfloatedFlag, FlowClass, Flow}; -use flow::{ImmutableFlowUtils, PreorderFlowTraversal}; +use flow::{ImmutableFlowUtils, MutableFlowUtils, OpaqueFlow, PreorderFlowTraversal}; use flow::{PostorderFlowTraversal, mut_base}; use flow::{BLOCK_POSITION_IS_STATIC, HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, INLINE_POSITION_IS_STATIC}; @@ -433,26 +433,31 @@ fn translate_including_floats(cur_b: &mut Au, delta: Au, floats: &mut Floats) { /// /// Note that flows with position 'fixed' just form a flat list as they all /// have the Root flow as their CB. -struct AbsoluteAssignBSizesTraversal<'a>(&'a LayoutContext<'a>); +pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a LayoutContext<'a>); impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> { #[inline] fn process(&self, flow: &mut Flow) { - let block_flow = flow.as_block(); - - // The root of the absolute flow tree is definitely not absolutely - // positioned. Nothing to process here. - if block_flow.is_root_of_absolute_flow_tree() { - return; + { + // The root of the absolute flow tree is definitely not absolutely + // positioned. Nothing to process here. + let flow: &Flow = flow; + if flow.contains_roots_of_absolute_flow_tree() { + return; + } + if !flow.is_block_like() { + return + } } - assert!(block_flow.base.flags.contains(IS_ABSOLUTELY_POSITIONED)); - if !block_flow.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) { + let block = flow.as_block(); + debug_assert!(block.base.flags.contains(IS_ABSOLUTELY_POSITIONED)); + if !block.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) { return } let AbsoluteAssignBSizesTraversal(ref layout_context) = *self; - block_flow.calculate_absolute_block_size_and_margins(*layout_context); + block.calculate_absolute_block_size_and_margins(*layout_context); } } @@ -462,16 +467,19 @@ impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> { /// not including the root of the Absolute flow tree. /// After that, it is up to the normal store-overflow traversal to propagate /// it further up. -struct AbsoluteStoreOverflowTraversal<'a>{ - layout_context: &'a LayoutContext<'a>, +pub struct AbsoluteStoreOverflowTraversal<'a>{ + pub layout_context: &'a LayoutContext<'a>, } impl<'a> PostorderFlowTraversal for AbsoluteStoreOverflowTraversal<'a> { #[inline] fn process(&self, flow: &mut Flow) { - // This will be taken care of by the normal store-overflow traversal. - if flow.is_root_of_absolute_flow_tree() { - return; + { + // This will be taken care of by the normal store-overflow traversal. + let flow: &Flow = flow; + if flow.contains_roots_of_absolute_flow_tree() { + return; + } } flow.store_overflow(self.layout_context); @@ -656,56 +664,23 @@ impl BlockFlow { &mut self.fragment } - /// Return the size of the Containing Block for this flow. + /// Return the size of the containing block for the given immediate absolute descendant of this + /// flow. /// - /// Right now, this only gets the Containing Block size for absolutely - /// positioned elements. - /// Note: Assume this is called in a top-down traversal, so it is ok to - /// reference the CB. + /// Right now, this only gets the containing block size for absolutely positioned elements. + /// Note: We assume this is called in a top-down traversal, so it is ok to reference the CB. #[inline] - pub fn containing_block_size(&mut self, viewport_size: Size2D) -> LogicalSize { + pub fn containing_block_size(&mut self, viewport_size: &Size2D, descendant: OpaqueFlow) + -> LogicalSize { debug_assert!(self.base.flags.contains(IS_ABSOLUTELY_POSITIONED)); if self.is_fixed() { // Initial containing block is the CB for the root - LogicalSize::from_physical(self.base.writing_mode, viewport_size) + LogicalSize::from_physical(self.base.writing_mode, *viewport_size) } else { - self.base.absolute_cb.generated_containing_block_rect().size + self.base.absolute_cb.generated_containing_block_size(descendant) } } - /// Traverse the Absolute flow tree in preorder. - /// - /// Traverse all your direct absolute descendants, who will then traverse - /// their direct absolute descendants. - /// - /// Return true if the traversal is to continue or false to stop. - fn traverse_preorder_absolute_flows(&mut self, traversal: &mut T) - where T: PreorderFlowTraversal { - let flow = self as &mut Flow; - - traversal.process(flow); - - let descendant_offset_iter = mut_base(flow).abs_descendants.iter(); - for ref mut descendant_link in descendant_offset_iter { - descendant_link.as_block().traverse_preorder_absolute_flows(traversal) - } - } - - /// Traverse the Absolute flow tree in postorder. - /// - /// Return true if the traversal is to continue or false to stop. - fn traverse_postorder_absolute_flows(&mut self, traversal: &mut T) - where T: PostorderFlowTraversal { - let flow = self as &mut Flow; - - for descendant_link in mut_base(flow).abs_descendants.iter() { - let block = descendant_link.as_block(); - block.traverse_postorder_absolute_flows(traversal); - } - - traversal.process(flow) - } - /// Return true if this has a replaced fragment. /// /// Text, Images, Inline Block and @@ -1006,16 +981,17 @@ impl BlockFlow { } } - if self.is_root_of_absolute_flow_tree() { + if (&*self as &Flow).contains_roots_of_absolute_flow_tree() { // Assign block-sizes for all flows in this absolute flow tree. // This is preorder because the block-size of an absolute flow may depend on // the block-size of its containing block, which may also be an absolute flow. - self.traverse_preorder_absolute_flows(&mut AbsoluteAssignBSizesTraversal( - layout_context)); + (&mut *self as &mut Flow).traverse_preorder_absolute_flows( + &mut AbsoluteAssignBSizesTraversal(layout_context)); // Store overflow for all absolute descendants. - self.traverse_postorder_absolute_flows(&mut AbsoluteStoreOverflowTraversal { - layout_context: layout_context, - }); + (&mut *self as &mut Flow).traverse_postorder_absolute_flows( + &mut AbsoluteStoreOverflowTraversal { + layout_context: layout_context, + }); } // Don't remove the dirty bits yet if we're absolutely-positioned, since our final size @@ -1086,8 +1062,10 @@ impl BlockFlow { /// + block-size for the flow /// + position in the block direction of the flow with respect to its Containing Block. /// + block-size, vertical margins, and y-coordinate for the flow's box. - fn calculate_absolute_block_size_and_margins(&mut self, ctx: &LayoutContext) { - let containing_block_block_size = self.containing_block_size(ctx.shared.screen_size).block; + fn calculate_absolute_block_size_and_margins(&mut self, layout_context: &LayoutContext) { + let opaque_self = OpaqueFlow::from_flow(self); + let containing_block_block_size = + self.containing_block_size(&layout_context.shared.screen_size, opaque_self).block; // This is the stored content block-size value from assign-block-size let content_block_size = self.fragment.border_box.size.block; @@ -1250,8 +1228,9 @@ impl BlockFlow { }; // Calculate containing block inline size. + let opaque_self = OpaqueFlow::from_flow(self); let containing_block_size = if flags.contains(IS_ABSOLUTELY_POSITIONED) { - self.containing_block_size(layout_context.shared.screen_size).inline + self.containing_block_size(&layout_context.shared.screen_size, opaque_self).inline } else { content_inline_size }; @@ -1724,13 +1703,15 @@ impl Flow for BlockFlow { self.fragment.relative_position(&self.base .absolute_position_info .relative_containing_block_size); - if self.is_positioned() { + if self.contains_positioned_fragments() { + let border_box_origin = (self.fragment.border_box - + self.fragment.style.logical_border_width()).start; self.base .absolute_position_info .stacking_relative_position_of_absolute_containing_block = self.base.stacking_relative_position + - (self.generated_containing_block_rect().start + - relative_offset).to_physical(self.base.writing_mode, container_size) + (border_box_origin + relative_offset).to_physical(self.base.writing_mode, + container_size) } // Compute absolute position info for children. @@ -1741,7 +1722,7 @@ impl Flow for BlockFlow { logical_border_width.inline_start, logical_border_width.block_start); let position = position.to_physical(self.base.writing_mode, container_size); - if self.is_positioned() { + if self.contains_positioned_fragments() { position } else { // We establish a stacking context but are not positioned. (This will happen @@ -1850,17 +1831,10 @@ impl Flow for BlockFlow { self.fragment.style.get_box().position } - /// Return true if this is the root of an Absolute flow tree. - /// - /// It has to be either relatively positioned or the Root flow. - fn is_root_of_absolute_flow_tree(&self) -> bool { - self.is_relatively_positioned() || self.is_root() - } - /// Return the dimensions of the containing block generated by this flow for absolutely- /// positioned descendants. For block flows, this is the padding box. - fn generated_containing_block_rect(&self) -> LogicalRect { - self.fragment.border_box - self.fragment.style().logical_border_width() + fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize { + (self.fragment.border_box - self.fragment.style().logical_border_width()).size } fn layer_id(&self, fragment_index: u32) -> LayerId { @@ -1871,7 +1845,7 @@ impl Flow for BlockFlow { } fn is_absolute_containing_block(&self) -> bool { - self.is_positioned() + self.contains_positioned_fragments() } fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { @@ -2491,7 +2465,8 @@ impl ISizeAndMarginsComputer for AbsoluteNonReplaced { _: Au, layout_context: &LayoutContext) -> Au { - block.containing_block_size(layout_context.shared.screen_size).inline + let opaque_block = OpaqueFlow::from_flow(block); + block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline } fn set_inline_position_of_flow_if_necessary(&self, @@ -2601,8 +2576,9 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced { _: Au, layout_context: &LayoutContext) -> MaybeAuto { + let opaque_block = OpaqueFlow::from_flow(block); let containing_block_inline_size = - block.containing_block_size(layout_context.shared.screen_size).inline; + block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline; let fragment = block.fragment(); fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size); // For replaced absolute flow, the rest of the constraint solving will @@ -2610,9 +2586,13 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced { MaybeAuto::Specified(fragment.content_inline_size()) } - fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext) + fn containing_block_inline_size(&self, + block: &mut BlockFlow, + _: Au, + layout_context: &LayoutContext) -> Au { - block.containing_block_size(ctx.shared.screen_size).inline + let opaque_block = OpaqueFlow::from_flow(block); + block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline } fn set_inline_position_of_flow_if_necessary(&self, diff --git a/components/layout/construct.rs b/components/layout/construct.rs index 0acd923de89..95d07afec6f 100644 --- a/components/layout/construct.rs +++ b/components/layout/construct.rs @@ -24,12 +24,9 @@ use flow::{IS_ABSOLUTELY_POSITIONED}; use flow; use flow_ref::FlowRef; use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo}; -use fragment::CanvasFragmentInfo; -use fragment::ImageFragmentInfo; -use fragment::InlineAbsoluteHypotheticalFragmentInfo; -use fragment::TableColumnFragmentInfo; -use fragment::UnscannedTextFragmentInfo; -use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo}; +use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo}; +use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo}; +use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo}; use incremental::{RECONSTRUCT_FLOW, RestyleDamage}; use inline::{InlineFlow, InlineFragmentNodeInfo}; use list_item::{ListItemFlow, ListStyleTypeContent}; @@ -121,7 +118,7 @@ pub struct InlineFragmentsConstructionResult { pub splits: LinkedList, /// Any fragments that succeed the {ib} splits. - pub fragments: LinkedList, + pub fragments: IntermediateInlineFragments, /// Any absolute descendants that we're bubbling up. pub abs_descendants: AbsDescendants, @@ -156,16 +153,44 @@ pub struct InlineFragmentsConstructionResult { #[derive(Clone)] pub struct InlineBlockSplit { /// The inline fragments that precede the flow. - pub predecessors: LinkedList, + pub predecessors: IntermediateInlineFragments, /// The flow that caused this {ib} split. pub flow: FlowRef, } +/// Holds inline fragments and absolute descendants. +#[derive(Clone)] +pub struct IntermediateInlineFragments { + /// The list of fragments. + pub fragments: LinkedList, + + /// The list of absolute descendants of those inline fragments. + pub absolute_descendants: AbsDescendants, +} + +impl IntermediateInlineFragments { + fn new() -> IntermediateInlineFragments { + IntermediateInlineFragments { + fragments: LinkedList::new(), + absolute_descendants: Descendants::new(), + } + } + + fn is_empty(&self) -> bool { + self.fragments.is_empty() && self.absolute_descendants.is_empty() + } + + fn push_all(&mut self, mut other: IntermediateInlineFragments) { + self.fragments.append(&mut other.fragments); + self.absolute_descendants.push_descendants(other.absolute_descendants); + } +} + /// Holds inline fragments that we're gathering for children of an inline node. struct InlineFragmentsAccumulator { /// The list of fragments. - fragments: LinkedList, + fragments: IntermediateInlineFragments, /// Whether we've created a range to enclose all the fragments. This will be Some() if the /// outer node is an inline and None otherwise. @@ -175,37 +200,38 @@ struct InlineFragmentsAccumulator { impl InlineFragmentsAccumulator { fn new() -> InlineFragmentsAccumulator { InlineFragmentsAccumulator { - fragments: LinkedList::new(), + fragments: IntermediateInlineFragments::new(), enclosing_node: None, } } fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator { - let fragments = LinkedList::new(); InlineFragmentsAccumulator { - fragments: fragments, + fragments: IntermediateInlineFragments::new(), enclosing_node: Some(InlineFragmentNodeInfo { - address: OpaqueNodeMethods::from_thread_safe_layout_node(node), - style: node.style().clone() }), + address: OpaqueNodeMethods::from_thread_safe_layout_node(node), + style: node.style().clone(), + }), } } - fn push_all(&mut self, mut fragments: LinkedList) { - if fragments.len() == 0 { - return - } - - self.fragments.append(&mut fragments) + fn push(&mut self, fragment: Fragment) { + self.fragments.fragments.push_back(fragment) } - fn to_dlist(self) -> LinkedList { + fn push_all(&mut self, mut fragments: IntermediateInlineFragments) { + self.fragments.fragments.append(&mut fragments.fragments); + self.fragments.absolute_descendants.push_descendants(fragments.absolute_descendants); + } + + fn to_intermediate_inline_fragments(self) -> IntermediateInlineFragments { let InlineFragmentsAccumulator { mut fragments, enclosing_node, } = self; if let Some(enclosing_node) = enclosing_node { - let frag_len = fragments.len(); - for (idx, frag) in fragments.iter_mut().enumerate() { + let frag_len = fragments.fragments.len(); + for (idx, frag) in fragments.fragments.iter_mut().enumerate() { // frag is first inline fragment in the inline node let is_first = idx == 0; @@ -355,7 +381,7 @@ impl<'a> FlowConstructor<'a> { flow_list: &mut Vec, whitespace_stripping: WhitespaceStrippingMode, node: &ThreadSafeLayoutNode) { - let mut fragments = fragment_accumulator.to_dlist(); + let mut fragments = fragment_accumulator.to_intermediate_inline_fragments(); if fragments.is_empty() { return }; @@ -363,13 +389,13 @@ impl<'a> FlowConstructor<'a> { match whitespace_stripping { WhitespaceStrippingMode::None => {} WhitespaceStrippingMode::FromStart => { - strip_ignorable_whitespace_from_start(&mut fragments); + strip_ignorable_whitespace_from_start(&mut fragments.fragments); if fragments.is_empty() { return }; } WhitespaceStrippingMode::FromEnd => { - strip_ignorable_whitespace_from_end(&mut fragments); + strip_ignorable_whitespace_from_end(&mut fragments.fragments); if fragments.is_empty() { return }; @@ -378,7 +404,7 @@ impl<'a> FlowConstructor<'a> { // Build a list of all the inline-block fragments before fragments is moved. let mut inline_block_flows = vec!(); - for fragment in fragments.iter() { + for fragment in fragments.fragments.iter() { match fragment.specific { SpecificFragmentInfo::InlineBlock(ref info) => { inline_block_flows.push(info.flow_ref.clone()) @@ -386,6 +412,9 @@ impl<'a> FlowConstructor<'a> { SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => { inline_block_flows.push(info.flow_ref.clone()) } + SpecificFragmentInfo::InlineAbsolute(ref info) => { + inline_block_flows.push(info.flow_ref.clone()) + } _ => {} } } @@ -393,16 +422,25 @@ impl<'a> FlowConstructor<'a> { // We must scan for runs before computing minimum ascent and descent because scanning // for runs might collapse so much whitespace away that only hypothetical fragments // remain. In that case the inline flow will compute its ascent and descent to be zero. - let fragments = TextRunScanner::new().scan_for_runs(self.layout_context.font_context(), - fragments); + let scanned_fragments = + TextRunScanner::new().scan_for_runs(self.layout_context.font_context(), + fragments.fragments); let mut inline_flow_ref = - FlowRef::new(box InlineFlow::from_fragments(fragments, node.style().writing_mode)); + FlowRef::new(box InlineFlow::from_fragments(scanned_fragments, + node.style().writing_mode)); // Add all the inline-block fragments as children of the inline flow. for inline_block_flow in inline_block_flows.iter() { inline_flow_ref.add_new_child(inline_block_flow.clone()); } + // Set up absolute descendants as necessary. + let contains_positioned_fragments = inline_flow_ref.contains_positioned_fragments(); + if contains_positioned_fragments { + // This is the containing block for all the absolute descendants. + inline_flow_ref.set_absolute_descendants(fragments.absolute_descendants); + } + { let inline_flow = inline_flow_ref.as_inline(); @@ -447,7 +485,7 @@ impl<'a> FlowConstructor<'a> { // Flush any inline fragments that we were gathering up. This allows us to // handle {ib} splits. debug!("flushing {} inline box(es) to flow A", - inline_fragment_accumulator.fragments.len()); + inline_fragment_accumulator.fragments.fragments.len()); self.flush_inline_fragments_to_flow_or_list( mem::replace(inline_fragment_accumulator, InlineFragmentsAccumulator::new()), @@ -491,7 +529,7 @@ impl<'a> FlowConstructor<'a> { // Flush any inline fragments that we were gathering up. debug!("flushing {} inline box(es) to flow A", - inline_fragment_accumulator.fragments.len()); + inline_fragment_accumulator.fragments.fragments.len()); self.flush_inline_fragments_to_flow_or_list( mem::replace(inline_fragment_accumulator, InlineFragmentsAccumulator::new()), @@ -526,7 +564,7 @@ impl<'a> FlowConstructor<'a> { whitespace_style, whitespace_damage, fragment_info); - inline_fragment_accumulator.fragments.push_back(fragment); + inline_fragment_accumulator.fragments.fragments.push_back(fragment); } ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => { // TODO: Implement anonymous table objects for missing parents @@ -538,16 +576,17 @@ impl<'a> FlowConstructor<'a> { /// Constructs a block flow, beginning with the given `initial_fragments` if present and then /// appending the construction results of children to the child list of the block flow. {ib} /// splits and absolutely-positioned descendants are handled correctly. - fn build_flow_for_block_starting_with_fragments(&mut self, - mut flow: FlowRef, - node: &ThreadSafeLayoutNode, - mut initial_fragments: LinkedList) - -> ConstructionResult { + fn build_flow_for_block_starting_with_fragments( + &mut self, + mut flow: FlowRef, + node: &ThreadSafeLayoutNode, + initial_fragments: IntermediateInlineFragments) + -> ConstructionResult { // Gather up fragments for the inline flows we might need to create. let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new(); let mut consecutive_siblings = vec!(); - inline_fragment_accumulator.fragments.append(&mut initial_fragments); + inline_fragment_accumulator.fragments.push_all(initial_fragments); let mut first_fragment = inline_fragment_accumulator.fragments.is_empty(); // List of absolute descendants, in tree order. @@ -582,9 +621,9 @@ impl<'a> FlowConstructor<'a> { flow.finish(); // Set up the absolute descendants. - let is_positioned = flow.as_block().is_positioned(); + let contains_positioned_fragments = flow.contains_positioned_fragments(); let is_absolutely_positioned = flow::base(&*flow).flags.contains(IS_ABSOLUTELY_POSITIONED); - if is_positioned { + if contains_positioned_fragments { // This is the containing block for all the absolute descendants. flow.set_absolute_descendants(abs_descendants); @@ -611,7 +650,7 @@ impl<'a> FlowConstructor<'a> { /// `