mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
layout_2020: Add support for hoisting positioned fragments in inline boxes
Add support for tracking containing blocks when doing inline layout. This requires setting up a PositioningContext for inline boxes when necessary. Instead of using the PositioningContext helper methods and we reuse the contexts between line breaks. Fixes #25279.
This commit is contained in:
parent
b945de4ea9
commit
bd06227a60
8 changed files with 59 additions and 24 deletions
|
@ -12,7 +12,10 @@ use crate::fragments::{
|
||||||
DebugId, Fragment, TextFragment,
|
DebugId, Fragment, TextFragment,
|
||||||
};
|
};
|
||||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||||
use crate::positioned::{relative_adjustement, AbsolutelyPositionedBox, PositioningContext};
|
use crate::positioned::{
|
||||||
|
relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox,
|
||||||
|
PositioningContext,
|
||||||
|
};
|
||||||
use crate::sizing::ContentSizes;
|
use crate::sizing::ContentSizes;
|
||||||
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
|
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
|
||||||
use crate::ContainingBlock;
|
use crate::ContainingBlock;
|
||||||
|
@ -64,6 +67,7 @@ struct InlineNestingLevelState<'box_tree> {
|
||||||
fragments_so_far: Vec<Fragment>,
|
fragments_so_far: Vec<Fragment>,
|
||||||
inline_start: Length,
|
inline_start: Length,
|
||||||
max_block_size_of_fragments_so_far: Length,
|
max_block_size_of_fragments_so_far: Length,
|
||||||
|
positioning_context: Option<PositioningContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PartialInlineBoxFragment<'box_tree> {
|
struct PartialInlineBoxFragment<'box_tree> {
|
||||||
|
@ -86,6 +90,31 @@ struct InlineFormattingContextState<'box_tree, 'a, 'b> {
|
||||||
current_nesting_level: InlineNestingLevelState<'box_tree>,
|
current_nesting_level: InlineNestingLevelState<'box_tree>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'box_tree, 'a, 'b> InlineFormattingContextState<'box_tree, 'a, 'b> {
|
||||||
|
fn push_hoisted_box_to_positioning_context(
|
||||||
|
&mut self,
|
||||||
|
hoisted_box: HoistedAbsolutelyPositionedBox,
|
||||||
|
) {
|
||||||
|
if let Some(context) = self.current_nesting_level.positioning_context.as_mut() {
|
||||||
|
context.push(hoisted_box);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for nesting_level in self.partial_inline_boxes_stack.iter_mut().rev() {
|
||||||
|
if let Some(context) = nesting_level
|
||||||
|
.parent_nesting_level
|
||||||
|
.positioning_context
|
||||||
|
.as_mut()
|
||||||
|
{
|
||||||
|
context.push(hoisted_box);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.positioning_context.push(hoisted_box);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Lines {
|
struct Lines {
|
||||||
// One anonymous fragment per line
|
// One anonymous fragment per line
|
||||||
fragments: Vec<Fragment>,
|
fragments: Vec<Fragment>,
|
||||||
|
@ -226,6 +255,7 @@ impl InlineFormattingContext {
|
||||||
fragments_so_far: Vec::with_capacity(self.inline_level_boxes.len()),
|
fragments_so_far: Vec::with_capacity(self.inline_level_boxes.len()),
|
||||||
inline_start: Length::zero(),
|
inline_start: Length::zero(),
|
||||||
max_block_size_of_fragments_so_far: Length::zero(),
|
max_block_size_of_fragments_so_far: Length::zero(),
|
||||||
|
positioning_context: None,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
|
@ -257,15 +287,14 @@ impl InlineFormattingContext {
|
||||||
panic!("display:none does not generate an abspos box")
|
panic!("display:none does not generate an abspos box")
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let hoisted_fragment =
|
let hoisted_box = box_.clone().to_hoisted(initial_start_corner, tree_rank);
|
||||||
box_.clone().to_hoisted(initial_start_corner, tree_rank);
|
let hoisted_fragment_id = hoisted_box.fragment_id;
|
||||||
let hoisted_fragment_id = hoisted_fragment.fragment_id;
|
ifc.push_hoisted_box_to_positioning_context(hoisted_box);
|
||||||
ifc.positioning_context.push(hoisted_fragment);
|
ifc.current_nesting_level.fragments_so_far.push(
|
||||||
ifc.lines
|
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment(
|
||||||
.fragments
|
hoisted_fragment_id,
|
||||||
.push(Fragment::AbsoluteOrFixedPositioned(
|
)),
|
||||||
AbsoluteOrFixedPositionedFragment(hoisted_fragment_id),
|
);
|
||||||
));
|
|
||||||
},
|
},
|
||||||
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
|
InlineLevelBox::OutOfFlowFloatBox(_box_) => {
|
||||||
// TODO
|
// TODO
|
||||||
|
@ -275,6 +304,7 @@ impl InlineFormattingContext {
|
||||||
// Reached the end of ifc.remaining_boxes
|
// Reached the end of ifc.remaining_boxes
|
||||||
if let Some(mut partial) = ifc.partial_inline_boxes_stack.pop() {
|
if let Some(mut partial) = ifc.partial_inline_boxes_stack.pop() {
|
||||||
partial.finish_layout(
|
partial.finish_layout(
|
||||||
|
layout_context,
|
||||||
&mut ifc.current_nesting_level,
|
&mut ifc.current_nesting_level,
|
||||||
&mut ifc.inline_position,
|
&mut ifc.inline_position,
|
||||||
false,
|
false,
|
||||||
|
@ -392,6 +422,7 @@ impl InlineBox {
|
||||||
if style.clone_position().is_relative() {
|
if style.clone_position().is_relative() {
|
||||||
start_corner += &relative_adjustement(&style, ifc.containing_block)
|
start_corner += &relative_adjustement(&style, ifc.containing_block)
|
||||||
}
|
}
|
||||||
|
let positioning_context = PositioningContext::new_for_style(&style);
|
||||||
PartialInlineBoxFragment {
|
PartialInlineBoxFragment {
|
||||||
tag: self.tag,
|
tag: self.tag,
|
||||||
style,
|
style,
|
||||||
|
@ -409,6 +440,7 @@ impl InlineBox {
|
||||||
fragments_so_far: Vec::with_capacity(self.children.len()),
|
fragments_so_far: Vec::with_capacity(self.children.len()),
|
||||||
inline_start: ifc.inline_position,
|
inline_start: ifc.inline_position,
|
||||||
max_block_size_of_fragments_so_far: Length::zero(),
|
max_block_size_of_fragments_so_far: Length::zero(),
|
||||||
|
positioning_context,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -418,6 +450,7 @@ impl InlineBox {
|
||||||
impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
||||||
fn finish_layout(
|
fn finish_layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
layout_context: &LayoutContext,
|
||||||
nesting_level: &mut InlineNestingLevelState,
|
nesting_level: &mut InlineNestingLevelState,
|
||||||
inline_position: &mut Length,
|
inline_position: &mut Length,
|
||||||
at_line_break: bool,
|
at_line_break: bool,
|
||||||
|
@ -459,6 +492,11 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
|
||||||
fragment.border.block_sum() +
|
fragment.border.block_sum() +
|
||||||
fragment.margin.block_sum(),
|
fragment.margin.block_sum(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(context) = nesting_level.positioning_context.as_mut() {
|
||||||
|
context.layout_collected_children(layout_context, &mut fragment);
|
||||||
|
}
|
||||||
|
|
||||||
self.parent_nesting_level
|
self.parent_nesting_level
|
||||||
.fragments_so_far
|
.fragments_so_far
|
||||||
.push(Fragment::Box(fragment));
|
.push(Fragment::Box(fragment));
|
||||||
|
@ -748,7 +786,12 @@ impl TextRun {
|
||||||
ifc.current_nesting_level.inline_start = Length::zero();
|
ifc.current_nesting_level.inline_start = Length::zero();
|
||||||
let mut nesting_level = &mut ifc.current_nesting_level;
|
let mut nesting_level = &mut ifc.current_nesting_level;
|
||||||
for partial in ifc.partial_inline_boxes_stack.iter_mut().rev() {
|
for partial in ifc.partial_inline_boxes_stack.iter_mut().rev() {
|
||||||
partial.finish_layout(nesting_level, &mut ifc.inline_position, true);
|
partial.finish_layout(
|
||||||
|
layout_context,
|
||||||
|
nesting_level,
|
||||||
|
&mut ifc.inline_position,
|
||||||
|
true,
|
||||||
|
);
|
||||||
partial.start_corner.inline = Length::zero();
|
partial.start_corner.inline = Length::zero();
|
||||||
partial.padding.inline_start = Length::zero();
|
partial.padding.inline_start = Length::zero();
|
||||||
partial.border.inline_start = Length::zero();
|
partial.border.inline_start = Length::zero();
|
||||||
|
|
|
@ -172,7 +172,7 @@ impl PositioningContext {
|
||||||
self.for_nearest_positioned_ancestor.is_some()
|
self.for_nearest_positioned_ancestor.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_for_style(style: &ComputedValues) -> Option<Self> {
|
pub(crate) fn new_for_style(style: &ComputedValues) -> Option<Self> {
|
||||||
if style.establishes_containing_block_for_all_descendants() {
|
if style.establishes_containing_block_for_all_descendants() {
|
||||||
Some(Self::new_for_containing_block_for_all_descendants())
|
Some(Self::new_for_containing_block_for_all_descendants())
|
||||||
} else if style.establishes_containing_block() {
|
} else if style.establishes_containing_block() {
|
||||||
|
@ -243,7 +243,7 @@ impl PositioningContext {
|
||||||
|
|
||||||
// Lay out the hoisted boxes collected into this `PositioningContext` and add them
|
// Lay out the hoisted boxes collected into this `PositioningContext` and add them
|
||||||
// to the given `BoxFragment`.
|
// to the given `BoxFragment`.
|
||||||
fn layout_collected_children(
|
pub fn layout_collected_children(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
new_fragment: &mut BoxFragment,
|
new_fragment: &mut BoxFragment,
|
||||||
|
|
|
@ -245,7 +245,9 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
/// Returns true if this style establishes a containing block for all descendants
|
/// Returns true if this style establishes a containing block for all descendants
|
||||||
/// including fixed and absolutely positioned ones.
|
/// including fixed and absolutely positioned ones.
|
||||||
fn establishes_containing_block_for_all_descendants(&self) -> bool {
|
fn establishes_containing_block_for_all_descendants(&self) -> bool {
|
||||||
if self.has_transform_or_perspective() {
|
if self.get_box().display.outside() != stylo::DisplayOutside::Inline &&
|
||||||
|
self.has_transform_or_perspective()
|
||||||
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[abspos-inline-008.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[toogle-abspos-on-relpos-inline-child.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[preserve3d-button.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[filtered-inline-is-container.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[absolute_inline_containing_block_a.html]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue