mirror of
https://github.com/servo/servo.git
synced 2025-07-31 19:20:22 +01:00
layout: Avoid layout sometimes when stretching (#33967)
This is the second flexbox caching change. It seeks to detect when a relayout can be avoided in the case of a stretching flex item. This heuristic can be combined, because currently we still do relayout sometimes when we do not need to. For instance currently we always relayout when a flex child is itself a column flex. This only needs to happen when the grandchildren themselves grow or shrink. That optimization is perhaps a lower priority as `flex-grow: 0 / flex-shrink: 1` is the default behavior for flex. Since this change means we more consistenly zero out the percentage part of `calc` expressions when they have circular dependencies, this causes one test to start failing (`/css/css-values/calc-min-height-block-1.html`). This is related to w3c/csswg-drafts#10969, which is pending on further discussion in the working group. Signed-off-by: Martin Robinson <mrobinson@igalia.com> Co-authored-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
638b520186
commit
52db185568
12 changed files with 490 additions and 257 deletions
|
@ -181,7 +181,7 @@ where
|
||||||
independent_formatting_context: IndependentFormattingContext::NonReplaced(
|
independent_formatting_context: IndependentFormattingContext::NonReplaced(
|
||||||
non_replaced,
|
non_replaced,
|
||||||
),
|
),
|
||||||
cached_layout: Default::default(),
|
block_content_size_cache: Default::default(),
|
||||||
})))
|
})))
|
||||||
},
|
},
|
||||||
FlexLevelJob::Element {
|
FlexLevelJob::Element {
|
||||||
|
@ -213,7 +213,7 @@ where
|
||||||
contents,
|
contents,
|
||||||
self.text_decoration_line,
|
self.text_decoration_line,
|
||||||
),
|
),
|
||||||
cached_layout: Default::default(),
|
block_content_size_cache: Default::default(),
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
box_slot.set(LayoutBox::FlexLevel(box_.clone()));
|
box_slot.set(LayoutBox::FlexLevel(box_.clone()));
|
||||||
|
|
|
@ -12,6 +12,7 @@ use style::computed_values::position::T as Position;
|
||||||
use style::logical_geometry::Direction;
|
use style::logical_geometry::Direction;
|
||||||
use style::properties::longhands::align_items::computed_value::T as AlignItems;
|
use style::properties::longhands::align_items::computed_value::T as AlignItems;
|
||||||
use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
|
use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
|
||||||
|
use style::properties::longhands::flex_direction::computed_value::T as FlexDirection;
|
||||||
use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap;
|
use style::properties::longhands::flex_wrap::computed_value::T as FlexWrap;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::length::Size;
|
use style::values::computed::length::Size;
|
||||||
|
@ -22,8 +23,7 @@ use style::Zero;
|
||||||
|
|
||||||
use super::geom::{FlexAxis, FlexRelativeRect, FlexRelativeSides, FlexRelativeVec2};
|
use super::geom::{FlexAxis, FlexRelativeRect, FlexRelativeSides, FlexRelativeVec2};
|
||||||
use super::{
|
use super::{
|
||||||
FlexContainer, FlexContainerConfig, FlexItemBox, FlexItemLayoutCache,
|
CachedBlockSizeContribution, FlexContainer, FlexContainerConfig, FlexItemBox, FlexLevelBox,
|
||||||
FlexItemLayoutCacheDescriptor, FlexLevelBox,
|
|
||||||
};
|
};
|
||||||
use crate::cell::ArcRefCell;
|
use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
|
@ -34,7 +34,9 @@ use crate::positioned::{
|
||||||
relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength,
|
relative_adjustement, AbsolutelyPositionedBox, PositioningContext, PositioningContextLength,
|
||||||
};
|
};
|
||||||
use crate::sizing::{ContentSizes, InlineContentSizesResult, IntrinsicSizingMode};
|
use crate::sizing::{ContentSizes, InlineContentSizesResult, IntrinsicSizingMode};
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
use crate::style_ext::{
|
||||||
|
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
|
||||||
|
};
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||||
|
|
||||||
// FIMXE: “Flex items […] `z-index` values other than `auto` create a stacking context
|
// FIMXE: “Flex items […] `z-index` values other than `auto` create a stacking context
|
||||||
|
@ -78,8 +80,12 @@ struct FlexItem<'a> {
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-flexbox/#algo-main-item>
|
/// <https://drafts.csswg.org/css-flexbox/#algo-main-item>
|
||||||
hypothetical_main_size: Au,
|
hypothetical_main_size: Au,
|
||||||
|
|
||||||
/// This is `align-self`, defaulting to `align-items` if `auto`
|
/// This is `align-self`, defaulting to `align-items` if `auto`
|
||||||
align_self: AlignItems,
|
align_self: AlignItems,
|
||||||
|
|
||||||
|
/// Whether or not the size of this [`FlexItem`] depends on its block constraints.
|
||||||
|
depends_on_block_constraints: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Child of a FlexContainer. Can either be absolutely positioned, or not. If not,
|
/// Child of a FlexContainer. Can either be absolutely positioned, or not. If not,
|
||||||
|
@ -97,6 +103,22 @@ struct FlexItemLayoutResult {
|
||||||
|
|
||||||
// Either the first or the last baseline, depending on ‘align-self’.
|
// Either the first or the last baseline, depending on ‘align-self’.
|
||||||
baseline_relative_to_margin_box: Option<Au>,
|
baseline_relative_to_margin_box: Option<Au>,
|
||||||
|
|
||||||
|
// The content size of this layout. For replaced elements this is known before layout,
|
||||||
|
// but for non-replaced it's only known after layout.
|
||||||
|
content_size: LogicalVec2<Au>,
|
||||||
|
|
||||||
|
// The containing block inline size used to generate this layout.
|
||||||
|
containing_block_inline_size: Au,
|
||||||
|
|
||||||
|
// The containing block block size used to generate this layout.
|
||||||
|
containing_block_block_size: AuOrAuto,
|
||||||
|
|
||||||
|
// Whether or not this layout depended on block constraints.
|
||||||
|
depends_on_block_constraints: bool,
|
||||||
|
|
||||||
|
// Whether or not this layout had a child that dependeded on block constraints.
|
||||||
|
has_child_which_depends_on_block_constraints: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlexItemLayoutResult {
|
impl FlexItemLayoutResult {
|
||||||
|
@ -172,11 +194,17 @@ impl FlexItemLayoutResult {
|
||||||
|
|
||||||
let mut fragment_info = item.box_.base_fragment_info();
|
let mut fragment_info = item.box_.base_fragment_info();
|
||||||
fragment_info.flags.insert(FragmentFlags::IS_FLEX_ITEM);
|
fragment_info.flags.insert(FragmentFlags::IS_FLEX_ITEM);
|
||||||
|
if item.depends_on_block_constraints {
|
||||||
|
fragment_info.flags.insert(
|
||||||
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
let flags = fragment_info.flags;
|
let flags = fragment_info.flags;
|
||||||
|
|
||||||
let containing_block = flex_context.containing_block;
|
let containing_block = flex_context.containing_block;
|
||||||
let container_writing_mode = containing_block.style.writing_mode;
|
let container_writing_mode = containing_block.style.writing_mode;
|
||||||
let style = item.box_.style();
|
let style = item.box_.style();
|
||||||
|
|
||||||
let mut fragment = BoxFragment::new(
|
let mut fragment = BoxFragment::new(
|
||||||
fragment_info,
|
fragment_info,
|
||||||
style.clone(),
|
style.clone(),
|
||||||
|
@ -208,6 +236,23 @@ impl FlexItemLayoutResult {
|
||||||
|
|
||||||
(fragment, self.positioning_context)
|
(fragment, self.positioning_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compatible_with_containing_block_size(&self, containing_block: &ContainingBlock) -> bool {
|
||||||
|
if containing_block.inline_size != self.containing_block_inline_size {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
containing_block.block_size == self.containing_block_block_size ||
|
||||||
|
(!self.depends_on_block_constraints &&
|
||||||
|
!self.has_child_which_depends_on_block_constraints)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compatible_with_containing_block_size_and_content_size(
|
||||||
|
&self,
|
||||||
|
containing_block: &ContainingBlock,
|
||||||
|
size: LogicalVec2<Au>,
|
||||||
|
) -> bool {
|
||||||
|
size == self.content_size && self.compatible_with_containing_block_size(containing_block)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InitialFlexLineLayout<'a> {
|
struct InitialFlexLineLayout<'a> {
|
||||||
|
@ -571,8 +616,12 @@ impl FlexContainer {
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
containing_block_for_container: &ContainingBlock,
|
containing_block_for_container: &ContainingBlock,
|
||||||
) -> IndependentLayout {
|
) -> IndependentLayout {
|
||||||
let (container_min_cross_size, container_max_cross_size) =
|
let (container_min_cross_size, container_max_cross_size, depends_on_block_constraints) =
|
||||||
self.available_cross_space_for_flex_items(containing_block_for_container);
|
self.available_cross_space_for_flex_items(containing_block_for_container);
|
||||||
|
|
||||||
|
let depends_on_block_constraints =
|
||||||
|
depends_on_block_constraints || self.config.flex_direction == FlexDirection::Column;
|
||||||
|
|
||||||
let mut flex_context = FlexContext {
|
let mut flex_context = FlexContext {
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
layout_context,
|
layout_context,
|
||||||
|
@ -896,6 +945,7 @@ impl FlexContainer {
|
||||||
content_block_size,
|
content_block_size,
|
||||||
content_inline_size_for_table: None,
|
content_inline_size_for_table: None,
|
||||||
baselines,
|
baselines,
|
||||||
|
depends_on_block_constraints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -967,22 +1017,26 @@ impl FlexContainer {
|
||||||
fn available_cross_space_for_flex_items(
|
fn available_cross_space_for_flex_items(
|
||||||
&self,
|
&self,
|
||||||
containing_block_for_container: &ContainingBlock,
|
containing_block_for_container: &ContainingBlock,
|
||||||
) -> (Au, Option<Au>) {
|
) -> (Au, Option<Au>, bool) {
|
||||||
let pbm = self
|
let sizes: ContentBoxSizesAndPBMDeprecated = self
|
||||||
.style
|
.style
|
||||||
.padding_border_margin(containing_block_for_container);
|
.content_box_sizes_and_padding_border_margin(&containing_block_for_container.into())
|
||||||
|
.into();
|
||||||
|
|
||||||
let max_box_size = self
|
let max_box_size = self
|
||||||
.style
|
.config
|
||||||
.content_max_box_size_deprecated(containing_block_for_container, &pbm);
|
.flex_axis
|
||||||
|
.vec2_to_flex_relative(sizes.content_max_box_size);
|
||||||
let min_box_size = self
|
let min_box_size = self
|
||||||
.style
|
.config
|
||||||
.content_min_box_size_deprecated(containing_block_for_container, &pbm)
|
.flex_axis
|
||||||
.auto_is(Au::zero);
|
.vec2_to_flex_relative(sizes.content_min_box_size.auto_is(Au::zero));
|
||||||
|
|
||||||
let max_box_size = self.config.flex_axis.vec2_to_flex_relative(max_box_size);
|
(
|
||||||
let min_box_size = self.config.flex_axis.vec2_to_flex_relative(min_box_size);
|
min_box_size.cross,
|
||||||
|
max_box_size.cross,
|
||||||
(min_box_size.cross, max_box_size.cross)
|
sizes.depends_on_block_constraints,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1046,9 +1100,16 @@ impl<'a> FlexItem<'a> {
|
||||||
flex_context.config.flex_axis,
|
flex_context.config.flex_axis,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (content_box_size, min_size, max_size, pbm, _) = box_
|
let ContentBoxSizesAndPBMDeprecated {
|
||||||
|
content_box_size,
|
||||||
|
content_min_box_size,
|
||||||
|
content_max_box_size,
|
||||||
|
pbm,
|
||||||
|
depends_on_block_constraints,
|
||||||
|
} = box_
|
||||||
.style()
|
.style()
|
||||||
.content_box_sizes_and_padding_border_margin_deprecated(&containing_block.into());
|
.content_box_sizes_and_padding_border_margin(&containing_block.into())
|
||||||
|
.into();
|
||||||
|
|
||||||
let margin_auto_is_zero = flex_context.sides_to_flex_relative(pbm.margin.auto_is(Au::zero));
|
let margin_auto_is_zero = flex_context.sides_to_flex_relative(pbm.margin.auto_is(Au::zero));
|
||||||
let padding = flex_context.sides_to_flex_relative(pbm.padding);
|
let padding = flex_context.sides_to_flex_relative(pbm.padding);
|
||||||
|
@ -1065,8 +1126,10 @@ impl<'a> FlexItem<'a> {
|
||||||
.item_with_auto_cross_size_stretches_to_container_size(box_.style(), &margin);
|
.item_with_auto_cross_size_stretches_to_container_size(box_.style(), &margin);
|
||||||
|
|
||||||
let flex_relative_content_box_size = flex_context.vec2_to_flex_relative(content_box_size);
|
let flex_relative_content_box_size = flex_context.vec2_to_flex_relative(content_box_size);
|
||||||
let flex_relative_content_max_size = flex_context.vec2_to_flex_relative(max_size);
|
let flex_relative_content_max_size =
|
||||||
let flex_relative_content_min_size = flex_context.vec2_to_flex_relative(min_size);
|
flex_context.vec2_to_flex_relative(content_max_box_size);
|
||||||
|
let flex_relative_content_min_size =
|
||||||
|
flex_context.vec2_to_flex_relative(content_min_box_size);
|
||||||
let flex_relative_content_min_size = FlexRelativeVec2 {
|
let flex_relative_content_min_size = FlexRelativeVec2 {
|
||||||
main: flex_relative_content_min_size.main.auto_is(|| {
|
main: flex_relative_content_min_size.main.auto_is(|| {
|
||||||
box_.automatic_min_size(
|
box_.automatic_min_size(
|
||||||
|
@ -1079,14 +1142,14 @@ impl<'a> FlexItem<'a> {
|
||||||
&pbm_auto_is_zero,
|
&pbm_auto_is_zero,
|
||||||
item_with_auto_cross_size_stretches_to_container_size,
|
item_with_auto_cross_size_stretches_to_container_size,
|
||||||
|item| {
|
|item| {
|
||||||
let min_size_auto_is_zero = min_size.auto_is(Au::zero);
|
let min_size_auto_is_zero = content_min_box_size.auto_is(Au::zero);
|
||||||
|
|
||||||
item.layout_for_block_content_size(
|
item.layout_for_block_content_size(
|
||||||
flex_context,
|
flex_context,
|
||||||
&pbm,
|
&pbm,
|
||||||
content_box_size,
|
content_box_size,
|
||||||
min_size_auto_is_zero,
|
min_size_auto_is_zero,
|
||||||
max_size,
|
content_max_box_size,
|
||||||
item_with_auto_cross_size_stretches_to_container_size,
|
item_with_auto_cross_size_stretches_to_container_size,
|
||||||
IntrinsicSizingMode::Size,
|
IntrinsicSizingMode::Size,
|
||||||
)
|
)
|
||||||
|
@ -1095,7 +1158,6 @@ impl<'a> FlexItem<'a> {
|
||||||
}),
|
}),
|
||||||
cross: flex_relative_content_min_size.cross.auto_is(Au::zero),
|
cross: flex_relative_content_min_size.cross.auto_is(Au::zero),
|
||||||
};
|
};
|
||||||
|
|
||||||
let align_self = AlignItems(
|
let align_self = AlignItems(
|
||||||
flex_context
|
flex_context
|
||||||
.config
|
.config
|
||||||
|
@ -1122,7 +1184,7 @@ impl<'a> FlexItem<'a> {
|
||||||
&pbm,
|
&pbm,
|
||||||
content_box_size,
|
content_box_size,
|
||||||
min_size,
|
min_size,
|
||||||
max_size,
|
content_max_box_size,
|
||||||
item_with_auto_cross_size_stretches_to_container_size,
|
item_with_auto_cross_size_stretches_to_container_size,
|
||||||
IntrinsicSizingMode::Size,
|
IntrinsicSizingMode::Size,
|
||||||
)
|
)
|
||||||
|
@ -1148,6 +1210,7 @@ impl<'a> FlexItem<'a> {
|
||||||
flex_base_size_is_definite,
|
flex_base_size_is_definite,
|
||||||
hypothetical_main_size,
|
hypothetical_main_size,
|
||||||
align_self,
|
align_self,
|
||||||
|
depends_on_block_constraints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1263,7 +1326,10 @@ impl InitialFlexLineLayout<'_> {
|
||||||
let item_layout_results = items
|
let item_layout_results = items
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(&item_used_main_sizes)
|
.zip(&item_used_main_sizes)
|
||||||
.map(|(item, &used_main_size)| item.layout(used_main_size, flex_context, None))
|
.map(|(item, &used_main_size)| {
|
||||||
|
item.layout(used_main_size, flex_context, None, None)
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-flexbox/#algo-cross-line
|
// https://drafts.csswg.org/css-flexbox/#algo-cross-line
|
||||||
|
@ -1552,14 +1618,23 @@ impl InitialFlexLineLayout<'_> {
|
||||||
};
|
};
|
||||||
item_used_cross_sizes.push(used_cross_size);
|
item_used_cross_sizes.push(used_cross_size);
|
||||||
|
|
||||||
|
// “If the flex item has `align-self: stretch`, redo layout for its contents,
|
||||||
|
// treating this used size as its definite cross size so that percentage-sized
|
||||||
|
// children can be resolved.”
|
||||||
if stretches {
|
if stretches {
|
||||||
// “If the flex item has `align-self: stretch`, redo layout for its contents,
|
let new_layout = item.layout(
|
||||||
// treating this used size as its definite cross size
|
*used_main_size,
|
||||||
// so that percentage-sized children can be resolved.”
|
flex_context,
|
||||||
*item_layout_result =
|
Some(used_cross_size),
|
||||||
item.layout(*used_main_size, flex_context, Some(used_cross_size));
|
Some(item_layout_result),
|
||||||
|
);
|
||||||
|
if let Some(layout) = new_layout {
|
||||||
|
*item_layout_result = layout;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let _ = item.box_.block_content_size_cache.borrow_mut().take();
|
||||||
|
|
||||||
let baseline = item_layout_result
|
let baseline = item_layout_result
|
||||||
.get_or_synthesize_baseline_with_cross_size(used_cross_size, item);
|
.get_or_synthesize_baseline_with_cross_size(used_cross_size, item);
|
||||||
if matches!(
|
if matches!(
|
||||||
|
@ -1705,14 +1780,16 @@ impl FlexItem<'_> {
|
||||||
/// From <https://drafts.csswg.org/css-flexbox/#algo-cross-item>:
|
/// From <https://drafts.csswg.org/css-flexbox/#algo-cross-item>:
|
||||||
/// > performing layout as if it were an in-flow block-level box with the used main
|
/// > performing layout as if it were an in-flow block-level box with the used main
|
||||||
/// > size and the given available space, treating `auto` as `fit-content`.
|
/// > size and the given available space, treating `auto` as `fit-content`.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
used_main_size: Au,
|
used_main_size: Au,
|
||||||
flex_context: &FlexContext,
|
flex_context: &FlexContext,
|
||||||
used_cross_size_override: Option<Au>,
|
used_cross_size_override: Option<Au>,
|
||||||
) -> FlexItemLayoutResult {
|
non_stretch_layout_result: Option<&mut FlexItemLayoutResult>,
|
||||||
|
) -> Option<FlexItemLayoutResult> {
|
||||||
// Clear any layout cache information so that it doesn't persist until the next layout.
|
// Clear any layout cache information so that it doesn't persist until the next layout.
|
||||||
self.box_.cached_layout.borrow_mut().take();
|
self.box_.block_content_size_cache.borrow_mut().take();
|
||||||
|
|
||||||
let containing_block = flex_context.containing_block;
|
let containing_block = flex_context.containing_block;
|
||||||
let mut positioning_context = PositioningContext::new_for_style(self.box_.style())
|
let mut positioning_context = PositioningContext::new_for_style(self.box_.style())
|
||||||
|
@ -1799,34 +1876,82 @@ impl FlexItem<'_> {
|
||||||
flex_axis.vec2_to_flow_relative(self.content_min_size),
|
flex_axis.vec2_to_flow_relative(self.content_min_size),
|
||||||
flex_axis.vec2_to_flow_relative(self.content_max_size),
|
flex_axis.vec2_to_flow_relative(self.content_max_size),
|
||||||
);
|
);
|
||||||
let cross_size = flex_axis.vec2_to_flex_relative(size).cross;
|
let hypothetical_cross_size = flex_axis.vec2_to_flex_relative(size).cross;
|
||||||
|
|
||||||
|
if let Some(non_stretch_layout_result) = non_stretch_layout_result {
|
||||||
|
if non_stretch_layout_result
|
||||||
|
.compatible_with_containing_block_size_and_content_size(
|
||||||
|
containing_block,
|
||||||
|
size,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
non_stretch_layout_result.hypothetical_cross_size = hypothetical_cross_size;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let fragments = replaced.contents.make_fragments(
|
let fragments = replaced.contents.make_fragments(
|
||||||
&replaced.style,
|
&replaced.style,
|
||||||
containing_block,
|
containing_block,
|
||||||
size.to_physical_size(container_writing_mode),
|
size.to_physical_size(container_writing_mode),
|
||||||
);
|
);
|
||||||
|
|
||||||
FlexItemLayoutResult {
|
Some(FlexItemLayoutResult {
|
||||||
hypothetical_cross_size: cross_size,
|
hypothetical_cross_size,
|
||||||
fragments,
|
fragments,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
|
content_size: size,
|
||||||
|
containing_block_inline_size: containing_block.inline_size,
|
||||||
|
containing_block_block_size: containing_block.block_size,
|
||||||
|
depends_on_block_constraints: false,
|
||||||
|
has_child_which_depends_on_block_constraints: false,
|
||||||
|
|
||||||
// We will need to synthesize the baseline, but since the used cross
|
// We will need to synthesize the baseline, but since the used cross
|
||||||
// size can differ from the hypothetical cross size, we should defer
|
// size can differ from the hypothetical cross size, we should defer
|
||||||
// synthesizing until needed.
|
// synthesizing until needed.
|
||||||
baseline_relative_to_margin_box: None,
|
baseline_relative_to_margin_box: None,
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||||
|
let calculate_hypothetical_cross_size = |content_block_size| {
|
||||||
|
self.content_box_size
|
||||||
|
.cross
|
||||||
|
.auto_is(|| {
|
||||||
|
if cross_axis_is_item_block_axis {
|
||||||
|
content_block_size
|
||||||
|
} else {
|
||||||
|
inline_size
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.clamp_between_extremums(
|
||||||
|
self.content_min_size.cross,
|
||||||
|
self.content_max_size.cross,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let item_as_containing_block = ContainingBlock {
|
let item_as_containing_block = ContainingBlock {
|
||||||
inline_size,
|
inline_size,
|
||||||
block_size,
|
block_size,
|
||||||
style: &non_replaced.style,
|
style: &non_replaced.style,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(non_stretch_layout_result) = non_stretch_layout_result {
|
||||||
|
if non_stretch_layout_result
|
||||||
|
.compatible_with_containing_block_size(&item_as_containing_block)
|
||||||
|
{
|
||||||
|
non_stretch_layout_result.hypothetical_cross_size =
|
||||||
|
calculate_hypothetical_cross_size(
|
||||||
|
non_stretch_layout_result.content_size.inline,
|
||||||
|
);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let IndependentLayout {
|
let IndependentLayout {
|
||||||
fragments,
|
fragments,
|
||||||
content_block_size,
|
content_block_size,
|
||||||
baselines: content_box_baselines,
|
baselines: content_box_baselines,
|
||||||
|
depends_on_block_constraints,
|
||||||
..
|
..
|
||||||
} = non_replaced.layout(
|
} = non_replaced.layout(
|
||||||
flex_context.layout_context,
|
flex_context.layout_context,
|
||||||
|
@ -1835,6 +1960,12 @@ impl FlexItem<'_> {
|
||||||
containing_block,
|
containing_block,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let has_child_which_depends_on_block_constraints = fragments.iter().any(|fragment| {
|
||||||
|
fragment.base().map_or(false,|base|
|
||||||
|
base.flags.contains(
|
||||||
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM))
|
||||||
|
});
|
||||||
|
|
||||||
let item_writing_mode_is_orthogonal_to_container_writing_mode =
|
let item_writing_mode_is_orthogonal_to_container_writing_mode =
|
||||||
flex_context.config.writing_mode.is_horizontal() !=
|
flex_context.config.writing_mode.is_horizontal() !=
|
||||||
non_replaced.style.writing_mode.is_horizontal();
|
non_replaced.style.writing_mode.is_horizontal();
|
||||||
|
@ -1860,27 +1991,20 @@ impl FlexItem<'_> {
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let hypothetical_cross_size = self
|
Some(FlexItemLayoutResult {
|
||||||
.content_box_size
|
hypothetical_cross_size: calculate_hypothetical_cross_size(content_block_size),
|
||||||
.cross
|
|
||||||
.auto_is(|| {
|
|
||||||
if cross_axis_is_item_block_axis {
|
|
||||||
content_block_size
|
|
||||||
} else {
|
|
||||||
inline_size
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.clamp_between_extremums(
|
|
||||||
self.content_min_size.cross,
|
|
||||||
self.content_max_size.cross,
|
|
||||||
);
|
|
||||||
|
|
||||||
FlexItemLayoutResult {
|
|
||||||
hypothetical_cross_size,
|
|
||||||
fragments,
|
fragments,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
baseline_relative_to_margin_box,
|
baseline_relative_to_margin_box,
|
||||||
}
|
content_size: LogicalVec2 {
|
||||||
|
inline: item_as_containing_block.inline_size,
|
||||||
|
block: content_block_size,
|
||||||
|
},
|
||||||
|
containing_block_inline_size: item_as_containing_block.inline_size,
|
||||||
|
containing_block_block_size: item_as_containing_block.block_size,
|
||||||
|
depends_on_block_constraints,
|
||||||
|
has_child_which_depends_on_block_constraints,
|
||||||
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2035,8 +2159,15 @@ impl FlexItemBox {
|
||||||
let cross_axis_is_item_block_axis =
|
let cross_axis_is_item_block_axis =
|
||||||
cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis);
|
cross_axis_is_item_block_axis(container_is_horizontal, item_is_horizontal, flex_axis);
|
||||||
|
|
||||||
let (content_box_size, content_min_size, content_max_size, pbm, _) =
|
let ContentBoxSizesAndPBMDeprecated {
|
||||||
style.content_box_sizes_and_padding_border_margin_deprecated(containing_block);
|
content_box_size,
|
||||||
|
content_min_box_size,
|
||||||
|
content_max_box_size,
|
||||||
|
pbm,
|
||||||
|
..
|
||||||
|
} = style
|
||||||
|
.content_box_sizes_and_padding_border_margin(containing_block)
|
||||||
|
.into();
|
||||||
let padding = main_start_cross_start.sides_to_flex_relative(pbm.padding);
|
let padding = main_start_cross_start.sides_to_flex_relative(pbm.padding);
|
||||||
let border = main_start_cross_start.sides_to_flex_relative(pbm.border);
|
let border = main_start_cross_start.sides_to_flex_relative(pbm.border);
|
||||||
let margin = main_start_cross_start.sides_to_flex_relative(pbm.margin);
|
let margin = main_start_cross_start.sides_to_flex_relative(pbm.margin);
|
||||||
|
@ -2055,8 +2186,8 @@ impl FlexItemBox {
|
||||||
containing_block,
|
containing_block,
|
||||||
cross_axis_is_item_block_axis,
|
cross_axis_is_item_block_axis,
|
||||||
flex_axis.vec2_to_flex_relative(content_box_size),
|
flex_axis.vec2_to_flex_relative(content_box_size),
|
||||||
flex_axis.vec2_to_flex_relative(content_min_size),
|
flex_axis.vec2_to_flex_relative(content_min_box_size),
|
||||||
flex_axis.vec2_to_flex_relative(content_max_size),
|
flex_axis.vec2_to_flex_relative(content_max_box_size),
|
||||||
&pbm_auto_is_zero,
|
&pbm_auto_is_zero,
|
||||||
item_with_auto_cross_size_stretches_to_container_size,
|
item_with_auto_cross_size_stretches_to_container_size,
|
||||||
|item| {
|
|item| {
|
||||||
|
@ -2064,8 +2195,8 @@ impl FlexItemBox {
|
||||||
flex_context_getter(),
|
flex_context_getter(),
|
||||||
&pbm,
|
&pbm,
|
||||||
content_box_size,
|
content_box_size,
|
||||||
content_min_size.map(|v| v.auto_is(Au::zero)),
|
content_min_box_size.map(|v| v.auto_is(Au::zero)),
|
||||||
content_max_size,
|
content_max_box_size,
|
||||||
item_with_auto_cross_size_stretches_to_container_size,
|
item_with_auto_cross_size_stretches_to_container_size,
|
||||||
IntrinsicSizingMode::Size,
|
IntrinsicSizingMode::Size,
|
||||||
)
|
)
|
||||||
|
@ -2073,13 +2204,13 @@ impl FlexItemBox {
|
||||||
);
|
);
|
||||||
let content_min_size_no_auto = if cross_axis_is_item_block_axis {
|
let content_min_size_no_auto = if cross_axis_is_item_block_axis {
|
||||||
LogicalVec2 {
|
LogicalVec2 {
|
||||||
inline: content_min_size.inline.auto_is(|| automatic_min_size),
|
inline: content_min_box_size.inline.auto_is(|| automatic_min_size),
|
||||||
block: content_min_size.block.auto_is(Au::zero),
|
block: content_min_box_size.block.auto_is(Au::zero),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LogicalVec2 {
|
LogicalVec2 {
|
||||||
inline: content_min_size.inline.auto_is(Au::zero),
|
inline: content_min_box_size.inline.auto_is(Au::zero),
|
||||||
block: content_min_size.block.auto_is(|| automatic_min_size),
|
block: content_min_box_size.block.auto_is(|| automatic_min_size),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let block_content_size_callback = |item: &mut FlexItemBox| {
|
let block_content_size_callback = |item: &mut FlexItemBox| {
|
||||||
|
@ -2088,7 +2219,7 @@ impl FlexItemBox {
|
||||||
&pbm,
|
&pbm,
|
||||||
content_box_size,
|
content_box_size,
|
||||||
content_min_size_no_auto,
|
content_min_size_no_auto,
|
||||||
content_max_size,
|
content_max_box_size,
|
||||||
item_with_auto_cross_size_stretches_to_container_size,
|
item_with_auto_cross_size_stretches_to_container_size,
|
||||||
IntrinsicSizingMode::Size,
|
IntrinsicSizingMode::Size,
|
||||||
)
|
)
|
||||||
|
@ -2117,7 +2248,7 @@ impl FlexItemBox {
|
||||||
&pbm,
|
&pbm,
|
||||||
content_box_size,
|
content_box_size,
|
||||||
content_min_size_no_auto,
|
content_min_size_no_auto,
|
||||||
content_max_size,
|
content_max_box_size,
|
||||||
item_with_auto_cross_size_stretches_to_container_size,
|
item_with_auto_cross_size_stretches_to_container_size,
|
||||||
IntrinsicSizingMode::Contribution,
|
IntrinsicSizingMode::Contribution,
|
||||||
);
|
);
|
||||||
|
@ -2127,7 +2258,7 @@ impl FlexItemBox {
|
||||||
|
|
||||||
let content_box_size = flex_axis.vec2_to_flex_relative(content_box_size);
|
let content_box_size = flex_axis.vec2_to_flex_relative(content_box_size);
|
||||||
let content_min_size_no_auto = flex_axis.vec2_to_flex_relative(content_min_size_no_auto);
|
let content_min_size_no_auto = flex_axis.vec2_to_flex_relative(content_min_size_no_auto);
|
||||||
let content_max_size = flex_axis.vec2_to_flex_relative(content_max_size);
|
let content_max_size = flex_axis.vec2_to_flex_relative(content_max_box_size);
|
||||||
|
|
||||||
// TODO: when laying out a column container with an indefinite main size,
|
// TODO: when laying out a column container with an indefinite main size,
|
||||||
// we compute the base sizes of the items twice. We should consider caching.
|
// we compute the base sizes of the items twice. We should consider caching.
|
||||||
|
@ -2578,9 +2709,9 @@ impl FlexItemBox {
|
||||||
style: &non_replaced.style,
|
style: &non_replaced.style,
|
||||||
};
|
};
|
||||||
let mut content_block_size = || {
|
let mut content_block_size = || {
|
||||||
if let Some(cache) = &*self.cached_layout.borrow() {
|
if let Some(cache) = &*self.block_content_size_cache.borrow() {
|
||||||
if cache.descriptor.compatible_with_size(inline_size) {
|
if inline_size == cache.containing_block_inline_size {
|
||||||
return cache.descriptor.content_block_size;
|
return cache.content_block_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2590,14 +2721,12 @@ impl FlexItemBox {
|
||||||
&item_as_containing_block,
|
&item_as_containing_block,
|
||||||
flex_context.containing_block,
|
flex_context.containing_block,
|
||||||
);
|
);
|
||||||
|
|
||||||
let content_block_size = layout.content_block_size;
|
let content_block_size = layout.content_block_size;
|
||||||
*self.cached_layout.borrow_mut() = Some(FlexItemLayoutCache {
|
*self.block_content_size_cache.borrow_mut() =
|
||||||
descriptor: FlexItemLayoutCacheDescriptor {
|
Some(CachedBlockSizeContribution {
|
||||||
containing_block_inline_size: item_as_containing_block.inline_size,
|
containing_block_inline_size: item_as_containing_block.inline_size,
|
||||||
content_block_size: layout.content_block_size,
|
content_block_size: layout.content_block_size,
|
||||||
},
|
});
|
||||||
});
|
|
||||||
content_block_size
|
content_block_size
|
||||||
};
|
};
|
||||||
match intrinsic_sizing_mode {
|
match intrinsic_sizing_mode {
|
||||||
|
|
|
@ -117,7 +117,7 @@ pub(crate) enum FlexLevelBox {
|
||||||
pub(crate) struct FlexItemBox {
|
pub(crate) struct FlexItemBox {
|
||||||
independent_formatting_context: IndependentFormattingContext,
|
independent_formatting_context: IndependentFormattingContext,
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
cached_layout: ArcRefCell<Option<FlexItemLayoutCache>>,
|
block_content_size_cache: ArcRefCell<Option<CachedBlockSizeContribution>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for FlexItemBox {
|
impl std::fmt::Debug for FlexItemBox {
|
||||||
|
@ -136,19 +136,7 @@ impl FlexItemBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
struct CachedBlockSizeContribution {
|
||||||
struct FlexItemLayoutCacheDescriptor {
|
|
||||||
containing_block_inline_size: Au,
|
containing_block_inline_size: Au,
|
||||||
content_block_size: Au,
|
content_block_size: Au,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FlexItemLayoutCacheDescriptor {
|
|
||||||
fn compatible_with_size(&self, inline: Au) -> bool {
|
|
||||||
inline == self.containing_block_inline_size
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A cache to avoid multiple layouts during flexbox layout.
|
|
||||||
struct FlexItemLayoutCache {
|
|
||||||
descriptor: FlexItemLayoutCacheDescriptor,
|
|
||||||
}
|
|
||||||
|
|
|
@ -627,6 +627,10 @@ pub(super) struct InlineFormattingContextLayout<'layout_data> {
|
||||||
/// Whether or not this InlineFormattingContext has processed any in flow content at all.
|
/// Whether or not this InlineFormattingContext has processed any in flow content at all.
|
||||||
had_inflow_content: bool,
|
had_inflow_content: bool,
|
||||||
|
|
||||||
|
/// Whether or not the layout of this InlineFormattingContext depends on the block size
|
||||||
|
/// of its container for the purposes of flexbox layout.
|
||||||
|
depends_on_block_constraints: bool,
|
||||||
|
|
||||||
/// The currently white-space-collapse setting of this line. This is stored on the
|
/// The currently white-space-collapse setting of this line. This is stored on the
|
||||||
/// [`InlineFormattingContextLayout`] because when a soft wrap opportunity is defined
|
/// [`InlineFormattingContextLayout`] because when a soft wrap opportunity is defined
|
||||||
/// by the boundary between two characters, the white-space-collapse property of their
|
/// by the boundary between two characters, the white-space-collapse property of their
|
||||||
|
@ -701,6 +705,12 @@ impl<'layout_dta> InlineFormattingContextLayout<'layout_dta> {
|
||||||
.map(|index| &self.ifc.font_metrics[index].metrics),
|
.map(|index| &self.ifc.font_metrics[index].metrics),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.depends_on_block_constraints |= inline_box
|
||||||
|
.style
|
||||||
|
.depends_on_block_constraints_due_to_relative_positioning(
|
||||||
|
self.containing_block.style.writing_mode,
|
||||||
|
);
|
||||||
|
|
||||||
// If we are starting a `<br>` element prepare to clear after its deferred linebreak has been
|
// If we are starting a `<br>` element prepare to clear after its deferred linebreak has been
|
||||||
// processed. Note that a `<br>` is composed of the element itself and the inner pseudo-element
|
// processed. Note that a `<br>` is composed of the element itself and the inner pseudo-element
|
||||||
// with the actual linebreak. Both will have this `FragmentFlag`; that's why this code only
|
// with the actual linebreak. Both will have this `FragmentFlag`; that's why this code only
|
||||||
|
@ -1631,6 +1641,7 @@ impl InlineFormattingContext {
|
||||||
deferred_br_clear: Clear::None,
|
deferred_br_clear: Clear::None,
|
||||||
have_deferred_soft_wrap_opportunity: false,
|
have_deferred_soft_wrap_opportunity: false,
|
||||||
had_inflow_content: false,
|
had_inflow_content: false,
|
||||||
|
depends_on_block_constraints: false,
|
||||||
white_space_collapse: style_text.white_space_collapse,
|
white_space_collapse: style_text.white_space_collapse,
|
||||||
text_wrap_mode: style_text.text_wrap_mode,
|
text_wrap_mode: style_text.text_wrap_mode,
|
||||||
baselines: Baselines::default(),
|
baselines: Baselines::default(),
|
||||||
|
@ -1692,6 +1703,7 @@ impl InlineFormattingContext {
|
||||||
content_block_size,
|
content_block_size,
|
||||||
collapsible_margins_in_children,
|
collapsible_margins_in_children,
|
||||||
baselines: layout.baselines,
|
baselines: layout.baselines,
|
||||||
|
depends_on_block_constraints: layout.depends_on_block_constraints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1921,6 +1933,12 @@ impl IndependentFormattingContext {
|
||||||
layout.containing_block,
|
layout.containing_block,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// If this Fragment's layout depends on the block size of the containing block,
|
||||||
|
// then the entire layout of the inline formatting context does as well.
|
||||||
|
layout.depends_on_block_constraints |= fragment.base.flags.contains(
|
||||||
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
);
|
||||||
|
|
||||||
// Offset the content rectangle by the physical offset of the padding, border, and margin.
|
// Offset the content rectangle by the physical offset of the padding, border, and margin.
|
||||||
let container_writing_mode = layout.containing_block.style.writing_mode;
|
let container_writing_mode = layout.containing_block.style.writing_mode;
|
||||||
let pbm_physical_offset = pbm_sums
|
let pbm_physical_offset = pbm_sums
|
||||||
|
|
|
@ -38,7 +38,9 @@ use crate::geom::{
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
||||||
use crate::replaced::ReplacedContent;
|
use crate::replaced::ReplacedContent;
|
||||||
use crate::sizing::{self, ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{self, ContentSizes, InlineContentSizesResult};
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
use crate::style_ext::{
|
||||||
|
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
|
||||||
|
};
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||||
|
|
||||||
mod construct;
|
mod construct;
|
||||||
|
@ -204,6 +206,8 @@ pub(crate) struct FlowLayout {
|
||||||
/// used to propagate inflow baselines to the ancestors of `display: inline-block` elements
|
/// used to propagate inflow baselines to the ancestors of `display: inline-block` elements
|
||||||
/// and table content.
|
/// and table content.
|
||||||
pub baselines: Baselines,
|
pub baselines: Baselines,
|
||||||
|
/// Whether or not this layout depends on the block size of its containing block.
|
||||||
|
pub depends_on_block_constraints: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -348,6 +352,7 @@ impl BlockFormattingContext {
|
||||||
clearance.unwrap_or_default(),
|
clearance.unwrap_or_default(),
|
||||||
content_inline_size_for_table: None,
|
content_inline_size_for_table: None,
|
||||||
baselines: flow_layout.baselines,
|
baselines: flow_layout.baselines,
|
||||||
|
depends_on_block_constraints: flow_layout.depends_on_block_constraints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -567,12 +572,21 @@ fn layout_block_level_children(
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let depends_on_block_constraints = fragments.iter().any(|fragment| {
|
||||||
|
fragment.base().is_some_and(|base| {
|
||||||
|
base.flags.contains(
|
||||||
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish();
|
let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish();
|
||||||
FlowLayout {
|
FlowLayout {
|
||||||
fragments,
|
fragments,
|
||||||
content_block_size,
|
content_block_size,
|
||||||
collapsible_margins_in_children,
|
collapsible_margins_in_children,
|
||||||
baselines,
|
baselines,
|
||||||
|
depends_on_block_constraints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,7 +777,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
positioning_context: &mut PositioningContext,
|
positioning_context: &mut PositioningContext,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
base_fragment_info: BaseFragmentInfo,
|
mut base_fragment_info: BaseFragmentInfo,
|
||||||
style: &Arc<ComputedValues>,
|
style: &Arc<ComputedValues>,
|
||||||
contents: &BlockContainer,
|
contents: &BlockContainer,
|
||||||
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
|
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
|
||||||
|
@ -775,6 +789,7 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
|
||||||
box_size,
|
box_size,
|
||||||
min_box_size,
|
min_box_size,
|
||||||
max_box_size,
|
max_box_size,
|
||||||
|
depends_on_block_constraints,
|
||||||
} = solve_containing_block_padding_and_border_for_in_flow_box(containing_block, style);
|
} = solve_containing_block_padding_and_border_for_in_flow_box(containing_block, style);
|
||||||
let ResolvedMargins {
|
let ResolvedMargins {
|
||||||
margin,
|
margin,
|
||||||
|
@ -954,6 +969,12 @@ fn layout_in_flow_non_replaced_block_level_same_formatting_context(
|
||||||
};
|
};
|
||||||
|
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||||
|
if depends_on_block_constraints {
|
||||||
|
base_fragment_info
|
||||||
|
.flags
|
||||||
|
.insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM);
|
||||||
|
}
|
||||||
|
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
base_fragment_info,
|
base_fragment_info,
|
||||||
style.clone(),
|
style.clone(),
|
||||||
|
@ -996,6 +1017,7 @@ impl NonReplacedFormattingContext {
|
||||||
box_size,
|
box_size,
|
||||||
min_box_size,
|
min_box_size,
|
||||||
max_box_size,
|
max_box_size,
|
||||||
|
depends_on_block_constraints,
|
||||||
} = solve_containing_block_padding_and_border_for_in_flow_box(
|
} = solve_containing_block_padding_and_border_for_in_flow_box(
|
||||||
containing_block,
|
containing_block,
|
||||||
&self.style,
|
&self.style,
|
||||||
|
@ -1039,8 +1061,15 @@ impl NonReplacedFormattingContext {
|
||||||
|
|
||||||
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||||
|
|
||||||
|
let mut base_fragment_info = self.base_fragment_info;
|
||||||
|
if depends_on_block_constraints {
|
||||||
|
base_fragment_info.flags.insert(
|
||||||
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
self.base_fragment_info,
|
base_fragment_info,
|
||||||
self.style.clone(),
|
self.style.clone(),
|
||||||
layout.fragments,
|
layout.fragments,
|
||||||
content_rect.to_physical(Some(containing_block)),
|
content_rect.to_physical(Some(containing_block)),
|
||||||
|
@ -1063,19 +1092,21 @@ impl NonReplacedFormattingContext {
|
||||||
containing_block: &ContainingBlock<'_>,
|
containing_block: &ContainingBlock<'_>,
|
||||||
sequential_layout_state: &mut SequentialLayoutState,
|
sequential_layout_state: &mut SequentialLayoutState,
|
||||||
) -> BoxFragment {
|
) -> BoxFragment {
|
||||||
let pbm = self.style.padding_border_margin(containing_block);
|
let ContentBoxSizesAndPBMDeprecated {
|
||||||
let box_size = self
|
content_box_size,
|
||||||
|
content_min_box_size,
|
||||||
|
content_max_box_size,
|
||||||
|
pbm,
|
||||||
|
depends_on_block_constraints,
|
||||||
|
} = self
|
||||||
.style
|
.style
|
||||||
.content_box_size_deprecated(containing_block, &pbm);
|
.content_box_sizes_and_padding_border_margin(&containing_block.into())
|
||||||
let max_box_size = self
|
.into();
|
||||||
.style
|
let content_min_box_size = content_min_box_size.auto_is(Au::zero);
|
||||||
.content_max_box_size_deprecated(containing_block, &pbm);
|
|
||||||
let min_box_size = self
|
let block_size = content_box_size.block.map(|block_size| {
|
||||||
.style
|
block_size
|
||||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
.clamp_between_extremums(content_min_box_size.block, content_max_box_size.block)
|
||||||
.auto_is(Au::zero);
|
|
||||||
let block_size = box_size.block.map(|block_size| {
|
|
||||||
block_size.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let margin_inline_start;
|
let margin_inline_start;
|
||||||
|
@ -1098,9 +1129,9 @@ impl NonReplacedFormattingContext {
|
||||||
let clearance;
|
let clearance;
|
||||||
let mut content_size;
|
let mut content_size;
|
||||||
let mut layout;
|
let mut layout;
|
||||||
if let AuOrAuto::LengthPercentage(ref inline_size) = box_size.inline {
|
if let AuOrAuto::LengthPercentage(ref inline_size) = content_box_size.inline {
|
||||||
let inline_size =
|
let inline_size = inline_size
|
||||||
inline_size.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
|
.clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline);
|
||||||
layout = self.layout(
|
layout = self.layout(
|
||||||
layout_context,
|
layout_context,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
|
@ -1120,9 +1151,10 @@ impl NonReplacedFormattingContext {
|
||||||
} else {
|
} else {
|
||||||
content_size = LogicalVec2 {
|
content_size = LogicalVec2 {
|
||||||
block: block_size.auto_is(|| {
|
block: block_size.auto_is(|| {
|
||||||
layout
|
layout.content_block_size.clamp_between_extremums(
|
||||||
.content_block_size
|
content_min_box_size.block,
|
||||||
.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
content_max_box_size.block,
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
inline: inline_size,
|
inline: inline_size,
|
||||||
};
|
};
|
||||||
|
@ -1154,8 +1186,8 @@ impl NonReplacedFormattingContext {
|
||||||
|
|
||||||
// Create a PlacementAmongFloats using the minimum size in all dimensions as the object size.
|
// Create a PlacementAmongFloats using the minimum size in all dimensions as the object size.
|
||||||
let minimum_size_of_block = LogicalVec2 {
|
let minimum_size_of_block = LogicalVec2 {
|
||||||
inline: min_box_size.inline,
|
inline: content_min_box_size.inline,
|
||||||
block: block_size.auto_is(|| min_box_size.block),
|
block: block_size.auto_is(|| content_min_box_size.block),
|
||||||
} + pbm.padding_border_sums;
|
} + pbm.padding_border_sums;
|
||||||
let mut placement = PlacementAmongFloats::new(
|
let mut placement = PlacementAmongFloats::new(
|
||||||
&sequential_layout_state.floats,
|
&sequential_layout_state.floats,
|
||||||
|
@ -1170,7 +1202,10 @@ impl NonReplacedFormattingContext {
|
||||||
placement_rect = placement.place();
|
placement_rect = placement.place();
|
||||||
let proposed_inline_size = (placement_rect.size.inline -
|
let proposed_inline_size = (placement_rect.size.inline -
|
||||||
pbm.padding_border_sums.inline)
|
pbm.padding_border_sums.inline)
|
||||||
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
|
.clamp_between_extremums(
|
||||||
|
content_min_box_size.inline,
|
||||||
|
content_max_box_size.inline,
|
||||||
|
);
|
||||||
|
|
||||||
// Now lay out the block using the inline size we calculated from the placement.
|
// Now lay out the block using the inline size we calculated from the placement.
|
||||||
// Later we'll check to see if the resulting block size is compatible with the
|
// Later we'll check to see if the resulting block size is compatible with the
|
||||||
|
@ -1208,9 +1243,10 @@ impl NonReplacedFormattingContext {
|
||||||
} else {
|
} else {
|
||||||
content_size = LogicalVec2 {
|
content_size = LogicalVec2 {
|
||||||
block: block_size.auto_is(|| {
|
block: block_size.auto_is(|| {
|
||||||
layout
|
layout.content_block_size.clamp_between_extremums(
|
||||||
.content_block_size
|
content_min_box_size.block,
|
||||||
.clamp_between_extremums(min_box_size.block, max_box_size.block)
|
content_max_box_size.block,
|
||||||
|
)
|
||||||
}),
|
}),
|
||||||
inline: proposed_inline_size,
|
inline: proposed_inline_size,
|
||||||
};
|
};
|
||||||
|
@ -1289,11 +1325,17 @@ impl NonReplacedFormattingContext {
|
||||||
},
|
},
|
||||||
size: content_size,
|
size: content_size,
|
||||||
};
|
};
|
||||||
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
|
||||||
|
let mut base_fragment_info = self.base_fragment_info;
|
||||||
|
if depends_on_block_constraints {
|
||||||
|
base_fragment_info.flags.insert(
|
||||||
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
self.base_fragment_info,
|
base_fragment_info,
|
||||||
self.style.clone(),
|
self.style.clone(),
|
||||||
layout.fragments,
|
layout.fragments,
|
||||||
content_rect.to_physical(Some(containing_block)),
|
content_rect.to_physical(Some(containing_block)),
|
||||||
|
@ -1301,7 +1343,7 @@ impl NonReplacedFormattingContext {
|
||||||
pbm.border.to_physical(containing_block_writing_mode),
|
pbm.border.to_physical(containing_block_writing_mode),
|
||||||
margin.to_physical(containing_block_writing_mode),
|
margin.to_physical(containing_block_writing_mode),
|
||||||
clearance,
|
clearance,
|
||||||
block_margins_collapsed_with_children,
|
CollapsedBlockMargins::from_margin(&margin),
|
||||||
)
|
)
|
||||||
.with_baselines(layout.baselines)
|
.with_baselines(layout.baselines)
|
||||||
}
|
}
|
||||||
|
@ -1312,18 +1354,25 @@ impl NonReplacedFormattingContext {
|
||||||
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
|
/// <https://drafts.csswg.org/css2/visudet.html#inline-replaced-height>
|
||||||
fn layout_in_flow_replaced_block_level(
|
fn layout_in_flow_replaced_block_level(
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
base_fragment_info: BaseFragmentInfo,
|
mut base_fragment_info: BaseFragmentInfo,
|
||||||
style: &Arc<ComputedValues>,
|
style: &Arc<ComputedValues>,
|
||||||
replaced: &ReplacedContent,
|
replaced: &ReplacedContent,
|
||||||
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
|
mut sequential_layout_state: Option<&mut SequentialLayoutState>,
|
||||||
) -> BoxFragment {
|
) -> BoxFragment {
|
||||||
let pbm = style.padding_border_margin(containing_block);
|
let content_box_sizes_and_pbm: ContentBoxSizesAndPBMDeprecated = style
|
||||||
let content_size = replaced.used_size_as_if_inline_element(containing_block, style, &pbm);
|
.content_box_sizes_and_padding_border_margin(&containing_block.into())
|
||||||
|
.into();
|
||||||
|
let pbm = &content_box_sizes_and_pbm.pbm;
|
||||||
|
let content_size = replaced.used_size_as_if_inline_element(
|
||||||
|
containing_block,
|
||||||
|
style,
|
||||||
|
&content_box_sizes_and_pbm,
|
||||||
|
);
|
||||||
|
|
||||||
let margin_inline_start;
|
let margin_inline_start;
|
||||||
let margin_inline_end;
|
let margin_inline_end;
|
||||||
let effective_margin_inline_start;
|
let effective_margin_inline_start;
|
||||||
let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(&pbm);
|
let (margin_block_start, margin_block_end) = solve_block_margins_for_in_flow_block_level(pbm);
|
||||||
|
|
||||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||||
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
|
let physical_content_size = content_size.to_physical_size(containing_block_writing_mode);
|
||||||
|
@ -1351,7 +1400,7 @@ fn layout_in_flow_replaced_block_level(
|
||||||
sequential_layout_state,
|
sequential_layout_state,
|
||||||
&collapsed_margin_block_start,
|
&collapsed_margin_block_start,
|
||||||
containing_block,
|
containing_block,
|
||||||
&pbm,
|
pbm,
|
||||||
size,
|
size,
|
||||||
style,
|
style,
|
||||||
);
|
);
|
||||||
|
@ -1375,7 +1424,7 @@ fn layout_in_flow_replaced_block_level(
|
||||||
effective_margin_inline_start,
|
effective_margin_inline_start,
|
||||||
) = solve_inline_margins_for_in_flow_block_level(
|
) = solve_inline_margins_for_in_flow_block_level(
|
||||||
containing_block,
|
containing_block,
|
||||||
&pbm,
|
pbm,
|
||||||
content_size.inline,
|
content_size.inline,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1399,7 +1448,11 @@ fn layout_in_flow_replaced_block_level(
|
||||||
}
|
}
|
||||||
.to_physical(Some(containing_block));
|
.to_physical(Some(containing_block));
|
||||||
|
|
||||||
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
|
if content_box_sizes_and_pbm.depends_on_block_constraints {
|
||||||
|
base_fragment_info
|
||||||
|
.flags
|
||||||
|
.insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM);
|
||||||
|
}
|
||||||
|
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
base_fragment_info,
|
base_fragment_info,
|
||||||
|
@ -1410,7 +1463,7 @@ fn layout_in_flow_replaced_block_level(
|
||||||
pbm.border.to_physical(containing_block_writing_mode),
|
pbm.border.to_physical(containing_block_writing_mode),
|
||||||
margin.to_physical(containing_block_writing_mode),
|
margin.to_physical(containing_block_writing_mode),
|
||||||
clearance,
|
clearance,
|
||||||
block_margins_collapsed_with_children,
|
CollapsedBlockMargins::from_margin(&margin),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1420,6 +1473,7 @@ struct ContainingBlockPaddingAndBorder<'a> {
|
||||||
box_size: LogicalVec2<AuOrAuto>,
|
box_size: LogicalVec2<AuOrAuto>,
|
||||||
min_box_size: LogicalVec2<Au>,
|
min_box_size: LogicalVec2<Au>,
|
||||||
max_box_size: LogicalVec2<Option<Au>>,
|
max_box_size: LogicalVec2<Option<Au>>,
|
||||||
|
depends_on_block_constraints: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ResolvedMargins {
|
struct ResolvedMargins {
|
||||||
|
@ -1464,19 +1518,24 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
},
|
},
|
||||||
min_box_size: LogicalVec2::default(),
|
min_box_size: LogicalVec2::default(),
|
||||||
max_box_size: LogicalVec2::default(),
|
max_box_size: LogicalVec2::default(),
|
||||||
|
depends_on_block_constraints: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let pbm = style.padding_border_margin(containing_block);
|
let ContentBoxSizesAndPBMDeprecated {
|
||||||
let box_size = style.content_box_size_deprecated(containing_block, &pbm);
|
content_box_size,
|
||||||
let max_box_size = style.content_max_box_size_deprecated(containing_block, &pbm);
|
content_min_box_size,
|
||||||
let min_box_size = style
|
content_max_box_size,
|
||||||
.content_min_box_size_deprecated(containing_block, &pbm)
|
pbm,
|
||||||
.auto_is(Au::zero);
|
depends_on_block_constraints,
|
||||||
|
} = style
|
||||||
|
.content_box_sizes_and_padding_border_margin(&containing_block.into())
|
||||||
|
.into();
|
||||||
|
let content_min_box_size = content_min_box_size.auto_is(Au::zero);
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/#the-width-property
|
// https://drafts.csswg.org/css2/#the-width-property
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
||||||
let inline_size = box_size
|
let inline_size = content_box_size
|
||||||
.inline
|
.inline
|
||||||
.auto_is(|| {
|
.auto_is(|| {
|
||||||
let margin_inline_start = pbm.margin.inline_start.auto_is(Au::zero);
|
let margin_inline_start = pbm.margin.inline_start.auto_is(Au::zero);
|
||||||
|
@ -1486,13 +1545,14 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
margin_inline_start -
|
margin_inline_start -
|
||||||
margin_inline_end
|
margin_inline_end
|
||||||
})
|
})
|
||||||
.clamp_between_extremums(min_box_size.inline, max_box_size.inline);
|
.clamp_between_extremums(content_min_box_size.inline, content_max_box_size.inline);
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/#the-height-property
|
// https://drafts.csswg.org/css2/#the-height-property
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
|
// https://drafts.csswg.org/css2/visudet.html#min-max-heights
|
||||||
let mut block_size = box_size.block;
|
let mut block_size = content_box_size.block;
|
||||||
if let AuOrAuto::LengthPercentage(ref mut block_size) = block_size {
|
if let AuOrAuto::LengthPercentage(ref mut block_size) = block_size {
|
||||||
*block_size = block_size.clamp_between_extremums(min_box_size.block, max_box_size.block);
|
*block_size = block_size
|
||||||
|
.clamp_between_extremums(content_min_box_size.block, content_max_box_size.block);
|
||||||
}
|
}
|
||||||
|
|
||||||
let containing_block_for_children = ContainingBlock {
|
let containing_block_for_children = ContainingBlock {
|
||||||
|
@ -1512,9 +1572,10 @@ fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
|
||||||
ContainingBlockPaddingAndBorder {
|
ContainingBlockPaddingAndBorder {
|
||||||
containing_block: containing_block_for_children,
|
containing_block: containing_block_for_children,
|
||||||
pbm,
|
pbm,
|
||||||
box_size,
|
box_size: content_box_size,
|
||||||
min_box_size,
|
min_box_size: content_min_box_size,
|
||||||
max_box_size,
|
max_box_size: content_max_box_size,
|
||||||
|
depends_on_block_constraints,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1942,7 +2003,9 @@ impl IndependentFormattingContext {
|
||||||
) -> IndependentLayoutResult {
|
) -> IndependentLayoutResult {
|
||||||
let style = self.style();
|
let style = self.style();
|
||||||
let container_writing_mode = containing_block.style.writing_mode;
|
let container_writing_mode = containing_block.style.writing_mode;
|
||||||
let pbm = style.padding_border_margin(containing_block);
|
let content_box_sizes_and_pbm =
|
||||||
|
style.content_box_sizes_and_padding_border_margin(&containing_block.into());
|
||||||
|
let pbm = &content_box_sizes_and_pbm.pbm;
|
||||||
let margin = pbm.margin.auto_is(Au::zero);
|
let margin = pbm.margin.auto_is(Au::zero);
|
||||||
let pbm_sums = pbm.padding + pbm.border + margin;
|
let pbm_sums = pbm.padding + pbm.border + margin;
|
||||||
|
|
||||||
|
@ -1952,7 +2015,11 @@ impl IndependentFormattingContext {
|
||||||
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
|
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
|
||||||
let content_size = replaced
|
let content_size = replaced
|
||||||
.contents
|
.contents
|
||||||
.used_size_as_if_inline_element(containing_block, &replaced.style, &pbm)
|
.used_size_as_if_inline_element(
|
||||||
|
containing_block,
|
||||||
|
&replaced.style,
|
||||||
|
&content_box_sizes_and_pbm.clone().into(),
|
||||||
|
)
|
||||||
.to_physical_size(container_writing_mode);
|
.to_physical_size(container_writing_mode);
|
||||||
let fragments = replaced.contents.make_fragments(
|
let fragments = replaced.contents.make_fragments(
|
||||||
&replaced.style,
|
&replaced.style,
|
||||||
|
@ -1965,25 +2032,24 @@ impl IndependentFormattingContext {
|
||||||
},
|
},
|
||||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||||
let style = non_replaced.style.clone();
|
let style = non_replaced.style.clone();
|
||||||
let box_size = style.content_box_size(containing_block, &pbm);
|
|
||||||
let max_box_size = style.content_max_box_size(containing_block, &pbm);
|
|
||||||
let min_box_size = style.content_min_box_size(containing_block, &pbm);
|
|
||||||
|
|
||||||
let available_inline_size =
|
let available_inline_size =
|
||||||
(containing_block.inline_size - pbm_sums.inline_sum()).max(Au::zero());
|
(containing_block.inline_size - pbm_sums.inline_sum()).max(Au::zero());
|
||||||
let available_block_size = containing_block
|
let available_block_size = containing_block
|
||||||
.block_size
|
.block_size
|
||||||
.non_auto()
|
.non_auto()
|
||||||
.map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero()));
|
.map(|block_size| (block_size - pbm_sums.block_sum()).max(Au::zero()));
|
||||||
let tentative_block_size = box_size
|
let tentative_block_size = content_box_sizes_and_pbm
|
||||||
|
.content_box_size
|
||||||
.block
|
.block
|
||||||
.maybe_resolve_extrinsic(available_block_size)
|
.maybe_resolve_extrinsic(available_block_size)
|
||||||
.map(|size| {
|
.map(|size| {
|
||||||
let min_block_size = min_box_size
|
let min_block_size = content_box_sizes_and_pbm
|
||||||
|
.content_min_box_size
|
||||||
.block
|
.block
|
||||||
.maybe_resolve_extrinsic(available_block_size)
|
.maybe_resolve_extrinsic(available_block_size)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let max_block_size = max_box_size
|
let max_block_size = content_box_sizes_and_pbm
|
||||||
|
.content_max_box_size
|
||||||
.block
|
.block
|
||||||
.maybe_resolve_extrinsic(available_block_size);
|
.maybe_resolve_extrinsic(available_block_size);
|
||||||
size.clamp_between_extremums(min_block_size, max_block_size)
|
size.clamp_between_extremums(min_block_size, max_block_size)
|
||||||
|
@ -2003,20 +2069,23 @@ impl IndependentFormattingContext {
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/visudet.html#float-width
|
// https://drafts.csswg.org/css2/visudet.html#float-width
|
||||||
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
|
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
|
||||||
let tentative_inline_size = box_size.inline.resolve(
|
let tentative_inline_size =
|
||||||
Size::FitContent,
|
content_box_sizes_and_pbm.content_box_size.inline.resolve(
|
||||||
available_inline_size,
|
Size::FitContent,
|
||||||
&mut get_content_size,
|
available_inline_size,
|
||||||
);
|
&mut get_content_size,
|
||||||
|
);
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
||||||
// In this case “applying the rules above again” with a non-auto inline-size
|
// In this case “applying the rules above again” with a non-auto inline-size
|
||||||
// always results in that size.
|
// always results in that size.
|
||||||
let min_inline_size = min_box_size
|
let min_inline_size = content_box_sizes_and_pbm
|
||||||
|
.content_min_box_size
|
||||||
.inline
|
.inline
|
||||||
.resolve_non_initial(available_inline_size, &mut get_content_size)
|
.resolve_non_initial(available_inline_size, &mut get_content_size)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let max_inline_size = max_box_size
|
let max_inline_size = content_box_sizes_and_pbm
|
||||||
|
.content_max_box_size
|
||||||
.inline
|
.inline
|
||||||
.resolve_non_initial(available_inline_size, &mut get_content_size);
|
.resolve_non_initial(available_inline_size, &mut get_content_size);
|
||||||
let inline_size =
|
let inline_size =
|
||||||
|
@ -2048,11 +2117,13 @@ impl IndependentFormattingContext {
|
||||||
let stretch_size =
|
let stretch_size =
|
||||||
available_block_size.unwrap_or(independent_layout.content_block_size);
|
available_block_size.unwrap_or(independent_layout.content_block_size);
|
||||||
let mut get_content_size = || independent_layout.content_block_size.into();
|
let mut get_content_size = || independent_layout.content_block_size.into();
|
||||||
let min_block_size = min_box_size
|
let min_block_size = content_box_sizes_and_pbm
|
||||||
|
.content_min_box_size
|
||||||
.block
|
.block
|
||||||
.resolve_non_initial(stretch_size, &mut get_content_size)
|
.resolve_non_initial(stretch_size, &mut get_content_size)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let max_block_size = max_box_size
|
let max_block_size = content_box_sizes_and_pbm
|
||||||
|
.content_max_box_size
|
||||||
.block
|
.block
|
||||||
.resolve_non_initial(stretch_size, &mut get_content_size);
|
.resolve_non_initial(stretch_size, &mut get_content_size);
|
||||||
let block_size = tentative_block_size
|
let block_size = tentative_block_size
|
||||||
|
@ -2077,8 +2148,15 @@ impl IndependentFormattingContext {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut base_fragment_info = self.base_fragment_info();
|
||||||
|
if content_box_sizes_and_pbm.depends_on_block_constraints {
|
||||||
|
base_fragment_info.flags.insert(
|
||||||
|
FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let fragment = BoxFragment::new(
|
let fragment = BoxFragment::new(
|
||||||
self.base_fragment_info(),
|
base_fragment_info,
|
||||||
self.style().clone(),
|
self.style().clone(),
|
||||||
fragments,
|
fragments,
|
||||||
content_rect,
|
content_rect,
|
||||||
|
|
|
@ -90,6 +90,9 @@ pub(crate) struct IndependentLayout {
|
||||||
/// there was one. This is used to propagate baselines to the ancestors of `display:
|
/// there was one. This is used to propagate baselines to the ancestors of `display:
|
||||||
/// inline-block`.
|
/// inline-block`.
|
||||||
pub baselines: Baselines,
|
pub baselines: Baselines,
|
||||||
|
|
||||||
|
/// Whether or not this layout depends on the containing block size.
|
||||||
|
pub depends_on_block_constraints: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct IndependentLayoutResult {
|
pub(crate) struct IndependentLayoutResult {
|
||||||
|
|
|
@ -104,6 +104,10 @@ bitflags! {
|
||||||
/// for empty table cells when 'empty-cells' is 'hide' and also table wrappers. This flag
|
/// for empty table cells when 'empty-cells' is 'hide' and also table wrappers. This flag
|
||||||
/// doesn't avoid hit-testing nor does it prevent the painting outlines.
|
/// doesn't avoid hit-testing nor does it prevent the painting outlines.
|
||||||
const DO_NOT_PAINT = 1 << 6;
|
const DO_NOT_PAINT = 1 << 6;
|
||||||
|
/// Whether or not the size of this fragment depends on the block size of its container
|
||||||
|
/// and the fragment can be a flex item. This flag is used to cache items during flex
|
||||||
|
/// layout.
|
||||||
|
const SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM = 1 << 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -459,9 +459,15 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
IndependentFormattingContext::Replaced(replaced) => {
|
IndependentFormattingContext::Replaced(replaced) => {
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
|
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-width
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
|
// https://drafts.csswg.org/css2/visudet.html#abs-replaced-height
|
||||||
|
let content_box_sizes_and_pbm =
|
||||||
|
style.content_box_sizes_and_padding_border_margin(&containing_block.into());
|
||||||
let used_size = replaced
|
let used_size = replaced
|
||||||
.contents
|
.contents
|
||||||
.used_size_as_if_inline_element(containing_block, &style, &pbm)
|
.used_size_as_if_inline_element(
|
||||||
|
containing_block,
|
||||||
|
&style,
|
||||||
|
&content_box_sizes_and_pbm.into(),
|
||||||
|
)
|
||||||
.map(|size| Size::Numeric(*size));
|
.map(|size| Size::Numeric(*size));
|
||||||
(used_size, Default::default(), Default::default())
|
(used_size, Default::default(), Default::default())
|
||||||
},
|
},
|
||||||
|
@ -477,7 +483,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
.static_position_rect
|
.static_position_rect
|
||||||
.to_logical(containing_block);
|
.to_logical(containing_block);
|
||||||
|
|
||||||
let box_offset = style.box_offsets(containing_block);
|
let box_offset = style.box_offsets(containing_block.style.writing_mode);
|
||||||
|
|
||||||
// When the "static-position rect" doesn't come into play, we do not do any alignment
|
// When the "static-position rect" doesn't come into play, we do not do any alignment
|
||||||
// in the inline axis.
|
// in the inline axis.
|
||||||
|
@ -982,7 +988,7 @@ pub(crate) fn relative_adjustement(
|
||||||
let cbis = containing_block.inline_size;
|
let cbis = containing_block.inline_size;
|
||||||
let cbbs = containing_block.block_size;
|
let cbbs = containing_block.block_size;
|
||||||
let box_offsets = style
|
let box_offsets = style
|
||||||
.box_offsets(containing_block)
|
.box_offsets(containing_block.style.writing_mode)
|
||||||
.map_inline_and_block_axes(
|
.map_inline_and_block_axes(
|
||||||
|value| value.map(|value| value.to_used_value(cbis)),
|
|value| value.map(|value| value.to_used_value(cbis)),
|
||||||
|value| match cbbs.non_auto() {
|
|value| match cbbs.non_auto() {
|
||||||
|
|
|
@ -30,7 +30,7 @@ use crate::dom::NodeExt;
|
||||||
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
|
use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFragment};
|
||||||
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize};
|
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize};
|
||||||
use crate::sizing::InlineContentSizesResult;
|
use crate::sizing::InlineContentSizesResult;
|
||||||
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, PaddingBorderMargin};
|
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated};
|
||||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
|
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
@ -430,24 +430,22 @@ impl ReplacedContent {
|
||||||
&self,
|
&self,
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
style: &ComputedValues,
|
style: &ComputedValues,
|
||||||
pbm: &PaddingBorderMargin,
|
content_box_sizes_and_pbm: &ContentBoxSizesAndPBMDeprecated,
|
||||||
) -> LogicalVec2<Au> {
|
) -> LogicalVec2<Au> {
|
||||||
let box_size = style
|
// We need to clamp to zero here to obtain the proper aspect ratio when box-sizing
|
||||||
.content_box_size_deprecated(containing_block, pbm)
|
// is border-box and the inner box size would otherwise be negative.
|
||||||
// We need to clamp to zero here to obtain the proper aspect
|
let content_box_size = content_box_sizes_and_pbm
|
||||||
// ratio when box-sizing is border-box and the inner box size
|
.content_box_size
|
||||||
// would otherwise be negative.
|
|
||||||
.map(|value| value.map(|value| value.max(Au::zero())));
|
.map(|value| value.map(|value| value.max(Au::zero())));
|
||||||
let min_box_size = style
|
let content_min_box_size = content_box_sizes_and_pbm
|
||||||
.content_min_box_size_deprecated(containing_block, pbm)
|
.content_min_box_size
|
||||||
.auto_is(Au::zero);
|
.auto_is(Au::zero);
|
||||||
let max_box_size = style.content_max_box_size_deprecated(containing_block, pbm);
|
|
||||||
self.used_size_as_if_inline_element_from_content_box_sizes(
|
self.used_size_as_if_inline_element_from_content_box_sizes(
|
||||||
containing_block,
|
containing_block,
|
||||||
style,
|
style,
|
||||||
box_size,
|
content_box_size,
|
||||||
min_box_size,
|
content_min_box_size,
|
||||||
max_box_size,
|
content_box_sizes_and_pbm.content_max_box_size,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ use serde::Serialize;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::Zero;
|
use style::Zero;
|
||||||
|
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt};
|
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated};
|
||||||
use crate::{AuOrAuto, IndefiniteContainingBlock, LogicalVec2};
|
use crate::{AuOrAuto, IndefiniteContainingBlock, LogicalVec2};
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
|
@ -120,21 +120,24 @@ pub(crate) fn outer_inline(
|
||||||
auto_block_size_stretches_to_containing_block: bool,
|
auto_block_size_stretches_to_containing_block: bool,
|
||||||
get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> InlineContentSizesResult,
|
get_content_size: impl FnOnce(&IndefiniteContainingBlock) -> InlineContentSizesResult,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
let (
|
let ContentBoxSizesAndPBMDeprecated {
|
||||||
content_box_size,
|
content_box_size,
|
||||||
content_min_size,
|
content_min_box_size,
|
||||||
content_max_size,
|
content_max_box_size,
|
||||||
pbm,
|
pbm,
|
||||||
mut depends_on_block_constraints,
|
mut depends_on_block_constraints,
|
||||||
) = style.content_box_sizes_and_padding_border_margin_deprecated(containing_block);
|
} = style
|
||||||
let content_min_size = LogicalVec2 {
|
.content_box_sizes_and_padding_border_margin(containing_block)
|
||||||
inline: content_min_size.inline.auto_is(|| auto_minimum.inline),
|
.into();
|
||||||
block: content_min_size.block.auto_is(|| auto_minimum.block),
|
let content_box_min_size = LogicalVec2 {
|
||||||
|
inline: content_min_box_size.inline.auto_is(|| auto_minimum.inline),
|
||||||
|
block: content_min_box_size.block.auto_is(|| auto_minimum.block),
|
||||||
};
|
};
|
||||||
let margin = pbm.margin.map(|v| v.auto_is(Au::zero));
|
let margin = pbm.margin.map(|v| v.auto_is(Au::zero));
|
||||||
let pbm_inline_sum = pbm.padding_border_sums.inline + margin.inline_sum();
|
let pbm_inline_sum = pbm.padding_border_sums.inline + margin.inline_sum();
|
||||||
let adjust = |v: Au| {
|
let adjust = |v: Au| {
|
||||||
v.clamp_between_extremums(content_min_size.inline, content_max_size.inline) + pbm_inline_sum
|
v.clamp_between_extremums(content_box_min_size.inline, content_max_box_size.inline) +
|
||||||
|
pbm_inline_sum
|
||||||
};
|
};
|
||||||
match content_box_size.inline {
|
match content_box_size.inline {
|
||||||
AuOrAuto::LengthPercentage(inline_size) => InlineContentSizesResult {
|
AuOrAuto::LengthPercentage(inline_size) => InlineContentSizesResult {
|
||||||
|
@ -151,7 +154,9 @@ pub(crate) fn outer_inline(
|
||||||
} else {
|
} else {
|
||||||
content_box_size.block
|
content_box_size.block
|
||||||
}
|
}
|
||||||
.map(|v| v.clamp_between_extremums(content_min_size.block, content_max_size.block));
|
.map(|v| {
|
||||||
|
v.clamp_between_extremums(content_box_min_size.block, content_max_box_size.block)
|
||||||
|
});
|
||||||
let containing_block_for_children =
|
let containing_block_for_children =
|
||||||
IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size);
|
IndefiniteContainingBlock::new_for_style_and_block_size(style, block_size);
|
||||||
let content_result = get_content_size(&containing_block_for_children);
|
let content_result = get_content_size(&containing_block_for_children);
|
||||||
|
|
|
@ -179,12 +179,38 @@ impl AspectRatio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct ContentBoxSizesAndPBM {
|
||||||
|
pub content_box_size: LogicalVec2<Size<Au>>,
|
||||||
|
pub content_min_box_size: LogicalVec2<Size<Au>>,
|
||||||
|
pub content_max_box_size: LogicalVec2<Size<Au>>,
|
||||||
|
pub pbm: PaddingBorderMargin,
|
||||||
|
pub depends_on_block_constraints: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ContentBoxSizesAndPBM> for ContentBoxSizesAndPBMDeprecated {
|
||||||
|
fn from(sizes: ContentBoxSizesAndPBM) -> Self {
|
||||||
|
Self {
|
||||||
|
content_box_size: sizes.content_box_size.map(Size::to_auto_or),
|
||||||
|
content_min_box_size: sizes.content_min_box_size.map(Size::to_auto_or),
|
||||||
|
content_max_box_size: sizes.content_max_box_size.map(Size::to_numeric),
|
||||||
|
pbm: sizes.pbm.clone(),
|
||||||
|
depends_on_block_constraints: sizes.depends_on_block_constraints,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct ContentBoxSizesAndPBMDeprecated {
|
||||||
|
pub content_box_size: LogicalVec2<AuOrAuto>,
|
||||||
|
pub content_min_box_size: LogicalVec2<AuOrAuto>,
|
||||||
|
pub content_max_box_size: LogicalVec2<Option<Au>>,
|
||||||
|
pub pbm: PaddingBorderMargin,
|
||||||
|
pub depends_on_block_constraints: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) trait ComputedValuesExt {
|
pub(crate) trait ComputedValuesExt {
|
||||||
fn physical_box_offsets(&self) -> PhysicalSides<LengthPercentageOrAuto<'_>>;
|
fn physical_box_offsets(&self) -> PhysicalSides<LengthPercentageOrAuto<'_>>;
|
||||||
fn box_offsets(
|
fn box_offsets(&self, writing_mode: WritingMode) -> LogicalSides<LengthPercentageOrAuto<'_>>;
|
||||||
&self,
|
|
||||||
containing_block: &ContainingBlock,
|
|
||||||
) -> LogicalSides<LengthPercentageOrAuto<'_>>;
|
|
||||||
fn box_size(
|
fn box_size(
|
||||||
&self,
|
&self,
|
||||||
containing_block_writing_mode: WritingMode,
|
containing_block_writing_mode: WritingMode,
|
||||||
|
@ -242,27 +268,10 @@ pub(crate) trait ComputedValuesExt {
|
||||||
box_size: LogicalVec2<Size<Au>>,
|
box_size: LogicalVec2<Size<Au>>,
|
||||||
pbm: &PaddingBorderMargin,
|
pbm: &PaddingBorderMargin,
|
||||||
) -> LogicalVec2<Size<Au>>;
|
) -> LogicalVec2<Size<Au>>;
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn content_box_sizes_and_padding_border_margin(
|
fn content_box_sizes_and_padding_border_margin(
|
||||||
&self,
|
&self,
|
||||||
containing_block: &IndefiniteContainingBlock,
|
containing_block: &IndefiniteContainingBlock,
|
||||||
) -> (
|
) -> ContentBoxSizesAndPBM;
|
||||||
LogicalVec2<Size<Au>>,
|
|
||||||
LogicalVec2<Size<Au>>,
|
|
||||||
LogicalVec2<Size<Au>>,
|
|
||||||
PaddingBorderMargin,
|
|
||||||
bool, /* depends_on_block_constraints */
|
|
||||||
);
|
|
||||||
fn content_box_sizes_and_padding_border_margin_deprecated(
|
|
||||||
&self,
|
|
||||||
containing_block: &IndefiniteContainingBlock,
|
|
||||||
) -> (
|
|
||||||
LogicalVec2<AuOrAuto>,
|
|
||||||
LogicalVec2<AuOrAuto>,
|
|
||||||
LogicalVec2<Option<Au>>,
|
|
||||||
PaddingBorderMargin,
|
|
||||||
bool, /* depends_on_block_constraints */
|
|
||||||
);
|
|
||||||
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin;
|
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin;
|
||||||
fn padding_border_margin_for_intrinsic_size(
|
fn padding_border_margin_for_intrinsic_size(
|
||||||
&self,
|
&self,
|
||||||
|
@ -313,6 +322,10 @@ pub(crate) trait ComputedValuesExt {
|
||||||
resolved_auto_value: AlignItems,
|
resolved_auto_value: AlignItems,
|
||||||
resolved_normal_value: AlignItems,
|
resolved_normal_value: AlignItems,
|
||||||
) -> AlignItems;
|
) -> AlignItems;
|
||||||
|
fn depends_on_block_constraints_due_to_relative_positioning(
|
||||||
|
&self,
|
||||||
|
writing_mode: WritingMode,
|
||||||
|
) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputedValuesExt for ComputedValues {
|
impl ComputedValuesExt for ComputedValues {
|
||||||
|
@ -334,14 +347,8 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_offsets(
|
fn box_offsets(&self, writing_mode: WritingMode) -> LogicalSides<LengthPercentageOrAuto<'_>> {
|
||||||
&self,
|
LogicalSides::from_physical(&self.physical_box_offsets(), writing_mode)
|
||||||
containing_block: &ContainingBlock,
|
|
||||||
) -> LogicalSides<LengthPercentageOrAuto<'_>> {
|
|
||||||
LogicalSides::from_physical(
|
|
||||||
&self.physical_box_offsets(),
|
|
||||||
containing_block.style.writing_mode,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn box_size(
|
fn box_size(
|
||||||
|
@ -500,13 +507,7 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
fn content_box_sizes_and_padding_border_margin(
|
fn content_box_sizes_and_padding_border_margin(
|
||||||
&self,
|
&self,
|
||||||
containing_block: &IndefiniteContainingBlock,
|
containing_block: &IndefiniteContainingBlock,
|
||||||
) -> (
|
) -> ContentBoxSizesAndPBM {
|
||||||
LogicalVec2<Size<Au>>,
|
|
||||||
LogicalVec2<Size<Au>>,
|
|
||||||
LogicalVec2<Size<Au>>,
|
|
||||||
PaddingBorderMargin,
|
|
||||||
bool, /* depends_on_block_constraints */
|
|
||||||
) {
|
|
||||||
// <https://drafts.csswg.org/css-sizing-3/#cyclic-percentage-contribution>
|
// <https://drafts.csswg.org/css-sizing-3/#cyclic-percentage-contribution>
|
||||||
// If max size properties or preferred size properties are set to a value containing
|
// If max size properties or preferred size properties are set to a value containing
|
||||||
// indefinite percentages, we treat the entire value as the initial value of the property.
|
// indefinite percentages, we treat the entire value as the initial value of the property.
|
||||||
|
@ -537,54 +538,31 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let depends_on_block_constraints = depends_on_block_constraints(&box_size.block) ||
|
let depends_on_block_constraints = depends_on_block_constraints(&box_size.block) ||
|
||||||
depends_on_block_constraints(&min_size.block) ||
|
depends_on_block_constraints(&min_size.block) ||
|
||||||
depends_on_block_constraints(&max_size.block);
|
depends_on_block_constraints(&max_size.block) ||
|
||||||
|
self.depends_on_block_constraints_due_to_relative_positioning(writing_mode);
|
||||||
|
|
||||||
let box_size = box_size.maybe_percentages_relative_to_basis(&containing_block_size);
|
let box_size = box_size.maybe_percentages_relative_to_basis(&containing_block_size);
|
||||||
let content_box_size = self
|
let content_box_size = self
|
||||||
.content_box_size_for_box_size(box_size, &pbm)
|
.content_box_size_for_box_size(box_size, &pbm)
|
||||||
.map(|v| v.map(Au::from));
|
.map(|v| v.map(Au::from));
|
||||||
let min_size = min_size.percentages_relative_to_basis(&containing_block_size_auto_is_zero);
|
let min_size = min_size.percentages_relative_to_basis(&containing_block_size_auto_is_zero);
|
||||||
let content_min_size = self
|
let content_min_box_size = self
|
||||||
.content_min_box_size_for_min_size(min_size, &pbm)
|
.content_min_box_size_for_min_size(min_size, &pbm)
|
||||||
.map(|v| v.map(Au::from));
|
.map(|v| v.map(Au::from));
|
||||||
let max_size = max_size.maybe_percentages_relative_to_basis(&containing_block_size);
|
let max_size = max_size.maybe_percentages_relative_to_basis(&containing_block_size);
|
||||||
let content_max_size = self
|
let content_max_box_size = self
|
||||||
.content_max_box_size_for_max_size(max_size, &pbm)
|
.content_max_box_size_for_max_size(max_size, &pbm)
|
||||||
.map(|v| v.map(Au::from));
|
.map(|v| v.map(Au::from));
|
||||||
(
|
ContentBoxSizesAndPBM {
|
||||||
content_box_size,
|
content_box_size,
|
||||||
content_min_size,
|
content_min_box_size,
|
||||||
content_max_size,
|
content_max_box_size,
|
||||||
pbm,
|
pbm,
|
||||||
depends_on_block_constraints,
|
depends_on_block_constraints,
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn content_box_sizes_and_padding_border_margin_deprecated(
|
|
||||||
&self,
|
|
||||||
containing_block: &IndefiniteContainingBlock,
|
|
||||||
) -> (
|
|
||||||
LogicalVec2<AuOrAuto>,
|
|
||||||
LogicalVec2<AuOrAuto>,
|
|
||||||
LogicalVec2<Option<Au>>,
|
|
||||||
PaddingBorderMargin,
|
|
||||||
bool, /* depends_on_block_constraints */
|
|
||||||
) {
|
|
||||||
let (
|
|
||||||
content_box_size,
|
|
||||||
content_min_size,
|
|
||||||
content_max_size,
|
|
||||||
pbm,
|
|
||||||
depends_on_block_constraints,
|
|
||||||
) = self.content_box_sizes_and_padding_border_margin(containing_block);
|
|
||||||
(
|
|
||||||
content_box_size.map(Size::to_auto_or),
|
|
||||||
content_min_size.map(Size::to_auto_or),
|
|
||||||
content_max_size.map(Size::to_numeric),
|
|
||||||
pbm,
|
|
||||||
depends_on_block_constraints,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin {
|
fn padding_border_margin(&self, containing_block: &ContainingBlock) -> PaddingBorderMargin {
|
||||||
|
@ -1031,6 +1009,25 @@ impl ComputedValuesExt for ComputedValues {
|
||||||
value => AlignItems(value),
|
value => AlignItems(value),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn depends_on_block_constraints_due_to_relative_positioning(
|
||||||
|
&self,
|
||||||
|
writing_mode: WritingMode,
|
||||||
|
) -> bool {
|
||||||
|
if !matches!(
|
||||||
|
self.get_box().position,
|
||||||
|
ComputedPosition::Relative | ComputedPosition::Sticky
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let box_offsets = self.box_offsets(writing_mode);
|
||||||
|
let has_percentage = |offset: LengthPercentageOrAuto<'_>| {
|
||||||
|
offset
|
||||||
|
.non_auto()
|
||||||
|
.is_some_and(LengthPercentage::has_percentage)
|
||||||
|
};
|
||||||
|
has_percentage(box_offsets.block_start) || has_percentage(box_offsets.block_end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<stylo::Display> for Display {
|
impl From<stylo::Display> for Display {
|
||||||
|
|
|
@ -1683,11 +1683,18 @@ impl<'a> TableLayout<'a> {
|
||||||
let offset_from_wrapper = -table_pbm.padding - table_pbm.border;
|
let offset_from_wrapper = -table_pbm.padding - table_pbm.border;
|
||||||
let mut current_block_offset = offset_from_wrapper.block_start;
|
let mut current_block_offset = offset_from_wrapper.block_start;
|
||||||
|
|
||||||
|
let depends_on_block_constraints = self
|
||||||
|
.table
|
||||||
|
.style
|
||||||
|
.content_box_sizes_and_padding_border_margin(&containing_block_for_table.into())
|
||||||
|
.depends_on_block_constraints;
|
||||||
|
|
||||||
let mut table_layout = IndependentLayout {
|
let mut table_layout = IndependentLayout {
|
||||||
fragments: Vec::new(),
|
fragments: Vec::new(),
|
||||||
content_block_size: Zero::zero(),
|
content_block_size: Zero::zero(),
|
||||||
content_inline_size_for_table: None,
|
content_inline_size_for_table: None,
|
||||||
baselines: Baselines::default(),
|
baselines: Baselines::default(),
|
||||||
|
depends_on_block_constraints,
|
||||||
};
|
};
|
||||||
|
|
||||||
table_layout
|
table_layout
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue