mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Fix inline content sizes of intrinsic element with indefinite block size (#34152)
To compute the min-content and max-content inline sizes of a replaced element, we were only using the aspect ratio to transfer definite block sizes resulting from clamping the preferred block size between the min and max block sizes. However, if the preferred block size is indefinite, then we weren't transfering the min and max through the aspect ratio. This patch adds a `SizeConstraint` enum that can represent these cases, and a `ConstraintSpace` struct analogous to `IndefiniteContainingBlock` but with no inline size, and a `SizeConstraint` block size. Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
72971bd271
commit
b28260aa13
15 changed files with 297 additions and 292 deletions
|
@ -40,7 +40,7 @@ use crate::sizing::{ContentSizes, InlineContentSizesResult, IntrinsicSizingMode}
|
||||||
use crate::style_ext::{
|
use crate::style_ext::{
|
||||||
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
|
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
|
||||||
};
|
};
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SizeConstraint};
|
||||||
|
|
||||||
/// Layout parameters and intermediate results about a flex container,
|
/// Layout parameters and intermediate results about a flex container,
|
||||||
/// grouped to avoid passing around many parameters
|
/// grouped to avoid passing around many parameters
|
||||||
|
@ -401,19 +401,17 @@ impl FlexContainer {
|
||||||
pub fn inline_content_sizes(
|
pub fn inline_content_sizes(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
match self.config.flex_axis {
|
match self.config.flex_axis {
|
||||||
FlexAxis::Row => {
|
FlexAxis::Row => {
|
||||||
self.main_content_sizes(layout_context, containing_block_for_children, || {
|
self.main_content_sizes(layout_context, &constraint_space.into(), || {
|
||||||
unreachable!(
|
unreachable!(
|
||||||
"Unexpected FlexContext query during row flex intrinsic size calculation."
|
"Unexpected FlexContext query during row flex intrinsic size calculation."
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
FlexAxis::Column => {
|
FlexAxis::Column => self.cross_content_sizes(layout_context, &constraint_space.into()),
|
||||||
self.cross_content_sizes(layout_context, containing_block_for_children)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1882,17 +1880,16 @@ impl FlexItem<'_> {
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
cross_size.auto_is(|| {
|
cross_size.auto_is(|| {
|
||||||
let containing_block_for_children =
|
let constraint_space = ConstraintSpace::new(
|
||||||
IndefiniteContainingBlock::new_for_writing_mode_and_block_size(
|
SizeConstraint::Definite(used_main_size),
|
||||||
item_writing_mode,
|
item_writing_mode,
|
||||||
AuOrAuto::LengthPercentage(used_main_size),
|
);
|
||||||
);
|
|
||||||
let content_contributions = self
|
let content_contributions = self
|
||||||
.box_
|
.box_
|
||||||
.independent_formatting_context
|
.independent_formatting_context
|
||||||
.inline_content_sizes(
|
.inline_content_sizes(
|
||||||
flex_context.layout_context,
|
flex_context.layout_context,
|
||||||
&containing_block_for_children,
|
&constraint_space,
|
||||||
&containing_block.into(),
|
&containing_block.into(),
|
||||||
)
|
)
|
||||||
.sizes
|
.sizes
|
||||||
|
@ -2474,7 +2471,7 @@ impl FlexItemBox {
|
||||||
Direction::Block
|
Direction::Block
|
||||||
};
|
};
|
||||||
|
|
||||||
let cross_size =
|
let cross_size = SizeConstraint::new(
|
||||||
if content_box_size.cross.is_auto() && auto_cross_size_stretches_to_container_size {
|
if content_box_size.cross.is_auto() && auto_cross_size_stretches_to_container_size {
|
||||||
if cross_axis_is_item_block_axis {
|
if cross_axis_is_item_block_axis {
|
||||||
containing_block.size.block
|
containing_block.size.block
|
||||||
|
@ -2485,14 +2482,17 @@ impl FlexItemBox {
|
||||||
} else {
|
} else {
|
||||||
content_box_size.cross
|
content_box_size.cross
|
||||||
}
|
}
|
||||||
.map(|v| v.clamp_between_extremums(min_size.cross.auto_is(Au::zero), max_size.cross));
|
.non_auto(),
|
||||||
|
min_size.cross.auto_is(Au::zero),
|
||||||
|
max_size.cross,
|
||||||
|
);
|
||||||
|
|
||||||
// > **transferred size suggestion**
|
// > **transferred size suggestion**
|
||||||
// > If the item has a preferred aspect ratio and its preferred cross size is definite, then the
|
// > If the item has a preferred aspect ratio and its preferred cross size is definite, then the
|
||||||
// > transferred size suggestion is that size (clamped by its minimum and maximum cross sizes if they
|
// > transferred size suggestion is that size (clamped by its minimum and maximum cross sizes if they
|
||||||
// > are definite), converted through the aspect ratio. It is otherwise undefined.
|
// > are definite), converted through the aspect ratio. It is otherwise undefined.
|
||||||
let transferred_size_suggestion = match (ratio, cross_size) {
|
let transferred_size_suggestion = match (ratio, cross_size) {
|
||||||
(Some(ratio), AuOrAuto::LengthPercentage(cross_size)) => {
|
(Some(ratio), SizeConstraint::Definite(cross_size)) => {
|
||||||
Some(ratio.compute_dependent_size(main_axis, cross_size))
|
Some(ratio.compute_dependent_size(main_axis, cross_size))
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -2504,17 +2504,9 @@ impl FlexItemBox {
|
||||||
// > aspect ratio.
|
// > aspect ratio.
|
||||||
let main_content_size = if cross_axis_is_item_block_axis {
|
let main_content_size = if cross_axis_is_item_block_axis {
|
||||||
let writing_mode = self.independent_formatting_context.style().writing_mode;
|
let writing_mode = self.independent_formatting_context.style().writing_mode;
|
||||||
let containing_block_for_children =
|
let constraint_space = ConstraintSpace::new(cross_size, writing_mode);
|
||||||
IndefiniteContainingBlock::new_for_writing_mode_and_block_size(
|
|
||||||
writing_mode,
|
|
||||||
cross_size,
|
|
||||||
);
|
|
||||||
self.independent_formatting_context
|
self.independent_formatting_context
|
||||||
.inline_content_sizes(
|
.inline_content_sizes(layout_context, &constraint_space, containing_block)
|
||||||
layout_context,
|
|
||||||
&containing_block_for_children,
|
|
||||||
containing_block,
|
|
||||||
)
|
|
||||||
.sizes
|
.sizes
|
||||||
.min_content
|
.min_content
|
||||||
} else {
|
} else {
|
||||||
|
@ -2664,23 +2656,16 @@ impl FlexItemBox {
|
||||||
// The main axis is the inline axis, so we can get the content size from the normal
|
// The main axis is the inline axis, so we can get the content size from the normal
|
||||||
// preferred widths calculation.
|
// preferred widths calculation.
|
||||||
let writing_mode = flex_item.style().writing_mode;
|
let writing_mode = flex_item.style().writing_mode;
|
||||||
let block_size = content_box_size.cross.map(|v| {
|
let constraint_space = ConstraintSpace::new(
|
||||||
v.clamp_between_extremums(
|
SizeConstraint::new(
|
||||||
|
content_box_size.cross.non_auto(),
|
||||||
content_min_box_size.cross,
|
content_min_box_size.cross,
|
||||||
content_max_box_size.cross,
|
content_max_box_size.cross,
|
||||||
)
|
),
|
||||||
});
|
writing_mode,
|
||||||
let containing_block_for_children =
|
);
|
||||||
IndefiniteContainingBlock::new_for_writing_mode_and_block_size(
|
|
||||||
writing_mode,
|
|
||||||
block_size,
|
|
||||||
);
|
|
||||||
let max_content = flex_item
|
let max_content = flex_item
|
||||||
.inline_content_sizes(
|
.inline_content_sizes(layout_context, &constraint_space, containing_block)
|
||||||
layout_context,
|
|
||||||
&containing_block_for_children,
|
|
||||||
containing_block,
|
|
||||||
)
|
|
||||||
.sizes
|
.sizes
|
||||||
.max_content;
|
.max_content;
|
||||||
if let Some(ratio) = ratio {
|
if let Some(ratio) = ratio {
|
||||||
|
@ -2764,9 +2749,7 @@ impl FlexItemBox {
|
||||||
containing_block_inline_size_minus_pbm
|
containing_block_inline_size_minus_pbm
|
||||||
} else {
|
} else {
|
||||||
let containing_block_for_children =
|
let containing_block_for_children =
|
||||||
IndefiniteContainingBlock::new_for_writing_mode(
|
ConstraintSpace::new_for_style(&non_replaced.style);
|
||||||
non_replaced.style.writing_mode,
|
|
||||||
);
|
|
||||||
non_replaced
|
non_replaced
|
||||||
.inline_content_sizes(
|
.inline_content_sizes(
|
||||||
flex_context.layout_context,
|
flex_context.layout_context,
|
||||||
|
|
|
@ -128,7 +128,7 @@ use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
||||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||||
use crate::sizing::{ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{ContentSizes, InlineContentSizesResult};
|
||||||
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
|
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ConstraintSpace, ContainingBlock};
|
||||||
|
|
||||||
// From gfxFontConstants.h in Firefox.
|
// From gfxFontConstants.h in Firefox.
|
||||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||||
|
@ -1574,9 +1574,9 @@ impl InlineFormattingContext {
|
||||||
pub(super) fn inline_content_sizes(
|
pub(super) fn inline_content_sizes(
|
||||||
&self,
|
&self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
ContentSizesComputation::compute(self, layout_context, containing_block_for_children)
|
ContentSizesComputation::compute(self, layout_context, constraint_space)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn layout(
|
pub(super) fn layout(
|
||||||
|
@ -2188,7 +2188,7 @@ fn inline_container_needs_strut(
|
||||||
/// A struct which takes care of computing [`ContentSizes`] for an [`InlineFormattingContext`].
|
/// A struct which takes care of computing [`ContentSizes`] for an [`InlineFormattingContext`].
|
||||||
struct ContentSizesComputation<'layout_data> {
|
struct ContentSizesComputation<'layout_data> {
|
||||||
layout_context: &'layout_data LayoutContext<'layout_data>,
|
layout_context: &'layout_data LayoutContext<'layout_data>,
|
||||||
containing_block: &'layout_data IndefiniteContainingBlock,
|
constraint_space: &'layout_data ConstraintSpace,
|
||||||
paragraph: ContentSizes,
|
paragraph: ContentSizes,
|
||||||
current_line: ContentSizes,
|
current_line: ContentSizes,
|
||||||
/// Size for whitespace pending to be added to this line.
|
/// Size for whitespace pending to be added to this line.
|
||||||
|
@ -2234,16 +2234,15 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
||||||
let inline_box = inline_formatting_context.inline_boxes.get(identifier);
|
let inline_box = inline_formatting_context.inline_boxes.get(identifier);
|
||||||
let inline_box = (*inline_box).borrow();
|
let inline_box = (*inline_box).borrow();
|
||||||
let zero = Au::zero();
|
let zero = Au::zero();
|
||||||
|
let writing_mode = self.constraint_space.writing_mode;
|
||||||
let padding = inline_box
|
let padding = inline_box
|
||||||
.style
|
.style
|
||||||
.padding(self.containing_block.writing_mode)
|
.padding(writing_mode)
|
||||||
.percentages_relative_to(zero);
|
.percentages_relative_to(zero);
|
||||||
let border = inline_box
|
let border = inline_box.style.border_width(writing_mode);
|
||||||
.style
|
|
||||||
.border_width(self.containing_block.writing_mode);
|
|
||||||
let margin = inline_box
|
let margin = inline_box
|
||||||
.style
|
.style
|
||||||
.margin(self.containing_block.writing_mode)
|
.margin(writing_mode)
|
||||||
.percentages_relative_to(zero)
|
.percentages_relative_to(zero)
|
||||||
.auto_is(Au::zero);
|
.auto_is(Au::zero);
|
||||||
|
|
||||||
|
@ -2329,7 +2328,7 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
||||||
depends_on_block_constraints,
|
depends_on_block_constraints,
|
||||||
} = atomic.outer_inline_content_sizes(
|
} = atomic.outer_inline_content_sizes(
|
||||||
self.layout_context,
|
self.layout_context,
|
||||||
self.containing_block,
|
&self.constraint_space.into(),
|
||||||
&LogicalVec2::zero(),
|
&LogicalVec2::zero(),
|
||||||
false, /* auto_block_size_stretches_to_containing_block */
|
false, /* auto_block_size_stretches_to_containing_block */
|
||||||
);
|
);
|
||||||
|
@ -2384,11 +2383,11 @@ impl<'layout_data> ContentSizesComputation<'layout_data> {
|
||||||
fn compute(
|
fn compute(
|
||||||
inline_formatting_context: &InlineFormattingContext,
|
inline_formatting_context: &InlineFormattingContext,
|
||||||
layout_context: &'layout_data LayoutContext,
|
layout_context: &'layout_data LayoutContext,
|
||||||
containing_block: &'layout_data IndefiniteContainingBlock,
|
constraint_space: &'layout_data ConstraintSpace,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
Self {
|
Self {
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block,
|
constraint_space,
|
||||||
paragraph: ContentSizes::zero(),
|
paragraph: ContentSizes::zero(),
|
||||||
current_line: ContentSizes::zero(),
|
current_line: ContentSizes::zero(),
|
||||||
pending_whitespace: ContentSizes::zero(),
|
pending_whitespace: ContentSizes::zero(),
|
||||||
|
|
|
@ -41,7 +41,7 @@ use crate::sizing::{self, ContentSizes, InlineContentSizesResult};
|
||||||
use crate::style_ext::{
|
use crate::style_ext::{
|
||||||
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
|
Clamp, ComputedValuesExt, ContentBoxSizesAndPBMDeprecated, PaddingBorderMargin,
|
||||||
};
|
};
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SizeConstraint};
|
||||||
|
|
||||||
mod construct;
|
mod construct;
|
||||||
pub mod float;
|
pub mod float;
|
||||||
|
@ -235,7 +235,7 @@ impl OutsideMarker {
|
||||||
) -> Fragment {
|
) -> Fragment {
|
||||||
let content_sizes = self.block_container.inline_content_sizes(
|
let content_sizes = self.block_container.inline_content_sizes(
|
||||||
layout_context,
|
layout_context,
|
||||||
&IndefiniteContainingBlock::new_for_writing_mode(self.marker_style.writing_mode),
|
&ConstraintSpace::new_for_style(&self.marker_style),
|
||||||
);
|
);
|
||||||
let containing_block_for_children = ContainingBlock {
|
let containing_block_for_children = ContainingBlock {
|
||||||
inline_size: content_sizes.sizes.max_content,
|
inline_size: content_sizes.sizes.max_content,
|
||||||
|
@ -393,8 +393,8 @@ fn calculate_inline_content_size_for_block_level_boxes(
|
||||||
containing_block,
|
containing_block,
|
||||||
&LogicalVec2::zero(),
|
&LogicalVec2::zero(),
|
||||||
false, /* auto_block_size_stretches_to_containing_block */
|
false, /* auto_block_size_stretches_to_containing_block */
|
||||||
|containing_block_for_children| {
|
|constraint_space| {
|
||||||
contents.inline_content_sizes(layout_context, containing_block_for_children)
|
contents.inline_content_sizes(layout_context, constraint_space)
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// A block in the same BFC can overlap floats, it's not moved next to them,
|
// A block in the same BFC can overlap floats, it's not moved next to them,
|
||||||
|
@ -528,16 +528,16 @@ impl BlockContainer {
|
||||||
pub(super) fn inline_content_sizes(
|
pub(super) fn inline_content_sizes(
|
||||||
&self,
|
&self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
match &self {
|
match &self {
|
||||||
Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes(
|
Self::BlockLevelBoxes(boxes) => calculate_inline_content_size_for_block_level_boxes(
|
||||||
boxes,
|
boxes,
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block_for_children,
|
&constraint_space.into(),
|
||||||
),
|
),
|
||||||
Self::InlineFormattingContext(context) => {
|
Self::InlineFormattingContext(context) => {
|
||||||
context.inline_content_sizes(layout_context, containing_block_for_children)
|
context.inline_content_sizes(layout_context, constraint_space)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2030,39 +2030,33 @@ impl IndependentFormattingContext {
|
||||||
(fragments, content_rect, None)
|
(fragments, content_rect, None)
|
||||||
},
|
},
|
||||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||||
let style = non_replaced.style.clone();
|
let writing_mode = non_replaced.style.writing_mode;
|
||||||
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 = content_box_sizes_and_pbm
|
let preferred_block_size = content_box_sizes_and_pbm
|
||||||
.content_box_size
|
.content_box_size
|
||||||
.block
|
.block
|
||||||
|
.maybe_resolve_extrinsic(available_block_size);
|
||||||
|
let min_block_size = content_box_sizes_and_pbm
|
||||||
|
.content_min_box_size
|
||||||
|
.block
|
||||||
.maybe_resolve_extrinsic(available_block_size)
|
.maybe_resolve_extrinsic(available_block_size)
|
||||||
.map(|size| {
|
.unwrap_or_default();
|
||||||
let min_block_size = content_box_sizes_and_pbm
|
let max_block_size = content_box_sizes_and_pbm
|
||||||
.content_min_box_size
|
.content_max_box_size
|
||||||
.block
|
.block
|
||||||
.maybe_resolve_extrinsic(available_block_size)
|
.maybe_resolve_extrinsic(available_block_size);
|
||||||
.unwrap_or_default();
|
let tentative_block_size =
|
||||||
let max_block_size = content_box_sizes_and_pbm
|
SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
|
||||||
.content_max_box_size
|
|
||||||
.block
|
|
||||||
.maybe_resolve_extrinsic(available_block_size);
|
|
||||||
size.clamp_between_extremums(min_block_size, max_block_size)
|
|
||||||
})
|
|
||||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
|
|
||||||
|
|
||||||
let mut get_content_size = || {
|
let mut get_content_size = || {
|
||||||
let containing_block_for_children =
|
let constraint_space = ConstraintSpace::new(tentative_block_size, writing_mode);
|
||||||
IndefiniteContainingBlock::new_for_writing_mode_and_block_size(
|
|
||||||
style.writing_mode,
|
|
||||||
tentative_block_size,
|
|
||||||
);
|
|
||||||
non_replaced
|
non_replaced
|
||||||
.inline_content_sizes(layout_context, &containing_block_for_children)
|
.inline_content_sizes(layout_context, &constraint_space)
|
||||||
.sizes
|
.sizes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2092,12 +2086,12 @@ impl IndependentFormattingContext {
|
||||||
|
|
||||||
let containing_block_for_children = ContainingBlock {
|
let containing_block_for_children = ContainingBlock {
|
||||||
inline_size,
|
inline_size,
|
||||||
block_size: tentative_block_size,
|
block_size: tentative_block_size.to_auto_or(),
|
||||||
style: &style,
|
style: &non_replaced.style,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
container_writing_mode.is_horizontal(),
|
container_writing_mode.is_horizontal(),
|
||||||
style.writing_mode.is_horizontal(),
|
writing_mode.is_horizontal(),
|
||||||
"Mixed horizontal and vertical writing modes are not supported yet"
|
"Mixed horizontal and vertical writing modes are not supported yet"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2126,7 +2120,8 @@ impl IndependentFormattingContext {
|
||||||
.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
|
||||||
.auto_is(|| independent_layout.content_block_size)
|
.to_definite()
|
||||||
|
.unwrap_or(independent_layout.content_block_size)
|
||||||
.clamp_between_extremums(min_block_size, max_block_size);
|
.clamp_between_extremums(min_block_size, max_block_size);
|
||||||
(inline_size, block_size)
|
(inline_size, block_size)
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,7 +21,9 @@ use crate::replaced::ReplacedContent;
|
||||||
use crate::sizing::{self, InlineContentSizesResult};
|
use crate::sizing::{self, InlineContentSizesResult};
|
||||||
use crate::style_ext::{AspectRatio, DisplayInside};
|
use crate::style_ext::{AspectRatio, DisplayInside};
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock, LogicalVec2};
|
use crate::{
|
||||||
|
ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, LogicalVec2, SizeConstraint,
|
||||||
|
};
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-display/#independent-formatting-context>
|
/// <https://drafts.csswg.org/css-display/#independent-formatting-context>
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
@ -36,7 +38,7 @@ pub(crate) struct NonReplacedFormattingContext {
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub style: Arc<ComputedValues>,
|
pub style: Arc<ComputedValues>,
|
||||||
/// If it was requested during construction
|
/// If it was requested during construction
|
||||||
pub content_sizes_result: Option<(AuOrAuto, InlineContentSizesResult)>,
|
pub content_sizes_result: Option<(SizeConstraint, InlineContentSizesResult)>,
|
||||||
pub contents: NonReplacedFormattingContextContents,
|
pub contents: NonReplacedFormattingContextContents,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,16 +190,16 @@ impl IndependentFormattingContext {
|
||||||
pub(crate) fn inline_content_sizes(
|
pub(crate) fn inline_content_sizes(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
containing_block: &IndefiniteContainingBlock,
|
containing_block: &IndefiniteContainingBlock,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
match self {
|
match self {
|
||||||
Self::NonReplaced(inner) => {
|
Self::NonReplaced(inner) => {
|
||||||
inner.inline_content_sizes(layout_context, containing_block_for_children)
|
inner.inline_content_sizes(layout_context, constraint_space)
|
||||||
},
|
},
|
||||||
Self::Replaced(inner) => inner.contents.inline_content_sizes(
|
Self::Replaced(inner) => inner.contents.inline_content_sizes(
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block_for_children,
|
constraint_space,
|
||||||
inner.preferred_aspect_ratio(containing_block),
|
inner.preferred_aspect_ratio(containing_block),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -222,10 +224,10 @@ impl IndependentFormattingContext {
|
||||||
containing_block,
|
containing_block,
|
||||||
auto_minimum,
|
auto_minimum,
|
||||||
auto_block_size_stretches_to_containing_block,
|
auto_block_size_stretches_to_containing_block,
|
||||||
|containing_block_for_children| {
|
|constraint_space| {
|
||||||
replaced.contents.inline_content_sizes(
|
replaced.contents.inline_content_sizes(
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block_for_children,
|
constraint_space,
|
||||||
replaced.preferred_aspect_ratio(containing_block),
|
replaced.preferred_aspect_ratio(containing_block),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -276,16 +278,11 @@ impl NonReplacedFormattingContext {
|
||||||
pub(crate) fn inline_content_sizes(
|
pub(crate) fn inline_content_sizes(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
assert_eq!(
|
|
||||||
containing_block_for_children.size.inline,
|
|
||||||
AuOrAuto::Auto,
|
|
||||||
"inline_content_sizes() got non-auto containing block inline-size",
|
|
||||||
);
|
|
||||||
if let Some((previous_cb_block_size, result)) = self.content_sizes_result {
|
if let Some((previous_cb_block_size, result)) = self.content_sizes_result {
|
||||||
if !result.depends_on_block_constraints ||
|
if !result.depends_on_block_constraints ||
|
||||||
previous_cb_block_size == containing_block_for_children.size.block
|
previous_cb_block_size == constraint_space.block_size
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -294,9 +291,9 @@ impl NonReplacedFormattingContext {
|
||||||
|
|
||||||
self.content_sizes_result
|
self.content_sizes_result
|
||||||
.insert((
|
.insert((
|
||||||
containing_block_for_children.size.block,
|
constraint_space.block_size,
|
||||||
self.contents
|
self.contents
|
||||||
.inline_content_sizes(layout_context, containing_block_for_children),
|
.inline_content_sizes(layout_context, constraint_space),
|
||||||
))
|
))
|
||||||
.1
|
.1
|
||||||
}
|
}
|
||||||
|
@ -313,9 +310,7 @@ impl NonReplacedFormattingContext {
|
||||||
containing_block,
|
containing_block,
|
||||||
auto_minimum,
|
auto_minimum,
|
||||||
auto_block_size_stretches_to_containing_block,
|
auto_block_size_stretches_to_containing_block,
|
||||||
|containing_block_for_children| {
|
|constraint_space| self.inline_content_sizes(layout_context, constraint_space),
|
||||||
self.inline_content_sizes(layout_context, containing_block_for_children)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,18 +319,14 @@ impl NonReplacedFormattingContextContents {
|
||||||
pub(crate) fn inline_content_sizes(
|
pub(crate) fn inline_content_sizes(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
match self {
|
match self {
|
||||||
Self::Flow(inner) => inner
|
Self::Flow(inner) => inner
|
||||||
.contents
|
.contents
|
||||||
.inline_content_sizes(layout_context, containing_block_for_children),
|
.inline_content_sizes(layout_context, constraint_space),
|
||||||
Self::Flex(inner) => {
|
Self::Flex(inner) => inner.inline_content_sizes(layout_context, constraint_space),
|
||||||
inner.inline_content_sizes(layout_context, containing_block_for_children)
|
Self::Table(table) => table.inline_content_sizes(layout_context, constraint_space),
|
||||||
},
|
|
||||||
Self::Table(table) => {
|
|
||||||
table.inline_content_sizes(layout_context, containing_block_for_children)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ use style::Zero;
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
|
|
||||||
use crate::sizing::ContentSizes;
|
use crate::sizing::ContentSizes;
|
||||||
|
use crate::style_ext::Clamp;
|
||||||
use crate::ContainingBlock;
|
use crate::ContainingBlock;
|
||||||
|
|
||||||
pub type PhysicalPoint<U> = euclid::Point2D<U, CSSPixel>;
|
pub type PhysicalPoint<U> = euclid::Point2D<U, CSSPixel>;
|
||||||
|
@ -848,3 +849,45 @@ impl Size<Au> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the sizing constraint that the preferred, min and max sizing properties
|
||||||
|
/// impose on one axis.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize)]
|
||||||
|
pub(crate) enum SizeConstraint {
|
||||||
|
/// Represents a definite preferred size, clamped by minimum and maximum sizes (if any).
|
||||||
|
Definite(Au),
|
||||||
|
/// Represents an indefinite preferred size that allows a range of values between
|
||||||
|
/// the first argument (minimum size) and the second one (maximum size).
|
||||||
|
MinMax(Au, Option<Au>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SizeConstraint {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::MinMax(Au::default(), None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SizeConstraint {
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn new(preferred_size: Option<Au>, min_size: Au, max_size: Option<Au>) -> Self {
|
||||||
|
preferred_size.map_or_else(
|
||||||
|
|| Self::MinMax(min_size, max_size),
|
||||||
|
|size| Self::Definite(size.clamp_between_extremums(min_size, max_size)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_definite(self) -> Option<Au> {
|
||||||
|
match self {
|
||||||
|
Self::Definite(size) => Some(size),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn to_auto_or(self) -> AutoOr<Au> {
|
||||||
|
self.to_definite()
|
||||||
|
.map_or(AutoOr::Auto, AutoOr::LengthPercentage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -32,34 +32,44 @@ use geom::AuOrAuto;
|
||||||
use style::logical_geometry::WritingMode;
|
use style::logical_geometry::WritingMode;
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
|
|
||||||
use crate::geom::LogicalVec2;
|
use crate::geom::{LogicalVec2, SizeConstraint};
|
||||||
|
|
||||||
/// A containing block useful for calculating inline content sizes, which may
|
/// Represents the set of constraints that we use when computing the min-content
|
||||||
/// have inline sizes that depend on block sizes due to aspect ratio.
|
/// and max-content inline sizes of an element.
|
||||||
|
pub(crate) struct ConstraintSpace {
|
||||||
|
pub block_size: SizeConstraint,
|
||||||
|
pub writing_mode: WritingMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstraintSpace {
|
||||||
|
fn new(block_size: SizeConstraint, writing_mode: WritingMode) -> Self {
|
||||||
|
Self {
|
||||||
|
block_size,
|
||||||
|
writing_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_for_style(style: &ComputedValues) -> Self {
|
||||||
|
Self::new(SizeConstraint::default(), style.writing_mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of [`ContainingBlock`] that allows an indefinite inline size.
|
||||||
|
/// Useful for code that is shared for both layout (where we know the inline size
|
||||||
|
/// of the containing block) and intrinsic sizing (where we don't know it).
|
||||||
pub(crate) struct IndefiniteContainingBlock {
|
pub(crate) struct IndefiniteContainingBlock {
|
||||||
pub size: LogicalVec2<AuOrAuto>,
|
pub size: LogicalVec2<AuOrAuto>,
|
||||||
pub writing_mode: WritingMode,
|
pub writing_mode: WritingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndefiniteContainingBlock {
|
impl From<&ConstraintSpace> for IndefiniteContainingBlock {
|
||||||
fn new_for_writing_mode(writing_mode: WritingMode) -> Self {
|
fn from(constraint_space: &ConstraintSpace) -> Self {
|
||||||
Self::new_for_writing_mode_and_block_size(writing_mode, AuOrAuto::Auto)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an [`IndefiniteContainingBlock`] with the provided style and block size,
|
|
||||||
/// and the inline size is set to auto.
|
|
||||||
/// This is useful when finding the min-content or max-content size of an element,
|
|
||||||
/// since then we ignore its 'inline-size', 'min-inline-size' and 'max-inline-size'.
|
|
||||||
fn new_for_writing_mode_and_block_size(
|
|
||||||
writing_mode: WritingMode,
|
|
||||||
block_size: AuOrAuto,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
size: LogicalVec2 {
|
size: LogicalVec2 {
|
||||||
inline: AuOrAuto::Auto,
|
inline: AuOrAuto::Auto,
|
||||||
block: block_size,
|
block: constraint_space.block_size.to_auto_or(),
|
||||||
},
|
},
|
||||||
writing_mode,
|
writing_mode: constraint_space.writing_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ use crate::geom::{
|
||||||
PhysicalRect, PhysicalVec, Size, ToLogical, ToLogicalWithContainingBlock,
|
PhysicalRect, PhysicalVec, Size, ToLogical, ToLogicalWithContainingBlock,
|
||||||
};
|
};
|
||||||
use crate::sizing::ContentSizes;
|
use crate::sizing::ContentSizes;
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt, DisplayInside};
|
use crate::style_ext::{ComputedValuesExt, DisplayInside};
|
||||||
use crate::{ContainingBlock, DefiniteContainingBlock, IndefiniteContainingBlock};
|
use crate::{ConstraintSpace, ContainingBlock, DefiniteContainingBlock, SizeConstraint};
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub(crate) struct AbsolutelyPositionedBox {
|
pub(crate) struct AbsolutelyPositionedBox {
|
||||||
|
@ -546,17 +546,9 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
// The inline axis can be fully resolved, computing intrinsic sizes using the
|
// The inline axis can be fully resolved, computing intrinsic sizes using the
|
||||||
// tentative block size.
|
// tentative block size.
|
||||||
let mut inline_axis = inline_axis_solver.solve(Some(|| {
|
let mut inline_axis = inline_axis_solver.solve(Some(|| {
|
||||||
let containing_block_for_children =
|
let constraint_space = ConstraintSpace::new(block_axis.size, style.writing_mode);
|
||||||
IndefiniteContainingBlock::new_for_writing_mode_and_block_size(
|
|
||||||
style.writing_mode,
|
|
||||||
block_axis.size,
|
|
||||||
);
|
|
||||||
context
|
context
|
||||||
.inline_content_sizes(
|
.inline_content_sizes(layout_context, &constraint_space, &containing_block.into())
|
||||||
layout_context,
|
|
||||||
&containing_block_for_children,
|
|
||||||
&containing_block.into(),
|
|
||||||
)
|
|
||||||
.sizes
|
.sizes
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -578,10 +570,10 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
|
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
|
||||||
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
|
// https://drafts.csswg.org/css2/visudet.html#abs-non-replaced-height
|
||||||
let inline_size = inline_axis.size.non_auto().unwrap();
|
let inline_size = inline_axis.size.to_definite().unwrap();
|
||||||
let containing_block_for_children = ContainingBlock {
|
let containing_block_for_children = ContainingBlock {
|
||||||
inline_size,
|
inline_size,
|
||||||
block_size: block_axis.size,
|
block_size: block_axis.size.to_auto_or(),
|
||||||
style: &style,
|
style: &style,
|
||||||
};
|
};
|
||||||
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
|
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
|
||||||
|
@ -608,7 +600,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
inline_axis = inline_axis_solver.solve_with_size(table_inline_size);
|
inline_axis = inline_axis_solver.solve_with_size(table_inline_size);
|
||||||
}
|
}
|
||||||
let table_block_size = independent_layout.content_block_size;
|
let table_block_size = independent_layout.content_block_size;
|
||||||
if block_axis.size != AuOrAuto::LengthPercentage(table_block_size) {
|
if block_axis.size != SizeConstraint::Definite(table_block_size) {
|
||||||
block_axis = block_axis_solver.solve_with_size(table_block_size);
|
block_axis = block_axis_solver.solve_with_size(table_block_size);
|
||||||
}
|
}
|
||||||
(table_block_size, table_inline_size)
|
(table_block_size, table_inline_size)
|
||||||
|
@ -617,7 +609,7 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
// Now we can properly solve the block size.
|
// Now we can properly solve the block size.
|
||||||
block_axis = block_axis_solver
|
block_axis = block_axis_solver
|
||||||
.solve(Some(|| independent_layout.content_block_size.into()));
|
.solve(Some(|| independent_layout.content_block_size.into()));
|
||||||
(block_axis.size.non_auto().unwrap(), inline_size)
|
(block_axis.size.to_definite().unwrap(), inline_size)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -747,7 +739,7 @@ impl Anchor {
|
||||||
|
|
||||||
struct AxisResult {
|
struct AxisResult {
|
||||||
anchor: Anchor,
|
anchor: Anchor,
|
||||||
size: AuOrAuto,
|
size: SizeConstraint,
|
||||||
margin_start: Au,
|
margin_start: Au,
|
||||||
margin_end: Au,
|
margin_end: Au,
|
||||||
}
|
}
|
||||||
|
@ -787,38 +779,37 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
||||||
let content_size = LazyCell::new(get_content_size);
|
let content_size = LazyCell::new(get_content_size);
|
||||||
move || *content_size
|
move || *content_size
|
||||||
});
|
});
|
||||||
let mut solve_size = |initial_behavior, stretch_size: Au| {
|
let mut solve_size = |initial_behavior, stretch_size: Au| -> SizeConstraint {
|
||||||
let initial_is_stretch = initial_behavior == Size::Stretch;
|
let initial_is_stretch = initial_behavior == Size::Stretch;
|
||||||
let stretch_size = stretch_size.max(Au::zero());
|
let stretch_size = stretch_size.max(Au::zero());
|
||||||
get_content_size
|
if let Some(mut get_content_size) = get_content_size.as_mut() {
|
||||||
.as_mut()
|
let preferred_size = Some(self.computed_size.resolve(
|
||||||
.map(|mut get_content_size| {
|
initial_behavior,
|
||||||
let min_size = self
|
stretch_size,
|
||||||
.computed_min_size
|
&mut get_content_size,
|
||||||
.resolve_non_initial(stretch_size, &mut get_content_size)
|
));
|
||||||
.unwrap_or_default();
|
let min_size = self
|
||||||
let max_size = self
|
.computed_min_size
|
||||||
.computed_max_size
|
.resolve_non_initial(stretch_size, &mut get_content_size)
|
||||||
.resolve_non_initial(stretch_size, &mut get_content_size);
|
.unwrap_or_default();
|
||||||
self.computed_size
|
let max_size = self
|
||||||
.resolve(initial_behavior, stretch_size, &mut get_content_size)
|
.computed_max_size
|
||||||
.clamp_between_extremums(min_size, max_size)
|
.resolve_non_initial(stretch_size, &mut get_content_size);
|
||||||
})
|
SizeConstraint::new(preferred_size, min_size, max_size)
|
||||||
.or_else(|| {
|
} else {
|
||||||
self.computed_size
|
let preferred_size = self
|
||||||
.maybe_resolve_extrinsic(Some(stretch_size))
|
.computed_size
|
||||||
.or(initial_is_stretch.then_some(stretch_size))
|
.maybe_resolve_extrinsic(Some(stretch_size))
|
||||||
.map(|size| {
|
.or(initial_is_stretch.then_some(stretch_size));
|
||||||
let min_size = self
|
let min_size = self
|
||||||
.computed_min_size
|
.computed_min_size
|
||||||
.maybe_resolve_extrinsic(Some(stretch_size))
|
.maybe_resolve_extrinsic(Some(stretch_size))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
let max_size = self
|
let max_size = self
|
||||||
.computed_max_size
|
.computed_max_size
|
||||||
.maybe_resolve_extrinsic(Some(stretch_size));
|
.maybe_resolve_extrinsic(Some(stretch_size));
|
||||||
size.clamp_between_extremums(min_size, max_size)
|
SizeConstraint::new(preferred_size, min_size, max_size)
|
||||||
})
|
}
|
||||||
})
|
|
||||||
};
|
};
|
||||||
let mut solve_for_anchor = |anchor: Anchor| {
|
let mut solve_for_anchor = |anchor: Anchor| {
|
||||||
let margin_start = self.computed_margin_start.auto_is(Au::zero);
|
let margin_start = self.computed_margin_start.auto_is(Au::zero);
|
||||||
|
@ -828,8 +819,7 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
||||||
self.padding_border_sum -
|
self.padding_border_sum -
|
||||||
margin_start -
|
margin_start -
|
||||||
margin_end;
|
margin_end;
|
||||||
let size = solve_size(Size::FitContent, stretch_size)
|
let size = solve_size(Size::FitContent, stretch_size);
|
||||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
|
|
||||||
AxisResult {
|
AxisResult {
|
||||||
anchor,
|
anchor,
|
||||||
size,
|
size,
|
||||||
|
@ -859,7 +849,9 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
||||||
let stretch_size = free_space -
|
let stretch_size = free_space -
|
||||||
self.computed_margin_start.auto_is(Au::zero) -
|
self.computed_margin_start.auto_is(Au::zero) -
|
||||||
self.computed_margin_end.auto_is(Au::zero);
|
self.computed_margin_end.auto_is(Au::zero);
|
||||||
let used_size = solve_size(Size::Stretch, stretch_size).unwrap();
|
let used_size = solve_size(Size::Stretch, stretch_size)
|
||||||
|
.to_definite()
|
||||||
|
.unwrap();
|
||||||
free_space -= used_size;
|
free_space -= used_size;
|
||||||
let (margin_start, margin_end) =
|
let (margin_start, margin_end) =
|
||||||
match (self.computed_margin_start, self.computed_margin_end) {
|
match (self.computed_margin_start, self.computed_margin_end) {
|
||||||
|
@ -883,7 +875,7 @@ impl<'a> AbsoluteAxisSolver<'a> {
|
||||||
};
|
};
|
||||||
AxisResult {
|
AxisResult {
|
||||||
anchor: Anchor::Start(start),
|
anchor: Anchor::Start(start),
|
||||||
size: AuOrAuto::LengthPercentage(used_size),
|
size: SizeConstraint::Definite(used_size),
|
||||||
margin_start,
|
margin_start,
|
||||||
margin_end,
|
margin_end,
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ use crate::fragment_tree::{BaseFragmentInfo, Fragment, IFrameFragment, ImageFrag
|
||||||
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size};
|
use crate::geom::{LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSize, Size};
|
||||||
use crate::sizing::InlineContentSizesResult;
|
use crate::sizing::InlineContentSizesResult;
|
||||||
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
|
use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
|
||||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, SizeConstraint};
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub(crate) struct ReplacedContent {
|
pub(crate) struct ReplacedContent {
|
||||||
|
@ -259,36 +259,46 @@ impl ReplacedContent {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn content_size(
|
||||||
|
&self,
|
||||||
|
axis: Direction,
|
||||||
|
preferred_aspect_ratio: Option<AspectRatio>,
|
||||||
|
get_size_in_opposite_axis: &dyn Fn() -> SizeConstraint,
|
||||||
|
get_fallback_size: &dyn Fn() -> Au,
|
||||||
|
) -> Au {
|
||||||
|
let Some(ratio) = preferred_aspect_ratio else {
|
||||||
|
return get_fallback_size();
|
||||||
|
};
|
||||||
|
let transfer = |size| ratio.compute_dependent_size(axis, size);
|
||||||
|
match get_size_in_opposite_axis() {
|
||||||
|
SizeConstraint::Definite(size) => transfer(size),
|
||||||
|
SizeConstraint::MinMax(min_size, max_size) => get_fallback_size()
|
||||||
|
.clamp_between_extremums(transfer(min_size), max_size.map(transfer)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn inline_content_sizes(
|
pub fn inline_content_sizes(
|
||||||
&self,
|
&self,
|
||||||
_: &LayoutContext,
|
_: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
preferred_aspect_ratio: Option<AspectRatio>,
|
preferred_aspect_ratio: Option<AspectRatio>,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
// FIXME: min/max-content of replaced elements is not defined in
|
let get_inline_fallback_size = || {
|
||||||
// https://dbaron.org/css/intrinsic/
|
let writing_mode = constraint_space.writing_mode;
|
||||||
// This seems sensible?
|
self.flow_relative_natural_size(writing_mode)
|
||||||
let block_size = containing_block_for_children.size.block;
|
.inline
|
||||||
match (block_size, preferred_aspect_ratio) {
|
.unwrap_or_else(|| Self::flow_relative_default_object_size(writing_mode).inline)
|
||||||
(AuOrAuto::LengthPercentage(block_size), Some(ratio)) => InlineContentSizesResult {
|
};
|
||||||
sizes: ratio
|
let inline_content_size = self.content_size(
|
||||||
.compute_dependent_size(Direction::Inline, block_size)
|
Direction::Inline,
|
||||||
.into(),
|
preferred_aspect_ratio,
|
||||||
depends_on_block_constraints: true,
|
&|| constraint_space.block_size,
|
||||||
},
|
&get_inline_fallback_size,
|
||||||
_ => {
|
);
|
||||||
let writing_mode = containing_block_for_children.writing_mode;
|
InlineContentSizesResult {
|
||||||
InlineContentSizesResult {
|
sizes: inline_content_size.into(),
|
||||||
sizes: self
|
depends_on_block_constraints: preferred_aspect_ratio.is_some(),
|
||||||
.flow_relative_natural_size(writing_mode)
|
|
||||||
.inline
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
Self::flow_relative_default_object_size(writing_mode).inline
|
|
||||||
})
|
|
||||||
.into(),
|
|
||||||
depends_on_block_constraints: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,51 +539,51 @@ impl ReplacedContent {
|
||||||
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
|
.map(|block_size| Au::zero().max(block_size - pbm_sums.block));
|
||||||
|
|
||||||
// <https://drafts.csswg.org/css-sizing-3/#intrinsic-sizes>
|
// <https://drafts.csswg.org/css-sizing-3/#intrinsic-sizes>
|
||||||
// FIXME: Use ReplacedContent::inline_content_sizes() once it's fixed to correctly handle
|
|
||||||
// min and max constraints.
|
|
||||||
let inline_content_size = LazyCell::new(|| {
|
let inline_content_size = LazyCell::new(|| {
|
||||||
let Some(ratio) = ratio else {
|
let get_block_size = || {
|
||||||
return get_inline_fallback_size();
|
let block_stretch_size = block_stretch_size.unwrap_or_else(get_block_fallback_size);
|
||||||
|
SizeConstraint::new(
|
||||||
|
box_size
|
||||||
|
.block
|
||||||
|
.maybe_resolve_extrinsic(Some(block_stretch_size)),
|
||||||
|
min_box_size
|
||||||
|
.block
|
||||||
|
.maybe_resolve_extrinsic(Some(block_stretch_size))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
max_box_size
|
||||||
|
.block
|
||||||
|
.maybe_resolve_extrinsic(Some(block_stretch_size)),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let block_stretch_size = block_stretch_size.unwrap_or_else(get_block_fallback_size);
|
self.content_size(
|
||||||
let transfer = |size| ratio.compute_dependent_size(Direction::Inline, size);
|
Direction::Inline,
|
||||||
let min = transfer(
|
ratio,
|
||||||
min_box_size
|
&get_block_size,
|
||||||
.block
|
&get_inline_fallback_size,
|
||||||
.maybe_resolve_extrinsic(Some(block_stretch_size))
|
)
|
||||||
.unwrap_or_default(),
|
|
||||||
);
|
|
||||||
let max = max_box_size
|
|
||||||
.block
|
|
||||||
.maybe_resolve_extrinsic(Some(block_stretch_size))
|
|
||||||
.map(transfer);
|
|
||||||
box_size
|
|
||||||
.block
|
|
||||||
.maybe_resolve_extrinsic(Some(block_stretch_size))
|
|
||||||
.map_or_else(get_inline_fallback_size, transfer)
|
|
||||||
.clamp_between_extremums(min, max)
|
|
||||||
});
|
});
|
||||||
let block_content_size = LazyCell::new(|| {
|
let block_content_size = LazyCell::new(|| {
|
||||||
let Some(ratio) = ratio else {
|
let get_inline_size = || {
|
||||||
return get_block_fallback_size();
|
let mut get_inline_content_size = || (*inline_content_size).into();
|
||||||
|
SizeConstraint::new(
|
||||||
|
box_size
|
||||||
|
.inline
|
||||||
|
.maybe_resolve_extrinsic(Some(inline_stretch_size)),
|
||||||
|
min_box_size
|
||||||
|
.inline
|
||||||
|
.resolve_non_initial(inline_stretch_size, &mut get_inline_content_size)
|
||||||
|
.unwrap_or_default(),
|
||||||
|
max_box_size
|
||||||
|
.inline
|
||||||
|
.resolve_non_initial(inline_stretch_size, &mut get_inline_content_size),
|
||||||
|
)
|
||||||
};
|
};
|
||||||
let mut get_inline_content_size = || (*inline_content_size).into();
|
self.content_size(
|
||||||
let transfer = |size| ratio.compute_dependent_size(Direction::Block, size);
|
Direction::Block,
|
||||||
let min = transfer(
|
ratio,
|
||||||
min_box_size
|
&get_inline_size,
|
||||||
.inline
|
&get_block_fallback_size,
|
||||||
.resolve_non_initial(inline_stretch_size, &mut get_inline_content_size)
|
)
|
||||||
.unwrap_or_default(),
|
|
||||||
);
|
|
||||||
let max = max_box_size
|
|
||||||
.inline
|
|
||||||
.resolve_non_initial(inline_stretch_size, &mut get_inline_content_size)
|
|
||||||
.map(transfer);
|
|
||||||
box_size
|
|
||||||
.inline
|
|
||||||
.maybe_resolve_extrinsic(Some(inline_stretch_size))
|
|
||||||
.map_or_else(get_block_fallback_size, transfer)
|
|
||||||
.clamp_between_extremums(min, max)
|
|
||||||
});
|
});
|
||||||
let mut get_inline_content_size = || (*inline_content_size).into();
|
let mut get_inline_content_size = || (*inline_content_size).into();
|
||||||
let mut get_block_content_size = || (*block_content_size).into();
|
let mut get_block_content_size = || (*block_content_size).into();
|
||||||
|
|
|
@ -14,7 +14,7 @@ use style::Zero;
|
||||||
|
|
||||||
use crate::geom::Size;
|
use crate::geom::Size;
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
|
use crate::style_ext::{Clamp, ComputedValuesExt, ContentBoxSizesAndPBM};
|
||||||
use crate::{AuOrAuto, IndefiniteContainingBlock, LogicalVec2};
|
use crate::{ConstraintSpace, IndefiniteContainingBlock, LogicalVec2, SizeConstraint};
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub(crate) enum IntrinsicSizingMode {
|
pub(crate) enum IntrinsicSizingMode {
|
||||||
|
@ -120,7 +120,7 @@ pub(crate) fn outer_inline(
|
||||||
containing_block: &IndefiniteContainingBlock,
|
containing_block: &IndefiniteContainingBlock,
|
||||||
auto_minimum: &LogicalVec2<Au>,
|
auto_minimum: &LogicalVec2<Au>,
|
||||||
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(&ConstraintSpace) -> InlineContentSizesResult,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
let ContentBoxSizesAndPBM {
|
let ContentBoxSizesAndPBM {
|
||||||
content_box_size,
|
content_box_size,
|
||||||
|
@ -140,7 +140,7 @@ pub(crate) fn outer_inline(
|
||||||
.block
|
.block
|
||||||
.non_auto()
|
.non_auto()
|
||||||
.map(|v| Au::zero().max(v - pbm_sums.block));
|
.map(|v| Au::zero().max(v - pbm_sums.block));
|
||||||
let block_size = if content_box_size.block.is_initial() &&
|
let preferred_block_size = if content_box_size.block.is_initial() &&
|
||||||
auto_block_size_stretches_to_containing_block
|
auto_block_size_stretches_to_containing_block
|
||||||
{
|
{
|
||||||
depends_on_block_constraints = true;
|
depends_on_block_constraints = true;
|
||||||
|
@ -149,24 +149,18 @@ pub(crate) fn outer_inline(
|
||||||
content_box_size
|
content_box_size
|
||||||
.block
|
.block
|
||||||
.maybe_resolve_extrinsic(available_block_size)
|
.maybe_resolve_extrinsic(available_block_size)
|
||||||
}
|
};
|
||||||
.map(|block_size| {
|
let min_block_size = content_min_box_size
|
||||||
let min_block_size = content_min_box_size
|
.block
|
||||||
.block
|
.maybe_resolve_extrinsic(available_block_size)
|
||||||
.maybe_resolve_extrinsic(available_block_size)
|
.unwrap_or(auto_minimum.block);
|
||||||
.unwrap_or(auto_minimum.block);
|
let max_block_size = content_max_box_size
|
||||||
let max_block_size = content_max_box_size
|
.block
|
||||||
.block
|
.maybe_resolve_extrinsic(available_block_size);
|
||||||
.maybe_resolve_extrinsic(available_block_size);
|
get_content_size(&ConstraintSpace::new(
|
||||||
block_size.clamp_between_extremums(min_block_size, max_block_size)
|
SizeConstraint::new(preferred_block_size, min_block_size, max_block_size),
|
||||||
})
|
style.writing_mode,
|
||||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
|
))
|
||||||
let containing_block_for_children =
|
|
||||||
IndefiniteContainingBlock::new_for_writing_mode_and_block_size(
|
|
||||||
style.writing_mode,
|
|
||||||
block_size,
|
|
||||||
);
|
|
||||||
get_content_size(&containing_block_for_children)
|
|
||||||
});
|
});
|
||||||
let resolve_non_initial = |inline_size| {
|
let resolve_non_initial = |inline_size| {
|
||||||
Some(match inline_size {
|
Some(match inline_size {
|
||||||
|
|
|
@ -16,7 +16,6 @@ use style::computed_values::empty_cells::T as EmptyCells;
|
||||||
use style::computed_values::position::T as Position;
|
use style::computed_values::position::T as Position;
|
||||||
use style::computed_values::table_layout::T as TableLayoutMode;
|
use style::computed_values::table_layout::T as TableLayoutMode;
|
||||||
use style::computed_values::visibility::T as Visibility;
|
use style::computed_values::visibility::T as Visibility;
|
||||||
use style::logical_geometry::WritingMode;
|
|
||||||
use style::properties::ComputedValues;
|
use style::properties::ComputedValues;
|
||||||
use style::values::computed::{
|
use style::values::computed::{
|
||||||
BorderStyle, LengthPercentage as ComputedLengthPercentage, Percentage,
|
BorderStyle, LengthPercentage as ComputedLengthPercentage, Percentage,
|
||||||
|
@ -40,7 +39,7 @@ use crate::positioned::{relative_adjustement, PositioningContext, PositioningCon
|
||||||
use crate::sizing::{ContentSizes, InlineContentSizesResult};
|
use crate::sizing::{ContentSizes, InlineContentSizesResult};
|
||||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||||
use crate::table::TableSlotCoordinates;
|
use crate::table::TableSlotCoordinates;
|
||||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
use crate::{ConstraintSpace, ContainingBlock, IndefiniteContainingBlock, WritingMode};
|
||||||
|
|
||||||
/// A result of a final or speculative layout of a single cell in
|
/// A result of a final or speculative layout of a single cell in
|
||||||
/// the table. Note that this is only done for slots that are not
|
/// the table. Note that this is only done for slots that are not
|
||||||
|
@ -301,9 +300,7 @@ impl<'a> TableLayout<'a> {
|
||||||
.contents
|
.contents
|
||||||
.inline_content_sizes(
|
.inline_content_sizes(
|
||||||
layout_context,
|
layout_context,
|
||||||
&IndefiniteContainingBlock::new_for_writing_mode(
|
&ConstraintSpace::new_for_style(&cell.style),
|
||||||
cell.style.writing_mode,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.sizes
|
.sizes
|
||||||
};
|
};
|
||||||
|
@ -776,8 +773,13 @@ impl<'a> TableLayout<'a> {
|
||||||
|
|
||||||
/// Compute CAPMIN: <https://drafts.csswg.org/css-tables/#capmin>
|
/// Compute CAPMIN: <https://drafts.csswg.org/css-tables/#capmin>
|
||||||
fn compute_caption_minimum_inline_size(&mut self, layout_context: &LayoutContext) -> Au {
|
fn compute_caption_minimum_inline_size(&mut self, layout_context: &LayoutContext) -> Au {
|
||||||
let containing_block =
|
let containing_block = IndefiniteContainingBlock {
|
||||||
IndefiniteContainingBlock::new_for_writing_mode(self.table.style.writing_mode);
|
size: LogicalVec2 {
|
||||||
|
inline: AuOrAuto::Auto,
|
||||||
|
block: AuOrAuto::Auto,
|
||||||
|
},
|
||||||
|
writing_mode: self.table.style.writing_mode,
|
||||||
|
};
|
||||||
self.table
|
self.table
|
||||||
.captions
|
.captions
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -2630,9 +2632,9 @@ impl Table {
|
||||||
pub(crate) fn inline_content_sizes(
|
pub(crate) fn inline_content_sizes(
|
||||||
&mut self,
|
&mut self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
containing_block_for_children: &IndefiniteContainingBlock,
|
constraint_space: &ConstraintSpace,
|
||||||
) -> InlineContentSizesResult {
|
) -> InlineContentSizesResult {
|
||||||
let writing_mode = containing_block_for_children.writing_mode;
|
let writing_mode = constraint_space.writing_mode;
|
||||||
let mut layout = TableLayout::new(self);
|
let mut layout = TableLayout::new(self);
|
||||||
let mut table_content_sizes = layout.compute_grid_min_max(layout_context, writing_mode);
|
let mut table_content_sizes = layout.compute_grid_min_max(layout_context, writing_mode);
|
||||||
|
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[box-sizing-replaced-001.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[box-sizing-replaced-002.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[box-sizing-replaced-003.xht]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[intrinsic-percent-replaced-017.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,6 +0,0 @@
|
||||||
[intrinsic-size-fallback-video.html]
|
|
||||||
[.wrapper 3]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[.wrapper 4]
|
|
||||||
expected: FAIL
|
|
Loading…
Add table
Add a link
Reference in a new issue