mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
layout_2020: Paint hoisted positioned fragments in tree order
Instead of painting hoisted position fragments in the order to which they are hoisted, paint them in tree order and properly incorporate them into the stacking context. We do this by creating a placeholder fragment in the original tree position of hoisted fragments. The ghost fragment contains an atomic id which links back to the hoisted fragment in the containing block. While building the stacking context, we keep track of containing blocks and their children. When encountering a placeholder fragment we look at the containing block's hoisted children in order to properly paint the hoisted fragment. One notable design modification in this change is that hoisted fragments no longer need an AnonymousFragment as their parent. Instead they are now direct children of the fragment that establishes their containing block.
This commit is contained in:
parent
e3c91f7c49
commit
c3b1c92ac1
41 changed files with 382 additions and 159 deletions
|
@ -6,8 +6,10 @@ use crate::context::LayoutContext;
|
|||
use crate::flow::float::FloatBox;
|
||||
use crate::flow::FlowLayout;
|
||||
use crate::formatting_contexts::IndependentFormattingContext;
|
||||
use crate::fragments::CollapsedBlockMargins;
|
||||
use crate::fragments::{AnonymousFragment, BoxFragment, DebugId, Fragment, TextFragment};
|
||||
use crate::fragments::{
|
||||
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
|
||||
DebugId, Fragment, TextFragment,
|
||||
};
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::positioned::{relative_adjustement, AbsolutelyPositionedBox, PositioningContext};
|
||||
use crate::sizing::ContentSizes;
|
||||
|
@ -254,8 +256,14 @@ impl InlineFormattingContext {
|
|||
panic!("display:none does not generate an abspos box")
|
||||
},
|
||||
};
|
||||
ifc.positioning_context
|
||||
.push(box_.to_hoisted(initial_start_corner, tree_rank));
|
||||
let hoisted_fragment = box_.to_hoisted(initial_start_corner, tree_rank);
|
||||
let hoisted_fragment_id = hoisted_fragment.fragment_id;
|
||||
ifc.positioning_context.push(hoisted_fragment);
|
||||
ifc.lines
|
||||
.fragments
|
||||
.push(Fragment::AbsoluteOrFixedPositioned(
|
||||
AbsoluteOrFixedPositionedFragment(hoisted_fragment_id),
|
||||
));
|
||||
},
|
||||
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
|
||||
// TODO
|
||||
|
@ -333,7 +341,7 @@ impl Lines {
|
|||
};
|
||||
if move_by > Length::zero() {
|
||||
for fragment in &mut line_contents {
|
||||
fragment.position_mut().inline += move_by;
|
||||
fragment.offset_inline(&move_by);
|
||||
}
|
||||
}
|
||||
let start_corner = Vec2 {
|
||||
|
@ -426,6 +434,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
|||
self.border.clone(),
|
||||
self.margin.clone(),
|
||||
CollapsedBlockMargins::zero(),
|
||||
None, // hoisted_fragment_id
|
||||
);
|
||||
let last_fragment = self.last_box_tree_fragment && !at_line_break;
|
||||
if last_fragment {
|
||||
|
@ -488,6 +497,7 @@ fn layout_atomic<'box_tree>(
|
|||
border,
|
||||
margin,
|
||||
CollapsedBlockMargins::zero(),
|
||||
None, // hoisted_fragment_id
|
||||
)
|
||||
},
|
||||
Err(non_replaced) => {
|
||||
|
@ -563,6 +573,7 @@ fn layout_atomic<'box_tree>(
|
|||
border,
|
||||
margin,
|
||||
CollapsedBlockMargins::zero(),
|
||||
None, // hoisted_fragment_id
|
||||
)
|
||||
},
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::context::LayoutContext;
|
|||
use crate::flow::float::{FloatBox, FloatContext};
|
||||
use crate::flow::inline::InlineFormattingContext;
|
||||
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC};
|
||||
use crate::fragments::{AnonymousFragment, BoxFragment};
|
||||
use crate::fragments::{AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment};
|
||||
use crate::fragments::{CollapsedBlockMargins, CollapsedMargin, Fragment};
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||
|
@ -176,14 +176,7 @@ fn layout_block_level_children<'a>(
|
|||
placement_state.current_margin.solve() + fragment_block_size;
|
||||
placement_state.current_margin = fragment_block_margins.end;
|
||||
},
|
||||
Fragment::Anonymous(fragment) => {
|
||||
// FIXME(nox): Margin collapsing for hypothetical boxes of
|
||||
// abspos elements is probably wrong.
|
||||
assert!(fragment.children.is_empty());
|
||||
assert_eq!(fragment.rect.size.block, Length::zero());
|
||||
fragment.rect.start_corner.block +=
|
||||
placement_state.current_block_direction_position;
|
||||
},
|
||||
Fragment::Anonymous(_) | Fragment::AbsoluteOrFixedPositioned(_) => {},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -321,9 +314,11 @@ impl BlockLevelBox {
|
|||
))
|
||||
},
|
||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
||||
positioning_context.push(box_.to_hoisted(Vec2::zero(), tree_rank));
|
||||
Fragment::Anonymous(AnonymousFragment::no_op(
|
||||
containing_block.style.writing_mode,
|
||||
let hoisted_fragment = box_.to_hoisted(Vec2::zero(), tree_rank);
|
||||
let hoisted_fragment_id = hoisted_fragment.fragment_id.clone();
|
||||
positioning_context.push(hoisted_fragment);
|
||||
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment(
|
||||
hoisted_fragment_id,
|
||||
))
|
||||
},
|
||||
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
|
||||
|
@ -505,6 +500,7 @@ fn layout_in_flow_non_replaced_block_level<'a>(
|
|||
border,
|
||||
margin,
|
||||
block_margins_collapsed_with_children,
|
||||
None, // hoisted_fragment_id
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -556,6 +552,7 @@ fn layout_in_flow_replaced_block_level<'a>(
|
|||
border,
|
||||
margin,
|
||||
block_margins_collapsed_with_children,
|
||||
None, // hoisted_fragment_id
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::context::LayoutContext;
|
||||
use crate::display_list::stacking_context::StackingContext;
|
||||
use crate::display_list::stacking_context::{
|
||||
ContainingBlock, ContainingBlockInfo, StackingContext, StackingContextBuildMode,
|
||||
StackingContextBuilder,
|
||||
};
|
||||
use crate::dom_traversal::{Contents, NodeExt};
|
||||
use crate::flow::construct::ContainsFloats;
|
||||
use crate::flow::float::FloatBox;
|
||||
|
@ -186,12 +189,26 @@ impl BoxTreeRoot {
|
|||
impl FragmentTreeRoot {
|
||||
pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
|
||||
let mut stacking_context = StackingContext::create_root();
|
||||
for fragment in &self.children {
|
||||
fragment.build_stacking_context_tree(
|
||||
builder,
|
||||
&self.initial_containing_block,
|
||||
&mut stacking_context,
|
||||
);
|
||||
{
|
||||
let mut stacking_context_builder = StackingContextBuilder::new(&mut builder.wr);
|
||||
let containing_block_info = ContainingBlockInfo {
|
||||
rect: self.initial_containing_block,
|
||||
nearest_containing_block: None,
|
||||
containing_block_for_all_descendants: ContainingBlock::new(
|
||||
&self.initial_containing_block,
|
||||
stacking_context_builder.current_space_and_clip,
|
||||
&self.children,
|
||||
),
|
||||
};
|
||||
|
||||
for fragment in &self.children {
|
||||
fragment.build_stacking_context_tree(
|
||||
&mut stacking_context_builder,
|
||||
&containing_block_info,
|
||||
&mut stacking_context,
|
||||
StackingContextBuildMode::SkipHoisted,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
stacking_context.sort();
|
||||
|
@ -268,6 +285,7 @@ impl FragmentTreeRoot {
|
|||
Fragment::Box(fragment) if fragment.tag == requested_node => fragment
|
||||
.border_rect()
|
||||
.to_physical(fragment.style.writing_mode, &containing_block),
|
||||
Fragment::AbsoluteOrFixedPositioned(_) => PhysicalRect::zero(),
|
||||
Fragment::Text(fragment) if fragment.tag == requested_node => fragment
|
||||
.rect
|
||||
.to_physical(fragment.parent_style.writing_mode, &containing_block),
|
||||
|
@ -301,6 +319,7 @@ impl FragmentTreeRoot {
|
|||
Fragment::Box(fragment) if fragment.tag == requested_node => {
|
||||
(&fragment.style, fragment.padding_rect())
|
||||
},
|
||||
Fragment::AbsoluteOrFixedPositioned(_) |
|
||||
Fragment::Box(_) |
|
||||
Fragment::Text(_) |
|
||||
Fragment::Image(_) |
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue