mirror of
https://github.com/servo/servo.git
synced 2025-08-08 23:15:33 +01:00
layout: Add an indefinite containing block for intrinsic sizing (#33204)
When computing the min-content or max-content size of an element we need to ignore `inline-size`, `min-inline-size` and `max-inline-size`. However, we should take the block-axis sizing properties into account. That's because the contents could have percentages depending on them, which can then affect their inline size via an aspect ratio. Therefore, this patch adds `IndefiniteContainingBlock`, which is similar to `ContainingBlock`, but it allows an indefinite inline-size. This struct is then passed arround during intrinsic sizing. More refinement will be needed in follow-up patches in order to fully address the problem. Signed-off-by: Oriol Brufau <obrufau@igalia.com> Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
parent
46dbe4ce32
commit
93abdf7cb5
29 changed files with 600 additions and 332 deletions
|
@ -18,7 +18,7 @@ use servo_arc::Arc;
|
|||
use style::computed_values::float::T as FloatProperty;
|
||||
use style::logical_geometry::WritingMode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Clear, Length};
|
||||
use style::values::computed::Clear;
|
||||
use style::values::specified::text::TextDecorationLine;
|
||||
|
||||
use crate::context::LayoutContext;
|
||||
|
@ -28,8 +28,8 @@ use crate::formatting_contexts::IndependentFormattingContext;
|
|||
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, CollapsedMargin};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
||||
use crate::positioned::PositioningContext;
|
||||
use crate::style_ext::{ComputedValuesExt, DisplayInside, PaddingBorderMargin};
|
||||
use crate::ContainingBlock;
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, DisplayInside, PaddingBorderMargin};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
/// A floating box.
|
||||
#[derive(Debug, Serialize)]
|
||||
|
@ -905,35 +905,44 @@ impl FloatBox {
|
|||
IndependentFormattingContext::NonReplaced(ref mut non_replaced) => {
|
||||
// Calculate inline size.
|
||||
// https://drafts.csswg.org/css2/#float-width
|
||||
let box_size = non_replaced.style.content_box_size(containing_block, &pbm);
|
||||
let max_box_size = non_replaced
|
||||
.style
|
||||
.content_max_box_size(containing_block, &pbm);
|
||||
let min_box_size = non_replaced
|
||||
.style
|
||||
let style = non_replaced.style.clone();
|
||||
let box_size = style
|
||||
.content_box_size(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let max_box_size = style
|
||||
.content_max_box_size(containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from));
|
||||
let min_box_size = style
|
||||
.content_min_box_size(containing_block, &pbm)
|
||||
.auto_is(Length::zero);
|
||||
.map(|v| v.map(Au::from))
|
||||
.auto_is(Au::zero);
|
||||
|
||||
let tentative_inline_size = box_size.inline.auto_is(|| {
|
||||
let available_size =
|
||||
containing_block.inline_size - pbm_sums.inline_sum();
|
||||
non_replaced
|
||||
.inline_content_sizes(layout_context)
|
||||
.shrink_to_fit(available_size)
|
||||
.into()
|
||||
});
|
||||
let inline_size = tentative_inline_size
|
||||
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
|
||||
let block_size = box_size.block.map(|size| {
|
||||
size.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
||||
});
|
||||
let tentative_inline_size = box_size.inline.auto_is(|| {
|
||||
let available_size =
|
||||
containing_block.inline_size - pbm_sums.inline_sum();
|
||||
let containing_block_for_children =
|
||||
IndefiniteContainingBlock::new_for_style_and_block_size(
|
||||
&style, block_size,
|
||||
);
|
||||
non_replaced
|
||||
.inline_content_sizes(
|
||||
layout_context,
|
||||
&containing_block_for_children,
|
||||
)
|
||||
.shrink_to_fit(available_size)
|
||||
});
|
||||
let inline_size = tentative_inline_size
|
||||
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
|
||||
|
||||
// Calculate block size.
|
||||
// https://drafts.csswg.org/css2/#block-root-margin
|
||||
// FIXME(pcwalton): Is a tree rank of zero correct here?
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size: inline_size.into(),
|
||||
block_size: block_size.map(|t| t.into()),
|
||||
inline_size,
|
||||
block_size,
|
||||
style: &non_replaced.style,
|
||||
};
|
||||
let independent_layout = non_replaced.layout(
|
||||
|
@ -944,13 +953,13 @@ impl FloatBox {
|
|||
);
|
||||
let (block_size, inline_size) =
|
||||
match independent_layout.content_inline_size_for_table {
|
||||
Some(inline_size) => (
|
||||
independent_layout.content_block_size.into(),
|
||||
inline_size.into(),
|
||||
),
|
||||
Some(inline_size) => {
|
||||
(independent_layout.content_block_size, inline_size)
|
||||
},
|
||||
None => (
|
||||
block_size.auto_is(|| {
|
||||
Length::from(independent_layout.content_block_size)
|
||||
independent_layout
|
||||
.content_block_size
|
||||
.clamp_between_extremums(
|
||||
min_box_size.block,
|
||||
max_box_size.block,
|
||||
|
@ -960,8 +969,8 @@ impl FloatBox {
|
|||
),
|
||||
};
|
||||
content_size = LogicalVec2 {
|
||||
inline: inline_size.into(),
|
||||
block: block_size.into(),
|
||||
inline: inline_size,
|
||||
block: block_size,
|
||||
};
|
||||
children = independent_layout.fragments;
|
||||
},
|
||||
|
|
|
@ -94,7 +94,6 @@ use style::computed_values::text_wrap_mode::T as TextWrapMode;
|
|||
use style::computed_values::vertical_align::T as VerticalAlign;
|
||||
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapse;
|
||||
use style::context::QuirksMode;
|
||||
use style::logical_geometry::WritingMode;
|
||||
use style::properties::style_structs::InheritedText;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{Clear, Length};
|
||||
|
@ -128,7 +127,7 @@ use crate::geom::{LogicalRect, LogicalVec2, PhysicalRect, ToLogical};
|
|||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||
use crate::sizing::ContentSizes;
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::ContainingBlock;
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
// From gfxFontConstants.h in Firefox.
|
||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||
|
@ -1557,9 +1556,9 @@ impl InlineFormattingContext {
|
|||
pub(super) fn inline_content_sizes(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
ContentSizesComputation::compute(self, layout_context, containing_block_writing_mode)
|
||||
ContentSizesComputation::compute(self, layout_context, containing_block_for_children)
|
||||
}
|
||||
|
||||
pub(super) fn layout(
|
||||
|
@ -1954,13 +1953,19 @@ impl IndependentFormattingContext {
|
|||
.content_min_box_size(layout.containing_block, &pbm)
|
||||
.map(|v| v.map(Au::from))
|
||||
.auto_is(Au::zero);
|
||||
let block_size = box_size
|
||||
.block
|
||||
.map(|v| v.clamp_between_extremums(min_box_size.block, max_box_size.block));
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
|
||||
let tentative_inline_size = box_size.inline.auto_is(|| {
|
||||
let style = non_replaced.style.clone();
|
||||
let containing_block_for_children =
|
||||
IndefiniteContainingBlock::new_for_style_and_block_size(&style, block_size);
|
||||
let available_size =
|
||||
layout.containing_block.inline_size - pbm_sums.inline_sum();
|
||||
non_replaced
|
||||
.inline_content_sizes(layout.layout_context)
|
||||
.inline_content_sizes(layout.layout_context, &containing_block_for_children)
|
||||
.shrink_to_fit(available_size)
|
||||
});
|
||||
|
||||
|
@ -1969,9 +1974,6 @@ impl IndependentFormattingContext {
|
|||
// always results in that size.
|
||||
let inline_size = tentative_inline_size
|
||||
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
|
||||
let block_size = box_size
|
||||
.block
|
||||
.map(|v| v.clamp_between_extremums(min_box_size.block, max_box_size.block));
|
||||
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size,
|
||||
|
@ -2259,7 +2261,7 @@ fn inline_container_needs_strut(
|
|||
/// A struct which takes care of computing [`ContentSizes`] for an [`InlineFormattingContext`].
|
||||
struct ContentSizesComputation<'layout_data> {
|
||||
layout_context: &'layout_data LayoutContext<'layout_data>,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
containing_block: &'layout_data IndefiniteContainingBlock<'layout_data>,
|
||||
paragraph: ContentSizes,
|
||||
current_line: ContentSizes,
|
||||
/// Size for whitepsace pending to be added to this line.
|
||||
|
@ -2297,14 +2299,14 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
|||
let zero = Length::zero();
|
||||
let padding = inline_box
|
||||
.style
|
||||
.padding(self.containing_block_writing_mode)
|
||||
.padding(self.containing_block.style.writing_mode)
|
||||
.percentages_relative_to(zero);
|
||||
let border = inline_box
|
||||
.style
|
||||
.border_width(self.containing_block_writing_mode);
|
||||
.border_width(self.containing_block.style.writing_mode);
|
||||
let margin = inline_box
|
||||
.style
|
||||
.margin(self.containing_block_writing_mode)
|
||||
.margin(self.containing_block.style.writing_mode)
|
||||
.percentages_relative_to(zero)
|
||||
.auto_is(Length::zero);
|
||||
|
||||
|
@ -2379,8 +2381,8 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
|||
|
||||
let outer = atomic.outer_inline_content_sizes(
|
||||
self.layout_context,
|
||||
self.containing_block_writing_mode,
|
||||
Au::zero,
|
||||
self.containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
);
|
||||
|
||||
if !inline_formatting_context
|
||||
|
@ -2428,11 +2430,11 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
|||
fn compute(
|
||||
inline_formatting_context: &InlineFormattingContext,
|
||||
layout_context: &'layout_data LayoutContext,
|
||||
containing_block_writing_mode: WritingMode,
|
||||
containing_block: &'layout_data IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
Self {
|
||||
layout_context,
|
||||
containing_block_writing_mode,
|
||||
containing_block,
|
||||
paragraph: ContentSizes::zero(),
|
||||
current_line: ContentSizes::zero(),
|
||||
pending_whitespace: Au::zero(),
|
||||
|
|
|
@ -36,7 +36,7 @@ use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, Positioning
|
|||
use crate::replaced::ReplacedContent;
|
||||
use crate::sizing::{self, ContentSizes};
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::ContainingBlock;
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
mod construct;
|
||||
pub mod float;
|
||||
|
@ -227,10 +227,10 @@ impl OutsideMarker {
|
|||
sequential_layout_state: Option<&mut SequentialLayoutState>,
|
||||
collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
|
||||
) -> Fragment {
|
||||
let containing_block_writing_mode = containing_block.effective_writing_mode();
|
||||
let content_sizes = self
|
||||
.block_container
|
||||
.inline_content_sizes(layout_context, containing_block_writing_mode);
|
||||
let content_sizes = self.block_container.inline_content_sizes(
|
||||
layout_context,
|
||||
&IndefiniteContainingBlock::new_for_style(&self.marker_style),
|
||||
);
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size: content_sizes.max_content,
|
||||
block_size: AuOrAuto::auto(),
|
||||
|
@ -244,6 +244,8 @@ impl OutsideMarker {
|
|||
sequential_layout_state,
|
||||
collapsible_with_parent_start_margin.unwrap_or(CollapsibleWithParentStartMargin(false)),
|
||||
);
|
||||
|
||||
let containing_block_writing_mode = containing_block.effective_writing_mode();
|
||||
let max_inline_size =
|
||||
flow_layout
|
||||
.fragments
|
||||
|
@ -357,7 +359,7 @@ impl BlockFormattingContext {
|
|||
fn calculate_inline_content_size_for_block_level_boxes(
|
||||
boxes: &[ArcRefCell<BlockLevelBox>],
|
||||
layout_context: &LayoutContext,
|
||||
writing_mode: WritingMode,
|
||||
containing_block: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| {
|
||||
match &mut *box_.borrow_mut() {
|
||||
|
@ -366,7 +368,11 @@ fn calculate_inline_content_size_for_block_level_boxes(
|
|||
BlockLevelBox::OutOfFlowFloatBox(ref mut float_box) => {
|
||||
let size = float_box
|
||||
.contents
|
||||
.outer_inline_content_sizes(layout_context, writing_mode, Au::zero)
|
||||
.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
)
|
||||
.max(ContentSizes::zero());
|
||||
let style_box = &float_box.contents.style().get_box();
|
||||
Some((size, style_box.float, style_box.clear))
|
||||
|
@ -376,12 +382,11 @@ fn calculate_inline_content_size_for_block_level_boxes(
|
|||
} => {
|
||||
let size = sizing::outer_inline(
|
||||
style,
|
||||
writing_mode,
|
||||
|| {
|
||||
contents
|
||||
.inline_content_sizes(layout_context, style.effective_writing_mode())
|
||||
&containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
|containing_block_for_children| {
|
||||
contents.inline_content_sizes(layout_context, containing_block_for_children)
|
||||
},
|
||||
Au::zero,
|
||||
)
|
||||
.max(ContentSizes::zero());
|
||||
// A block in the same BFC can overlap floats, it's not moved next to them,
|
||||
|
@ -391,7 +396,11 @@ fn calculate_inline_content_size_for_block_level_boxes(
|
|||
},
|
||||
BlockLevelBox::Independent(ref mut independent) => {
|
||||
let size = independent
|
||||
.outer_inline_content_sizes(layout_context, writing_mode, Au::zero)
|
||||
.outer_inline_content_sizes(
|
||||
layout_context,
|
||||
containing_block,
|
||||
&LogicalVec2::zero(),
|
||||
)
|
||||
.max(ContentSizes::zero());
|
||||
Some((size, Float::None, independent.style().get_box().clear))
|
||||
},
|
||||
|
@ -498,16 +507,16 @@ impl BlockContainer {
|
|||
pub(super) fn inline_content_sizes(
|
||||
&self,
|
||||
layout_context: &LayoutContext,
|
||||
writing_mode: WritingMode,
|
||||
containing_block_for_children: &IndefiniteContainingBlock,
|
||||
) -> ContentSizes {
|
||||
match &self {
|
||||
Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes(
|
||||
boxes,
|
||||
layout_context,
|
||||
writing_mode,
|
||||
containing_block_for_children,
|
||||
),
|
||||
Self::InlineFormattingContext(context) => {
|
||||
context.inline_content_sizes(layout_context, writing_mode)
|
||||
context.inline_content_sizes(layout_context, containing_block_for_children)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue