mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Auto merge of #26852 - servo:layout-2020-independent-kind, r=SimonSapin
Some more boring stuff to change how we compute content sizes
This commit is contained in:
commit
24cc72ba85
7 changed files with 343 additions and 335 deletions
|
@ -204,7 +204,7 @@ where
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-flexbox/#order-modified-document-order
|
// https://drafts.csswg.org/css-flexbox/#order-modified-document-order
|
||||||
children.sort_by_key(|child| match &*child.borrow() {
|
children.sort_by_key(|child| match &*child.borrow() {
|
||||||
FlexLevelBox::FlexItem(item) => item.style.clone_order(),
|
FlexLevelBox::FlexItem(item) => item.style().clone_order(),
|
||||||
|
|
||||||
// “Absolutely-positioned children of a flex container are treated
|
// “Absolutely-positioned children of a flex container are treated
|
||||||
// as having order: 0 for the purpose of determining their painting order
|
// as having order: 0 for the purpose of determining their painting order
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
|
||||||
use crate::formatting_contexts::IndependentFormattingContext;
|
use crate::formatting_contexts::IndependentFormattingContext;
|
||||||
use crate::fragments::Tag;
|
use crate::fragments::Tag;
|
||||||
use crate::positioned::AbsolutelyPositionedBox;
|
use crate::positioned::AbsolutelyPositionedBox;
|
||||||
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
|
use crate::sizing::{self, BoxContentSizes, ContentSizes, ContentSizesRequest};
|
||||||
use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside};
|
use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, DisplayOutside};
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
use rayon_croissant::ParallelIteratorExt;
|
use rayon_croissant::ParallelIteratorExt;
|
||||||
|
@ -701,10 +701,11 @@ where
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
|
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
|
||||||
to.max_assign(
|
to.max_assign(&sizing::outer_inline(
|
||||||
&box_content_sizes
|
&info.style,
|
||||||
.outer_inline(&info.style, not_actually_containing_block_writing_mode),
|
not_actually_containing_block_writing_mode,
|
||||||
)
|
|| box_content_sizes.expect_inline().clone(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock {
|
let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock {
|
||||||
tag: Tag::from_node_and_style_info(info),
|
tag: Tag::from_node_and_style_info(info),
|
||||||
|
@ -722,7 +723,7 @@ where
|
||||||
max_assign_in_flow_outer_content_sizes_to.is_some() &&
|
max_assign_in_flow_outer_content_sizes_to.is_some() &&
|
||||||
!info.style.inline_size_is_length(),
|
!info.style.inline_size_is_length(),
|
||||||
);
|
);
|
||||||
let contents = IndependentFormattingContext::construct(
|
let context = IndependentFormattingContext::construct(
|
||||||
context,
|
context,
|
||||||
info,
|
info,
|
||||||
display_inside,
|
display_inside,
|
||||||
|
@ -731,15 +732,14 @@ where
|
||||||
propagated_text_decoration_line,
|
propagated_text_decoration_line,
|
||||||
);
|
);
|
||||||
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
|
if let Some(to) = max_assign_in_flow_outer_content_sizes_to {
|
||||||
to.max_assign(
|
to.max_assign(&sizing::outer_inline(
|
||||||
&contents.content_sizes.outer_inline(
|
&context.style(),
|
||||||
&contents.style,
|
|
||||||
not_actually_containing_block_writing_mode,
|
not_actually_containing_block_writing_mode,
|
||||||
),
|
|| context.content_sizes(),
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
ArcRefCell::new(BlockLevelBox::Independent(contents)),
|
ArcRefCell::new(BlockLevelBox::Independent(context)),
|
||||||
ContainsFloats::No,
|
ContainsFloats::No,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,7 +16,7 @@ use crate::positioned::{
|
||||||
relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox,
|
relative_adjustement, AbsolutelyPositionedBox, HoistedAbsolutelyPositionedBox,
|
||||||
PositioningContext,
|
PositioningContext,
|
||||||
};
|
};
|
||||||
use crate::sizing::ContentSizes;
|
use crate::sizing::{self, ContentSizes};
|
||||||
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
|
use crate::style_ext::{ComputedValuesExt, Display, DisplayGeneratingBox, DisplayOutside};
|
||||||
use crate::ContainingBlock;
|
use crate::ContainingBlock;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
|
@ -155,7 +155,7 @@ impl InlineFormattingContext {
|
||||||
impl Computation<'_> {
|
impl Computation<'_> {
|
||||||
fn traverse(&mut self, inline_level_boxes: &[ArcRefCell<InlineLevelBox>]) {
|
fn traverse(&mut self, inline_level_boxes: &[ArcRefCell<InlineLevelBox>]) {
|
||||||
for inline_level_box in inline_level_boxes {
|
for inline_level_box in inline_level_boxes {
|
||||||
match &*inline_level_box.borrow() {
|
match &mut *inline_level_box.borrow_mut() {
|
||||||
InlineLevelBox::InlineBox(inline_box) => {
|
InlineLevelBox::InlineBox(inline_box) => {
|
||||||
let padding =
|
let padding =
|
||||||
inline_box.style.padding(self.containing_block_writing_mode);
|
inline_box.style.padding(self.containing_block_writing_mode);
|
||||||
|
@ -200,9 +200,10 @@ impl InlineFormattingContext {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
InlineLevelBox::Atomic(atomic) => {
|
InlineLevelBox::Atomic(atomic) => {
|
||||||
let (outer, pc) = atomic.content_sizes.outer_inline_and_percentages(
|
let (outer, pc) = sizing::outer_inline_and_percentages(
|
||||||
&atomic.style,
|
&atomic.style(),
|
||||||
self.containing_block_writing_mode,
|
self.containing_block_writing_mode,
|
||||||
|
|| atomic.content_sizes(),
|
||||||
);
|
);
|
||||||
self.current_line.min_content += outer.min_content;
|
self.current_line.min_content += outer.min_content;
|
||||||
self.current_line.max_content += outer.max_content;
|
self.current_line.max_content += outer.max_content;
|
||||||
|
@ -294,7 +295,7 @@ impl InlineFormattingContext {
|
||||||
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
|
InlineLevelBox::TextRun(run) => run.layout(layout_context, &mut ifc),
|
||||||
InlineLevelBox::Atomic(a) => layout_atomic(layout_context, &mut ifc, a),
|
InlineLevelBox::Atomic(a) => layout_atomic(layout_context, &mut ifc, a),
|
||||||
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
InlineLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
||||||
let style = AtomicRef::map(box_.borrow(), |box_| &box_.contents.style);
|
let style = AtomicRef::map(box_.borrow(), |box_| box_.context.style());
|
||||||
let initial_start_corner =
|
let initial_start_corner =
|
||||||
match Display::from(style.get_box().original_display) {
|
match Display::from(style.get_box().original_display) {
|
||||||
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
|
Display::GeneratingBox(DisplayGeneratingBox::OutsideInside {
|
||||||
|
@ -544,7 +545,8 @@ fn layout_atomic(
|
||||||
ifc: &mut InlineFormattingContextState,
|
ifc: &mut InlineFormattingContextState,
|
||||||
atomic: &mut IndependentFormattingContext,
|
atomic: &mut IndependentFormattingContext,
|
||||||
) {
|
) {
|
||||||
let pbm = atomic.style.padding_border_margin(&ifc.containing_block);
|
let style = atomic.style();
|
||||||
|
let pbm = style.padding_border_margin(&ifc.containing_block);
|
||||||
let margin = pbm.margin.auto_is(Length::zero);
|
let margin = pbm.margin.auto_is(Length::zero);
|
||||||
let pbm_sums = &(&pbm.padding + &pbm.border) + &margin;
|
let pbm_sums = &(&pbm.padding + &pbm.border) + &margin;
|
||||||
ifc.inline_position += pbm_sums.inline_start;
|
ifc.inline_position += pbm_sums.inline_start;
|
||||||
|
@ -552,19 +554,24 @@ fn layout_atomic(
|
||||||
block: pbm_sums.block_start,
|
block: pbm_sums.block_start,
|
||||||
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
|
inline: ifc.inline_position - ifc.current_nesting_level.inline_start,
|
||||||
};
|
};
|
||||||
if atomic.style.clone_position().is_relative() {
|
if style.clone_position().is_relative() {
|
||||||
start_corner += &relative_adjustement(&atomic.style, ifc.containing_block)
|
start_corner += &relative_adjustement(&style, ifc.containing_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
let fragment = match atomic.as_replaced() {
|
let fragment = match atomic {
|
||||||
Ok(replaced) => {
|
IndependentFormattingContext::Replaced(replaced) => {
|
||||||
let size =
|
let size = replaced.contents.used_size_as_if_inline_element(
|
||||||
replaced.used_size_as_if_inline_element(ifc.containing_block, &atomic.style, &pbm);
|
ifc.containing_block,
|
||||||
let fragments = replaced.make_fragments(&atomic.style, size.clone());
|
&replaced.style,
|
||||||
|
&pbm,
|
||||||
|
);
|
||||||
|
let fragments = replaced
|
||||||
|
.contents
|
||||||
|
.make_fragments(&replaced.style, size.clone());
|
||||||
let content_rect = Rect { start_corner, size };
|
let content_rect = Rect { start_corner, size };
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
atomic.tag,
|
replaced.tag,
|
||||||
atomic.style.clone(),
|
replaced.style.clone(),
|
||||||
fragments,
|
fragments,
|
||||||
content_rect,
|
content_rect,
|
||||||
pbm.padding,
|
pbm.padding,
|
||||||
|
@ -573,12 +580,14 @@ fn layout_atomic(
|
||||||
CollapsedBlockMargins::zero(),
|
CollapsedBlockMargins::zero(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
Err(non_replaced) => {
|
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||||
let box_size = atomic.style.content_box_size(&ifc.containing_block, &pbm);
|
let box_size = non_replaced
|
||||||
let max_box_size = atomic
|
.style
|
||||||
|
.content_box_size(&ifc.containing_block, &pbm);
|
||||||
|
let max_box_size = non_replaced
|
||||||
.style
|
.style
|
||||||
.content_max_box_size(&ifc.containing_block, &pbm);
|
.content_max_box_size(&ifc.containing_block, &pbm);
|
||||||
let min_box_size = atomic
|
let min_box_size = non_replaced
|
||||||
.style
|
.style
|
||||||
.content_min_box_size(&ifc.containing_block, &pbm)
|
.content_min_box_size(&ifc.containing_block, &pbm)
|
||||||
.auto_is(Length::zero);
|
.auto_is(Length::zero);
|
||||||
|
@ -586,7 +595,7 @@ fn layout_atomic(
|
||||||
// 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.auto_is(|| {
|
let tentative_inline_size = box_size.inline.auto_is(|| {
|
||||||
let available_size = ifc.containing_block.inline_size - pbm_sums.inline_sum();
|
let available_size = ifc.containing_block.inline_size - pbm_sums.inline_sum();
|
||||||
atomic.content_sizes.shrink_to_fit(available_size)
|
non_replaced.content_sizes.shrink_to_fit(available_size)
|
||||||
});
|
});
|
||||||
|
|
||||||
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
||||||
|
@ -598,7 +607,7 @@ fn layout_atomic(
|
||||||
let containing_block_for_children = ContainingBlock {
|
let containing_block_for_children = ContainingBlock {
|
||||||
inline_size,
|
inline_size,
|
||||||
block_size: box_size.block,
|
block_size: box_size.block,
|
||||||
style: &atomic.style,
|
style: &non_replaced.style,
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ifc.containing_block.style.writing_mode,
|
ifc.containing_block.style.writing_mode,
|
||||||
|
@ -634,8 +643,8 @@ fn layout_atomic(
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
atomic.tag,
|
non_replaced.tag,
|
||||||
atomic.style.clone(),
|
non_replaced.style.clone(),
|
||||||
independent_layout.fragments,
|
independent_layout.fragments,
|
||||||
content_rect,
|
content_rect,
|
||||||
pbm.padding,
|
pbm.padding,
|
||||||
|
|
|
@ -8,7 +8,9 @@ use crate::cell::ArcRefCell;
|
||||||
use crate::context::LayoutContext;
|
use crate::context::LayoutContext;
|
||||||
use crate::flow::float::{FloatBox, FloatContext};
|
use crate::flow::float::{FloatBox, FloatContext};
|
||||||
use crate::flow::inline::InlineFormattingContext;
|
use crate::flow::inline::InlineFormattingContext;
|
||||||
use crate::formatting_contexts::{IndependentFormattingContext, IndependentLayout, NonReplacedIFC};
|
use crate::formatting_contexts::{
|
||||||
|
IndependentFormattingContext, IndependentLayout, NonReplacedFormattingContext,
|
||||||
|
};
|
||||||
use crate::fragments::{
|
use crate::fragments::{
|
||||||
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
|
AbsoluteOrFixedPositionedFragment, AnonymousFragment, BoxFragment, CollapsedBlockMargins,
|
||||||
CollapsedMargin, Fragment, Tag,
|
CollapsedMargin, Fragment, Tag,
|
||||||
|
@ -288,33 +290,44 @@ impl BlockLevelBox {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
BlockLevelBox::Independent(contents) => {
|
BlockLevelBox::Independent(independent) => match independent {
|
||||||
|
IndependentFormattingContext::Replaced(replaced) => {
|
||||||
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
|
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
|
||||||
layout_context,
|
layout_context,
|
||||||
containing_block,
|
containing_block,
|
||||||
&contents.style,
|
&replaced.style,
|
||||||
|positioning_context| match contents.as_replaced() {
|
|_positioning_context| {
|
||||||
Ok(replaced) => layout_in_flow_replaced_block_level(
|
layout_in_flow_replaced_block_level(
|
||||||
containing_block,
|
containing_block,
|
||||||
contents.tag,
|
replaced.tag,
|
||||||
&contents.style,
|
&replaced.style,
|
||||||
replaced,
|
&replaced.contents,
|
||||||
),
|
)
|
||||||
Err(non_replaced) => layout_in_flow_non_replaced_block_level(
|
},
|
||||||
|
))
|
||||||
|
},
|
||||||
|
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||||
|
Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
|
||||||
|
layout_context,
|
||||||
|
containing_block,
|
||||||
|
&non_replaced.style,
|
||||||
|
|positioning_context| {
|
||||||
|
layout_in_flow_non_replaced_block_level(
|
||||||
layout_context,
|
layout_context,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
containing_block,
|
containing_block,
|
||||||
contents.tag,
|
non_replaced.tag,
|
||||||
&contents.style,
|
&non_replaced.style,
|
||||||
NonReplacedContents::EstablishesAnIndependentFormattingContext(
|
NonReplacedContents::EstablishesAnIndependentFormattingContext(
|
||||||
non_replaced,
|
non_replaced,
|
||||||
),
|
),
|
||||||
tree_rank,
|
tree_rank,
|
||||||
float_context,
|
float_context,
|
||||||
),
|
)
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
|
},
|
||||||
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
|
||||||
let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
|
let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
|
||||||
box_.clone(),
|
box_.clone(),
|
||||||
|
@ -326,7 +339,7 @@ impl BlockLevelBox {
|
||||||
positioning_context.push(hoisted_box);
|
positioning_context.push(hoisted_box);
|
||||||
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment {
|
Fragment::AbsoluteOrFixedPositioned(AbsoluteOrFixedPositionedFragment {
|
||||||
hoisted_fragment,
|
hoisted_fragment,
|
||||||
position: box_.borrow().contents.style.clone_position(),
|
position: box_.borrow().context.style().clone_position(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
|
BlockLevelBox::OutOfFlowFloatBox(_box_) => {
|
||||||
|
@ -341,7 +354,7 @@ impl BlockLevelBox {
|
||||||
|
|
||||||
enum NonReplacedContents<'a> {
|
enum NonReplacedContents<'a> {
|
||||||
SameFormattingContextBlock(&'a BlockContainer),
|
SameFormattingContextBlock(&'a BlockContainer),
|
||||||
EstablishesAnIndependentFormattingContext(NonReplacedIFC<'a>),
|
EstablishesAnIndependentFormattingContext(&'a NonReplacedFormattingContext),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css2/visudet.html#blockwidth
|
/// https://drafts.csswg.org/css2/visudet.html#blockwidth
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::flow::BlockFormattingContext;
|
||||||
use crate::fragments::{Fragment, Tag};
|
use crate::fragments::{Fragment, Tag};
|
||||||
use crate::positioned::PositioningContext;
|
use crate::positioned::PositioningContext;
|
||||||
use crate::replaced::ReplacedContent;
|
use crate::replaced::ReplacedContent;
|
||||||
use crate::sizing::{BoxContentSizes, ContentSizesRequest};
|
use crate::sizing::{BoxContentSizes, ContentSizes, ContentSizesRequest};
|
||||||
use crate::style_ext::DisplayInside;
|
use crate::style_ext::DisplayInside;
|
||||||
use crate::ContainingBlock;
|
use crate::ContainingBlock;
|
||||||
use servo_arc::Arc;
|
use servo_arc::Arc;
|
||||||
|
@ -20,15 +20,36 @@ use style::values::specified::text::TextDecorationLine;
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-display/#independent-formatting-context
|
/// https://drafts.csswg.org/css-display/#independent-formatting-context
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub(crate) struct IndependentFormattingContext {
|
pub(crate) enum IndependentFormattingContext {
|
||||||
|
NonReplaced(NonReplacedFormattingContext),
|
||||||
|
Replaced(ReplacedFormattingContext),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub(crate) struct NonReplacedFormattingContext {
|
||||||
pub tag: Tag,
|
pub tag: Tag,
|
||||||
#[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: BoxContentSizes,
|
pub content_sizes: BoxContentSizes,
|
||||||
|
pub contents: NonReplacedFormattingContextContents,
|
||||||
|
}
|
||||||
|
|
||||||
contents: IndependentFormattingContextContents,
|
#[derive(Debug, Serialize)]
|
||||||
|
pub(crate) struct ReplacedFormattingContext {
|
||||||
|
pub tag: Tag,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub style: Arc<ComputedValues>,
|
||||||
|
pub contents: ReplacedContent,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private so that code outside of this module cannot match variants.
|
||||||
|
// It should got through methods instead.
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
pub(crate) enum NonReplacedFormattingContextContents {
|
||||||
|
Flow(BlockFormattingContext),
|
||||||
|
Flex(FlexContainer),
|
||||||
|
// Other layout modes go here
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct IndependentLayout {
|
pub(crate) struct IndependentLayout {
|
||||||
|
@ -38,25 +59,6 @@ pub(crate) struct IndependentLayout {
|
||||||
pub content_block_size: Length,
|
pub content_block_size: Length,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Private so that code outside of this module cannot match variants.
|
|
||||||
// It should got through methods instead.
|
|
||||||
#[derive(Debug, Serialize)]
|
|
||||||
enum IndependentFormattingContextContents {
|
|
||||||
Flow(BlockFormattingContext),
|
|
||||||
Flex(FlexContainer),
|
|
||||||
|
|
||||||
// Not called FC in specs, but behaves close enough
|
|
||||||
Replaced(ReplacedContent),
|
|
||||||
// Other layout modes go here
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct NonReplacedIFC<'a>(NonReplacedIFCKind<'a>);
|
|
||||||
|
|
||||||
enum NonReplacedIFCKind<'a> {
|
|
||||||
Flow(&'a BlockFormattingContext),
|
|
||||||
Flex(&'a FlexContainer),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IndependentFormattingContext {
|
impl IndependentFormattingContext {
|
||||||
pub fn construct<'dom>(
|
pub fn construct<'dom>(
|
||||||
context: &LayoutContext,
|
context: &LayoutContext,
|
||||||
|
@ -76,12 +78,12 @@ impl IndependentFormattingContext {
|
||||||
content_sizes,
|
content_sizes,
|
||||||
propagated_text_decoration_line,
|
propagated_text_decoration_line,
|
||||||
);
|
);
|
||||||
Self {
|
Self::NonReplaced(NonReplacedFormattingContext {
|
||||||
tag: Tag::from_node_and_style_info(info),
|
tag: Tag::from_node_and_style_info(info),
|
||||||
style: Arc::clone(&info.style),
|
style: Arc::clone(&info.style),
|
||||||
content_sizes,
|
content_sizes,
|
||||||
contents: IndependentFormattingContextContents::Flow(bfc),
|
contents: NonReplacedFormattingContextContents::Flow(bfc),
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
DisplayInside::Flex => {
|
DisplayInside::Flex => {
|
||||||
let (fc, content_sizes) = FlexContainer::construct(
|
let (fc, content_sizes) = FlexContainer::construct(
|
||||||
|
@ -91,24 +93,19 @@ impl IndependentFormattingContext {
|
||||||
content_sizes,
|
content_sizes,
|
||||||
propagated_text_decoration_line,
|
propagated_text_decoration_line,
|
||||||
);
|
);
|
||||||
Self {
|
Self::NonReplaced(NonReplacedFormattingContext {
|
||||||
tag: Tag::from_node_and_style_info(info),
|
tag: Tag::from_node_and_style_info(info),
|
||||||
style: Arc::clone(&info.style),
|
style: Arc::clone(&info.style),
|
||||||
content_sizes,
|
content_sizes,
|
||||||
contents: IndependentFormattingContextContents::Flex(fc),
|
contents: NonReplacedFormattingContextContents::Flex(fc),
|
||||||
}
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Err(replaced) => {
|
Err(contents) => Self::Replaced(ReplacedFormattingContext {
|
||||||
let content_sizes =
|
|
||||||
content_sizes.compute(|| replaced.inline_content_sizes(&info.style));
|
|
||||||
Self {
|
|
||||||
tag: Tag::from_node_and_style_info(info),
|
tag: Tag::from_node_and_style_info(info),
|
||||||
style: Arc::clone(&info.style),
|
style: Arc::clone(&info.style),
|
||||||
content_sizes,
|
contents,
|
||||||
contents: IndependentFormattingContextContents::Replaced(replaced),
|
}),
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,27 +122,37 @@ impl IndependentFormattingContext {
|
||||||
content_sizes,
|
content_sizes,
|
||||||
propagated_text_decoration_line,
|
propagated_text_decoration_line,
|
||||||
);
|
);
|
||||||
Self {
|
Self::NonReplaced(NonReplacedFormattingContext {
|
||||||
tag: Tag::from_node_and_style_info(info),
|
tag: Tag::from_node_and_style_info(info),
|
||||||
style: Arc::clone(&info.style),
|
style: Arc::clone(&info.style),
|
||||||
content_sizes,
|
content_sizes,
|
||||||
contents: IndependentFormattingContextContents::Flow(bfc),
|
contents: NonReplacedFormattingContextContents::Flow(bfc),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn style(&self) -> &Arc<ComputedValues> {
|
||||||
|
match self {
|
||||||
|
Self::NonReplaced(inner) => &inner.style,
|
||||||
|
Self::Replaced(inner) => &inner.style,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_replaced(&self) -> Result<&ReplacedContent, NonReplacedIFC> {
|
pub fn tag(&self) -> Tag {
|
||||||
use self::IndependentFormattingContextContents as Contents;
|
match self {
|
||||||
use self::NonReplacedIFC as NR;
|
Self::NonReplaced(inner) => inner.tag,
|
||||||
use self::NonReplacedIFCKind as Kind;
|
Self::Replaced(inner) => inner.tag,
|
||||||
match &self.contents {
|
}
|
||||||
Contents::Replaced(r) => Ok(r),
|
}
|
||||||
Contents::Flow(f) => Err(NR(Kind::Flow(f))),
|
|
||||||
Contents::Flex(f) => Err(NR(Kind::Flex(f))),
|
pub fn content_sizes(&self) -> ContentSizes {
|
||||||
|
match self {
|
||||||
|
Self::NonReplaced(inner) => inner.content_sizes.expect_inline().clone(),
|
||||||
|
Self::Replaced(inner) => inner.contents.inline_content_sizes(&inner.style),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonReplacedIFC<'_> {
|
impl NonReplacedFormattingContext {
|
||||||
pub fn layout(
|
pub fn layout(
|
||||||
&self,
|
&self,
|
||||||
layout_context: &LayoutContext,
|
layout_context: &LayoutContext,
|
||||||
|
@ -153,14 +160,14 @@ impl NonReplacedIFC<'_> {
|
||||||
containing_block: &ContainingBlock,
|
containing_block: &ContainingBlock,
|
||||||
tree_rank: usize,
|
tree_rank: usize,
|
||||||
) -> IndependentLayout {
|
) -> IndependentLayout {
|
||||||
match &self.0 {
|
match &self.contents {
|
||||||
NonReplacedIFCKind::Flow(bfc) => bfc.layout(
|
NonReplacedFormattingContextContents::Flow(bfc) => bfc.layout(
|
||||||
layout_context,
|
layout_context,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
containing_block,
|
containing_block,
|
||||||
tree_rank,
|
tree_rank,
|
||||||
),
|
),
|
||||||
NonReplacedIFCKind::Flex(fc) => fc.layout(
|
NonReplacedFormattingContextContents::Flex(fc) => fc.layout(
|
||||||
layout_context,
|
layout_context,
|
||||||
positioning_context,
|
positioning_context,
|
||||||
containing_block,
|
containing_block,
|
||||||
|
|
|
@ -22,7 +22,7 @@ use style::Zero;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub(crate) struct AbsolutelyPositionedBox {
|
pub(crate) struct AbsolutelyPositionedBox {
|
||||||
pub contents: IndependentFormattingContext,
|
pub context: IndependentFormattingContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct PositioningContext {
|
pub(crate) struct PositioningContext {
|
||||||
|
@ -84,7 +84,7 @@ impl AbsolutelyPositionedBox {
|
||||||
!node_info.style.inline_box_offsets_are_both_non_auto(),
|
!node_info.style.inline_box_offsets_are_both_non_auto(),
|
||||||
);
|
);
|
||||||
Self {
|
Self {
|
||||||
contents: IndependentFormattingContext::construct(
|
context: IndependentFormattingContext::construct(
|
||||||
context,
|
context,
|
||||||
node_info,
|
node_info,
|
||||||
display_inside,
|
display_inside,
|
||||||
|
@ -124,7 +124,7 @@ impl AbsolutelyPositionedBox {
|
||||||
|
|
||||||
let box_offsets = {
|
let box_offsets = {
|
||||||
let box_ = self_.borrow();
|
let box_ = self_.borrow();
|
||||||
let box_offsets = box_.contents.style.box_offsets(containing_block);
|
let box_offsets = box_.context.style().box_offsets(containing_block);
|
||||||
Vec2 {
|
Vec2 {
|
||||||
inline: absolute_box_offsets(
|
inline: absolute_box_offsets(
|
||||||
initial_start_corner.inline,
|
initial_start_corner.inline,
|
||||||
|
@ -218,27 +218,6 @@ impl PositioningContext {
|
||||||
new_fragment
|
new_fragment
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given `fragment_layout_fn`, a closure which lays out a fragment in a provided
|
|
||||||
/// `PositioningContext`, create a positioning context for a positioned fragment and lay out
|
|
||||||
/// the fragment and all its children. Returns the resulting `BoxFragment`.
|
|
||||||
fn create_and_layout_positioned(
|
|
||||||
layout_context: &LayoutContext,
|
|
||||||
style: &ComputedValues,
|
|
||||||
for_nearest_containing_block_for_all_descendants: &mut Vec<HoistedAbsolutelyPositionedBox>,
|
|
||||||
fragment_layout_fn: impl FnOnce(&mut Self) -> BoxFragment,
|
|
||||||
) -> BoxFragment {
|
|
||||||
let mut new_context = match Self::new_for_style(style) {
|
|
||||||
Some(new_context) => new_context,
|
|
||||||
None => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut new_fragment = fragment_layout_fn(&mut new_context);
|
|
||||||
new_context.layout_collected_children(layout_context, &mut new_fragment);
|
|
||||||
for_nearest_containing_block_for_all_descendants
|
|
||||||
.extend(new_context.for_nearest_containing_block_for_all_descendants);
|
|
||||||
new_fragment
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lay out the hoisted boxes collected into this `PositioningContext` and add them
|
// Lay out the hoisted boxes collected into this `PositioningContext` and add them
|
||||||
// to the given `BoxFragment`.
|
// to the given `BoxFragment`.
|
||||||
pub fn layout_collected_children(
|
pub fn layout_collected_children(
|
||||||
|
@ -288,8 +267,8 @@ impl PositioningContext {
|
||||||
let position = box_
|
let position = box_
|
||||||
.absolutely_positioned_box
|
.absolutely_positioned_box
|
||||||
.borrow()
|
.borrow()
|
||||||
.contents
|
.context
|
||||||
.style
|
.style()
|
||||||
.clone_position();
|
.clone_position();
|
||||||
match position {
|
match position {
|
||||||
Position::Fixed => {}, // fall through
|
Position::Fixed => {}, // fall through
|
||||||
|
@ -416,29 +395,30 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
) -> BoxFragment {
|
) -> BoxFragment {
|
||||||
let cbis = containing_block.size.inline;
|
let cbis = containing_block.size.inline;
|
||||||
let cbbs = containing_block.size.block;
|
let cbbs = containing_block.size.block;
|
||||||
let absolutely_positioned_box = self.absolutely_positioned_box.borrow_mut();
|
let mut absolutely_positioned_box = self.absolutely_positioned_box.borrow_mut();
|
||||||
let style = &absolutely_positioned_box.contents.style;
|
let pbm = absolutely_positioned_box
|
||||||
let pbm = style.padding_border_margin(&containing_block.into());
|
.context
|
||||||
|
.style()
|
||||||
|
.padding_border_margin(&containing_block.into());
|
||||||
|
|
||||||
let size;
|
let size = match &absolutely_positioned_box.context {
|
||||||
let replaced_used_size;
|
IndependentFormattingContext::Replaced(replaced) => {
|
||||||
match absolutely_positioned_box.contents.as_replaced() {
|
|
||||||
Ok(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 used_size =
|
let used_size = replaced.contents.used_size_as_if_inline_element(
|
||||||
replaced.used_size_as_if_inline_element(&containing_block.into(), style, &pbm);
|
&containing_block.into(),
|
||||||
size = Vec2 {
|
&replaced.style,
|
||||||
|
&pbm,
|
||||||
|
);
|
||||||
|
Vec2 {
|
||||||
inline: LengthOrAuto::LengthPercentage(used_size.inline),
|
inline: LengthOrAuto::LengthPercentage(used_size.inline),
|
||||||
block: LengthOrAuto::LengthPercentage(used_size.block),
|
block: LengthOrAuto::LengthPercentage(used_size.block),
|
||||||
};
|
|
||||||
replaced_used_size = Some(used_size);
|
|
||||||
},
|
|
||||||
Err(_non_replaced) => {
|
|
||||||
size = style.content_box_size(&containing_block.into(), &pbm);
|
|
||||||
replaced_used_size = None;
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
IndependentFormattingContext::NonReplaced(non_replaced) => non_replaced
|
||||||
|
.style
|
||||||
|
.content_box_size(&containing_block.into(), &pbm),
|
||||||
|
};
|
||||||
|
|
||||||
let inline_axis = solve_axis(
|
let inline_axis = solve_axis(
|
||||||
cbis,
|
cbis,
|
||||||
|
@ -467,22 +447,22 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
block_end: block_axis.margin_end,
|
block_end: block_axis.margin_end,
|
||||||
};
|
};
|
||||||
|
|
||||||
PositioningContext::create_and_layout_positioned(
|
let mut positioning_context =
|
||||||
layout_context,
|
PositioningContext::new_for_style(absolutely_positioned_box.context.style()).unwrap();
|
||||||
style,
|
let mut new_fragment = {
|
||||||
for_nearest_containing_block_for_all_descendants,
|
let content_size;
|
||||||
|positioning_context| {
|
|
||||||
let size;
|
|
||||||
let fragments;
|
let fragments;
|
||||||
match absolutely_positioned_box.contents.as_replaced() {
|
match &mut absolutely_positioned_box.context {
|
||||||
Ok(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 style = &absolutely_positioned_box.contents.style;
|
let style = &replaced.style;
|
||||||
size = replaced_used_size.unwrap();
|
content_size = size.auto_is(|| unreachable!());
|
||||||
fragments = replaced.make_fragments(style, size.clone());
|
fragments = replaced
|
||||||
|
.contents
|
||||||
|
.make_fragments(style, content_size.clone());
|
||||||
},
|
},
|
||||||
Err(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.auto_is(|| {
|
let inline_size = inline_axis.size.auto_is(|| {
|
||||||
|
@ -490,20 +470,15 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
Anchor::Start(start) => start,
|
Anchor::Start(start) => start,
|
||||||
Anchor::End(end) => end,
|
Anchor::End(end) => end,
|
||||||
};
|
};
|
||||||
let available_size = cbis -
|
let available_size =
|
||||||
anchor -
|
cbis - anchor - pbm.padding_border_sums.inline - margin.inline_sum();
|
||||||
pbm.padding_border_sums.inline -
|
non_replaced.content_sizes.shrink_to_fit(available_size)
|
||||||
margin.inline_sum();
|
|
||||||
absolutely_positioned_box
|
|
||||||
.contents
|
|
||||||
.content_sizes
|
|
||||||
.shrink_to_fit(available_size)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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,
|
||||||
style,
|
style: &non_replaced.style,
|
||||||
};
|
};
|
||||||
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
|
// https://drafts.csswg.org/css-writing-modes/#orthogonal-flows
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -514,12 +489,12 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
let dummy_tree_rank = 0;
|
let dummy_tree_rank = 0;
|
||||||
let independent_layout = non_replaced.layout(
|
let independent_layout = non_replaced.layout(
|
||||||
layout_context,
|
layout_context,
|
||||||
positioning_context,
|
&mut positioning_context,
|
||||||
&containing_block_for_children,
|
&containing_block_for_children,
|
||||||
dummy_tree_rank,
|
dummy_tree_rank,
|
||||||
);
|
);
|
||||||
|
|
||||||
size = Vec2 {
|
content_size = Vec2 {
|
||||||
inline: inline_size,
|
inline: inline_size,
|
||||||
block: block_axis
|
block: block_axis
|
||||||
.size
|
.size
|
||||||
|
@ -533,12 +508,14 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
let inline_start = match inline_axis.anchor {
|
let inline_start = match inline_axis.anchor {
|
||||||
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
|
Anchor::Start(start) => start + pb.inline_start + margin.inline_start,
|
||||||
Anchor::End(end) => {
|
Anchor::End(end) => {
|
||||||
cbis - end - pb.inline_end - margin.inline_end - size.inline
|
cbis - end - pb.inline_end - margin.inline_end - content_size.inline
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let block_start = match block_axis.anchor {
|
let block_start = match block_axis.anchor {
|
||||||
Anchor::Start(start) => start + pb.block_start + margin.block_start,
|
Anchor::Start(start) => start + pb.block_start + margin.block_start,
|
||||||
Anchor::End(end) => cbbs - end - pb.block_end - margin.block_end - size.block,
|
Anchor::End(end) => {
|
||||||
|
cbbs - end - pb.block_end - margin.block_end - content_size.block
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let content_rect = Rect {
|
let content_rect = Rect {
|
||||||
|
@ -546,12 +523,12 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
inline: inline_start,
|
inline: inline_start,
|
||||||
block: block_start,
|
block: block_start,
|
||||||
},
|
},
|
||||||
size,
|
size: content_size,
|
||||||
};
|
};
|
||||||
|
|
||||||
BoxFragment::new(
|
BoxFragment::new(
|
||||||
absolutely_positioned_box.contents.tag,
|
absolutely_positioned_box.context.tag(),
|
||||||
style.clone(),
|
absolutely_positioned_box.context.style().clone(),
|
||||||
fragments,
|
fragments,
|
||||||
content_rect,
|
content_rect,
|
||||||
pbm.padding,
|
pbm.padding,
|
||||||
|
@ -559,8 +536,11 @@ impl HoistedAbsolutelyPositionedBox {
|
||||||
margin,
|
margin,
|
||||||
CollapsedBlockMargins::zero(),
|
CollapsedBlockMargins::zero(),
|
||||||
)
|
)
|
||||||
},
|
};
|
||||||
)
|
positioning_context.layout_collected_children(layout_context, &mut new_fragment);
|
||||||
|
for_nearest_containing_block_for_all_descendants
|
||||||
|
.extend(positioning_context.for_nearest_containing_block_for_all_descendants);
|
||||||
|
new_fragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ impl ContentSizes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(&self, f: impl Fn(Length) -> Length) -> Self {
|
pub fn map(&self, f: impl Fn(Length) -> Length) -> Self {
|
||||||
Self {
|
Self {
|
||||||
min_content: f(self.min_content),
|
min_content: f(self.min_content),
|
||||||
max_content: f(self.max_content),
|
max_content: f(self.max_content),
|
||||||
|
@ -98,29 +98,37 @@ pub(crate) enum BoxContentSizes {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxContentSizes {
|
impl BoxContentSizes {
|
||||||
fn expect_inline(&self) -> &ContentSizes {
|
pub fn expect_inline(&self) -> &ContentSizes {
|
||||||
match self {
|
match self {
|
||||||
Self::NoneWereRequested => panic!("Accessing content size that was not requested"),
|
Self::NoneWereRequested => panic!("Accessing content size that was not requested"),
|
||||||
Self::Inline(s) => s,
|
Self::Inline(s) => s,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://dbaron.org/css/intrinsic/#outer-intrinsic
|
/// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float
|
||||||
pub fn outer_inline(
|
pub(crate) fn shrink_to_fit(&self, available_size: Length) -> Length {
|
||||||
&self,
|
let inline = self.expect_inline();
|
||||||
|
available_size
|
||||||
|
.max(inline.min_content)
|
||||||
|
.min(inline.max_content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn outer_inline(
|
||||||
style: &ComputedValues,
|
style: &ComputedValues,
|
||||||
containing_block_writing_mode: WritingMode,
|
containing_block_writing_mode: WritingMode,
|
||||||
|
get_content_size: impl FnOnce() -> ContentSizes,
|
||||||
) -> ContentSizes {
|
) -> ContentSizes {
|
||||||
let (mut outer, percentages) =
|
let (mut outer, percentages) =
|
||||||
self.outer_inline_and_percentages(style, containing_block_writing_mode);
|
outer_inline_and_percentages(style, containing_block_writing_mode, get_content_size);
|
||||||
outer.adjust_for_pbm_percentages(percentages);
|
outer.adjust_for_pbm_percentages(percentages);
|
||||||
outer
|
outer
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn outer_inline_and_percentages(
|
pub(crate) fn outer_inline_and_percentages(
|
||||||
&self,
|
|
||||||
style: &ComputedValues,
|
style: &ComputedValues,
|
||||||
containing_block_writing_mode: WritingMode,
|
containing_block_writing_mode: WritingMode,
|
||||||
|
get_content_size: impl FnOnce() -> ContentSizes,
|
||||||
) -> (ContentSizes, Percentage) {
|
) -> (ContentSizes, Percentage) {
|
||||||
let padding = style.padding(containing_block_writing_mode);
|
let padding = style.padding(containing_block_writing_mode);
|
||||||
let border = style.border_width(containing_block_writing_mode);
|
let border = style.border_width(containing_block_writing_mode);
|
||||||
|
@ -174,7 +182,7 @@ impl BoxContentSizes {
|
||||||
max_content: border_box_size,
|
max_content: border_box_size,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => self.expect_inline().map(|content_box_size| {
|
None => get_content_size().map(|content_box_size| {
|
||||||
match box_sizing {
|
match box_sizing {
|
||||||
// Clamp to 'min-width' and 'max-width', which are sizing the…
|
// Clamp to 'min-width' and 'max-width', which are sizing the…
|
||||||
BoxSizing::ContentBox => clamp(content_box_size) + pb_lengths,
|
BoxSizing::ContentBox => clamp(content_box_size) + pb_lengths,
|
||||||
|
@ -186,12 +194,3 @@ impl BoxContentSizes {
|
||||||
let outer = border_box_sizes.map(|s| s + m_lengths);
|
let outer = border_box_sizes.map(|s| s + m_lengths);
|
||||||
(outer, pbm_percentages)
|
(outer, pbm_percentages)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css2/visudet.html#shrink-to-fit-float
|
|
||||||
pub(crate) fn shrink_to_fit(&self, available_size: Length) -> Length {
|
|
||||||
let inline = self.expect_inline();
|
|
||||||
available_size
|
|
||||||
.max(inline.min_content)
|
|
||||||
.min(inline.max_content)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue