mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Unify logic for laying out floats and atomic inlines (#33802)
Signed-off-by: Oriol Brufau <obrufau@igalia.com>
This commit is contained in:
parent
0eb8d22d88
commit
a86dcfc6e7
4 changed files with 224 additions and 320 deletions
|
@ -26,11 +26,11 @@ use crate::context::LayoutContext;
|
|||
use crate::dom::NodeExt;
|
||||
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
|
||||
use crate::formatting_contexts::IndependentFormattingContext;
|
||||
use crate::fragment_tree::{BoxFragment, CollapsedBlockMargins, CollapsedMargin};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, PhysicalPoint, PhysicalRect, Size, ToLogical};
|
||||
use crate::fragment_tree::{BoxFragment, CollapsedMargin};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
||||
use crate::positioned::{relative_adjustement, PositioningContext};
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, DisplayInside, PaddingBorderMargin};
|
||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
|
||||
use crate::style_ext::{DisplayInside, PaddingBorderMargin};
|
||||
use crate::ContainingBlock;
|
||||
|
||||
/// A floating box.
|
||||
#[derive(Debug, Serialize)]
|
||||
|
@ -902,145 +902,13 @@ impl FloatBox {
|
|||
containing_block,
|
||||
&style,
|
||||
|positioning_context| {
|
||||
// Margin is computed this way regardless of whether the element is replaced
|
||||
// or non-replaced.
|
||||
let pbm = style.padding_border_margin(containing_block);
|
||||
let margin = pbm.margin.auto_is(Au::zero);
|
||||
let pbm_sums = pbm.padding + pbm.border + margin;
|
||||
|
||||
let (content_size, children);
|
||||
match self.contents {
|
||||
IndependentFormattingContext::NonReplaced(ref mut non_replaced) => {
|
||||
// Calculate inline size.
|
||||
// https://drafts.csswg.org/css2/#float-width
|
||||
let style = non_replaced.style.clone();
|
||||
let box_size = style.content_box_size(containing_block, &pbm);
|
||||
let max_box_size = style.content_max_box_size(containing_block, &pbm);
|
||||
let min_box_size = style.content_min_box_size(containing_block, &pbm);
|
||||
let available_inline_size =
|
||||
containing_block.inline_size - pbm_sums.inline_sum();
|
||||
let available_block_size = containing_block
|
||||
.block_size
|
||||
.non_auto()
|
||||
.map(|block_size| block_size - pbm_sums.block_sum());
|
||||
let tentative_block_size = box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.map(|size| {
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = 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 containing_block_for_children =
|
||||
IndefiniteContainingBlock::new_for_style_and_block_size(
|
||||
&style,
|
||||
tentative_block_size,
|
||||
);
|
||||
non_replaced.inline_content_sizes(
|
||||
layout_context,
|
||||
&containing_block_for_children,
|
||||
)
|
||||
};
|
||||
let tentative_inline_size = box_size.inline.resolve(
|
||||
Size::fit_content,
|
||||
available_inline_size,
|
||||
&mut get_content_size,
|
||||
);
|
||||
let min_inline_size = min_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_inline_size = max_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size);
|
||||
let inline_size = tentative_inline_size
|
||||
.clamp_between_extremums(min_inline_size, max_inline_size);
|
||||
|
||||
// Calculate block size.
|
||||
// https://drafts.csswg.org/css2/#block-root-margin
|
||||
// FIXME(pcwalton): Is a tree rank of zero correct here?
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size,
|
||||
block_size: tentative_block_size,
|
||||
style: &non_replaced.style,
|
||||
};
|
||||
let independent_layout = non_replaced.layout(
|
||||
layout_context,
|
||||
positioning_context,
|
||||
&containing_block_for_children,
|
||||
containing_block,
|
||||
);
|
||||
let (block_size, inline_size) =
|
||||
match independent_layout.content_inline_size_for_table {
|
||||
Some(inline_size) => {
|
||||
(independent_layout.content_block_size, inline_size)
|
||||
},
|
||||
None => {
|
||||
let stretch_size = available_block_size
|
||||
.unwrap_or(independent_layout.content_block_size);
|
||||
let mut get_content_size =
|
||||
|| independent_layout.content_block_size.into();
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = max_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size);
|
||||
let block_size = tentative_block_size
|
||||
.auto_is(|| independent_layout.content_block_size)
|
||||
.clamp_between_extremums(min_block_size, max_block_size);
|
||||
(block_size, inline_size)
|
||||
},
|
||||
};
|
||||
content_size = LogicalVec2 {
|
||||
inline: inline_size,
|
||||
block: block_size,
|
||||
};
|
||||
children = independent_layout.fragments;
|
||||
},
|
||||
IndependentFormattingContext::Replaced(ref replaced) => {
|
||||
// https://drafts.csswg.org/css2/#float-replaced-width
|
||||
// https://drafts.csswg.org/css2/#inline-replaced-height
|
||||
content_size = replaced.contents.used_size_as_if_inline_element(
|
||||
containing_block,
|
||||
&replaced.style,
|
||||
&pbm,
|
||||
);
|
||||
children = replaced.contents.make_fragments(
|
||||
&replaced.style,
|
||||
containing_block,
|
||||
content_size.to_physical_size(containing_block.style.writing_mode),
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
let containing_block_writing_mode = containing_block.style.writing_mode;
|
||||
let content_rect = PhysicalRect::new(
|
||||
PhysicalPoint::zero(),
|
||||
content_size.to_physical_size(containing_block_writing_mode),
|
||||
);
|
||||
|
||||
BoxFragment::new(
|
||||
self.contents.base_fragment_info(),
|
||||
style.clone(),
|
||||
children,
|
||||
content_rect,
|
||||
pbm.padding.to_physical(containing_block_writing_mode),
|
||||
pbm.border.to_physical(containing_block_writing_mode),
|
||||
margin.to_physical(containing_block_writing_mode),
|
||||
// Clearance is handled internally by the float placement logic, so there's no need
|
||||
// to store it explicitly in the fragment.
|
||||
None, // clearance
|
||||
CollapsedBlockMargins::zero(),
|
||||
)
|
||||
self.contents
|
||||
.layout_float_or_atomic_inline(
|
||||
layout_context,
|
||||
positioning_context,
|
||||
containing_block,
|
||||
)
|
||||
.fragment
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
|
@ -117,17 +117,18 @@ use crate::context::LayoutContext;
|
|||
use crate::flow::float::{FloatBox, SequentialLayoutState};
|
||||
use crate::flow::{CollapsibleWithParentStartMargin, FlowLayout};
|
||||
use crate::formatting_contexts::{
|
||||
Baselines, IndependentFormattingContext, NonReplacedFormattingContextContents,
|
||||
Baselines, IndependentFormattingContext, IndependentLayoutResult,
|
||||
NonReplacedFormattingContextContents,
|
||||
};
|
||||
use crate::fragment_tree::{
|
||||
BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
|
||||
PositioningFragment,
|
||||
};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, PhysicalPoint, PhysicalRect, Size, ToLogical};
|
||||
use crate::geom::{LogicalRect, LogicalVec2, ToLogical};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
|
||||
use crate::sizing::ContentSizes;
|
||||
use crate::style_ext::{Clamp, ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{AuOrAuto, ContainingBlock, IndefiniteContainingBlock};
|
||||
use crate::style_ext::{ComputedValuesExt, PaddingBorderMargin};
|
||||
use crate::{ContainingBlock, IndefiniteContainingBlock};
|
||||
|
||||
// From gfxFontConstants.h in Firefox.
|
||||
static FONT_SUBSCRIPT_OFFSET_RATIO: f32 = 0.20;
|
||||
|
@ -1907,173 +1908,27 @@ impl IndependentFormattingContext {
|
|||
offset_in_text: usize,
|
||||
bidi_level: Level,
|
||||
) {
|
||||
let style = self.style();
|
||||
let container_writing_mode = layout.containing_block.style.writing_mode;
|
||||
let pbm = style.padding_border_margin(layout.containing_block);
|
||||
let margin = pbm.margin.auto_is(Au::zero);
|
||||
let pbm_sums = pbm.padding + pbm.border + margin;
|
||||
|
||||
// We need to know the inline size of the atomic before deciding whether to do the line break.
|
||||
let (fragments, content_rect, baselines, mut child_positioning_context) = match self {
|
||||
IndependentFormattingContext::Replaced(replaced) => {
|
||||
let size = replaced
|
||||
.contents
|
||||
.used_size_as_if_inline_element(layout.containing_block, &replaced.style, &pbm)
|
||||
.to_physical_size(container_writing_mode);
|
||||
let fragments = replaced.contents.make_fragments(
|
||||
&replaced.style,
|
||||
layout.containing_block,
|
||||
size,
|
||||
);
|
||||
|
||||
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), size);
|
||||
(fragments, content_rect, None, None)
|
||||
},
|
||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||
let box_size = non_replaced
|
||||
.style
|
||||
.content_box_size(layout.containing_block, &pbm);
|
||||
let max_box_size = non_replaced
|
||||
.style
|
||||
.content_max_box_size(layout.containing_block, &pbm);
|
||||
let min_box_size = non_replaced
|
||||
.style
|
||||
.content_min_box_size(layout.containing_block, &pbm);
|
||||
|
||||
let available_inline_size =
|
||||
layout.containing_block.inline_size - pbm_sums.inline_sum();
|
||||
let available_block_size = layout
|
||||
.containing_block
|
||||
.block_size
|
||||
.non_auto()
|
||||
.map(|block_size| block_size - pbm_sums.block_sum());
|
||||
let tentative_block_size = box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.map(|v| {
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = max_box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size);
|
||||
v.clamp_between_extremums(min_block_size, max_block_size)
|
||||
})
|
||||
.map_or(AuOrAuto::Auto, AuOrAuto::LengthPercentage);
|
||||
|
||||
let style = non_replaced.style.clone();
|
||||
let mut get_content_size = || {
|
||||
let containing_block_for_children =
|
||||
IndefiniteContainingBlock::new_for_style_and_block_size(
|
||||
&style,
|
||||
tentative_block_size,
|
||||
);
|
||||
non_replaced
|
||||
.inline_content_sizes(layout.layout_context, &containing_block_for_children)
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
|
||||
let tentative_inline_size = box_size.inline.resolve(
|
||||
Size::fit_content,
|
||||
available_inline_size,
|
||||
&mut get_content_size,
|
||||
);
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
||||
// In this case “applying the rules above again” with a non-auto inline-size
|
||||
// always results in that size.
|
||||
let min_inline_size = min_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_inline_size = max_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size);
|
||||
let inline_size =
|
||||
tentative_inline_size.clamp_between_extremums(min_inline_size, max_inline_size);
|
||||
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size,
|
||||
block_size: tentative_block_size,
|
||||
style: &non_replaced.style,
|
||||
};
|
||||
assert_eq!(
|
||||
layout.containing_block.style.writing_mode.is_horizontal(),
|
||||
containing_block_for_children
|
||||
.style
|
||||
.writing_mode
|
||||
.is_horizontal(),
|
||||
"Mixed horizontal and vertical writing modes are not supported yet"
|
||||
);
|
||||
|
||||
let mut positioning_context =
|
||||
PositioningContext::new_for_style(&non_replaced.style)
|
||||
.unwrap_or_else(|| PositioningContext::new_for_subtree(true));
|
||||
let independent_layout = non_replaced.layout(
|
||||
layout.layout_context,
|
||||
&mut positioning_context,
|
||||
&containing_block_for_children,
|
||||
layout.containing_block,
|
||||
);
|
||||
let (inline_size, block_size) = match independent_layout
|
||||
.content_inline_size_for_table
|
||||
{
|
||||
Some(inline) => (inline, independent_layout.content_block_size),
|
||||
None => {
|
||||
// https://drafts.csswg.org/css2/visudet.html#block-root-margin
|
||||
let stretch_size =
|
||||
available_block_size.unwrap_or(independent_layout.content_block_size);
|
||||
let mut get_content_size = || independent_layout.content_block_size.into();
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = max_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size);
|
||||
let block_size = tentative_block_size
|
||||
.auto_is(|| independent_layout.content_block_size)
|
||||
.clamp_between_extremums(min_block_size, max_block_size);
|
||||
(inline_size, block_size)
|
||||
},
|
||||
};
|
||||
|
||||
let content_rect = PhysicalRect::new(
|
||||
PhysicalPoint::zero(),
|
||||
LogicalVec2 {
|
||||
block: block_size,
|
||||
inline: inline_size,
|
||||
}
|
||||
.to_physical_size(container_writing_mode),
|
||||
);
|
||||
|
||||
(
|
||||
independent_layout.fragments,
|
||||
content_rect,
|
||||
Some(independent_layout.baselines),
|
||||
Some(positioning_context),
|
||||
)
|
||||
},
|
||||
};
|
||||
let mut child_positioning_context = PositioningContext::new_for_style(self.style())
|
||||
.unwrap_or_else(|| PositioningContext::new_for_subtree(true));
|
||||
let IndependentLayoutResult {
|
||||
mut fragment,
|
||||
baselines,
|
||||
pbm_sums,
|
||||
} = self.layout_float_or_atomic_inline(
|
||||
layout.layout_context,
|
||||
&mut child_positioning_context,
|
||||
layout.containing_block,
|
||||
);
|
||||
|
||||
// Offset the content rectangle by the physical offset of the padding, border, and margin.
|
||||
let container_writing_mode = layout.containing_block.style.writing_mode;
|
||||
let pbm_physical_offset = pbm_sums
|
||||
.start_offset()
|
||||
.to_physical_size(container_writing_mode);
|
||||
let content_rect = content_rect.translate(pbm_physical_offset.to_vector());
|
||||
|
||||
let fragment = BoxFragment::new(
|
||||
self.base_fragment_info(),
|
||||
self.style().clone(),
|
||||
fragments,
|
||||
content_rect,
|
||||
pbm.padding.to_physical(container_writing_mode),
|
||||
pbm.border.to_physical(container_writing_mode),
|
||||
margin.to_physical(container_writing_mode),
|
||||
None, /* clearance */
|
||||
CollapsedBlockMargins::zero(),
|
||||
);
|
||||
fragment.content_rect = fragment
|
||||
.content_rect
|
||||
.translate(pbm_physical_offset.to_vector());
|
||||
|
||||
// Apply baselines if necessary.
|
||||
let mut fragment = match baselines {
|
||||
|
@ -2083,14 +1938,18 @@ impl IndependentFormattingContext {
|
|||
|
||||
// Lay out absolutely positioned children if this new atomic establishes a containing block
|
||||
// for absolutes.
|
||||
if let Some(positioning_context) = child_positioning_context.as_mut() {
|
||||
let positioning_context = if matches!(self, IndependentFormattingContext::Replaced(_)) {
|
||||
None
|
||||
} else {
|
||||
if fragment
|
||||
.style
|
||||
.establishes_containing_block_for_absolute_descendants(fragment.base.flags)
|
||||
{
|
||||
positioning_context.layout_collected_children(layout.layout_context, &mut fragment);
|
||||
child_positioning_context
|
||||
.layout_collected_children(layout.layout_context, &mut fragment);
|
||||
}
|
||||
}
|
||||
Some(child_positioning_context)
|
||||
};
|
||||
|
||||
if layout.text_wrap_mode == TextWrapMode::Wrap &&
|
||||
!layout
|
||||
|
@ -2122,7 +1981,7 @@ impl IndependentFormattingContext {
|
|||
AtomicLineItem {
|
||||
fragment,
|
||||
size,
|
||||
positioning_context: child_positioning_context,
|
||||
positioning_context,
|
||||
baseline_offset_in_parent,
|
||||
baseline_offset_in_item: baseline_offset,
|
||||
bidi_level,
|
||||
|
|
|
@ -14,7 +14,7 @@ use style::computed_values::clear::T as Clear;
|
|||
use style::computed_values::float::T as Float;
|
||||
use style::properties::ComputedValues;
|
||||
use style::servo::selector_parser::PseudoElement;
|
||||
use style::values::computed::Size;
|
||||
use style::values::computed::Size as StyleSize;
|
||||
use style::values::specified::align::AlignFlags;
|
||||
use style::values::specified::{Display, TextAlignKeyword};
|
||||
use style::Zero;
|
||||
|
@ -25,14 +25,15 @@ use crate::flow::float::{
|
|||
ContainingBlockPositionInfo, FloatBox, PlacementAmongFloats, SequentialLayoutState,
|
||||
};
|
||||
use crate::formatting_contexts::{
|
||||
Baselines, IndependentFormattingContext, IndependentLayout, NonReplacedFormattingContext,
|
||||
Baselines, IndependentFormattingContext, IndependentLayout, IndependentLayoutResult,
|
||||
NonReplacedFormattingContext,
|
||||
};
|
||||
use crate::fragment_tree::{
|
||||
BaseFragmentInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, FragmentFlags,
|
||||
};
|
||||
use crate::geom::{
|
||||
AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalRect, PhysicalSides, ToLogical,
|
||||
ToLogicalWithContainingBlock,
|
||||
AuOrAuto, LogicalRect, LogicalSides, LogicalVec2, PhysicalPoint, PhysicalRect, PhysicalSides,
|
||||
Size, ToLogical, ToLogicalWithContainingBlock,
|
||||
};
|
||||
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
|
||||
use crate::replaced::ReplacedContent;
|
||||
|
@ -1904,13 +1905,182 @@ impl<'container> PlacementState<'container> {
|
|||
}
|
||||
}
|
||||
|
||||
fn block_size_is_zero_or_intrinsic(size: &Size, containing_block: &ContainingBlock) -> bool {
|
||||
fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &ContainingBlock) -> bool {
|
||||
match size {
|
||||
Size::Auto | Size::MinContent | Size::MaxContent | Size::FitContent | Size::Stretch => true,
|
||||
Size::LengthPercentage(ref lp) => {
|
||||
StyleSize::Auto |
|
||||
StyleSize::MinContent |
|
||||
StyleSize::MaxContent |
|
||||
StyleSize::FitContent |
|
||||
StyleSize::Stretch => true,
|
||||
StyleSize::LengthPercentage(ref lp) => {
|
||||
// TODO: Should this resolve definite percentages? Blink does it, Gecko and WebKit don't.
|
||||
lp.is_definitely_zero() ||
|
||||
(lp.0.has_percentage() && containing_block.block_size.is_auto())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl IndependentFormattingContext {
|
||||
pub(crate) fn layout_float_or_atomic_inline(
|
||||
&mut self,
|
||||
layout_context: &LayoutContext,
|
||||
child_positioning_context: &mut PositioningContext,
|
||||
containing_block: &ContainingBlock,
|
||||
) -> IndependentLayoutResult {
|
||||
let style = self.style();
|
||||
let container_writing_mode = containing_block.style.writing_mode;
|
||||
let pbm = style.padding_border_margin(containing_block);
|
||||
let margin = pbm.margin.auto_is(Au::zero);
|
||||
let pbm_sums = pbm.padding + pbm.border + margin;
|
||||
|
||||
let (fragments, content_rect, baselines) = match self {
|
||||
IndependentFormattingContext::Replaced(replaced) => {
|
||||
// https://drafts.csswg.org/css2/visudet.html#float-replaced-width
|
||||
// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
|
||||
let content_size = replaced
|
||||
.contents
|
||||
.used_size_as_if_inline_element(containing_block, &replaced.style, &pbm)
|
||||
.to_physical_size(container_writing_mode);
|
||||
let fragments = replaced.contents.make_fragments(
|
||||
&replaced.style,
|
||||
containing_block,
|
||||
content_size,
|
||||
);
|
||||
|
||||
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
|
||||
(fragments, content_rect, None)
|
||||
},
|
||||
IndependentFormattingContext::NonReplaced(non_replaced) => {
|
||||
let style = non_replaced.style.clone();
|
||||
let box_size = style.content_box_size(containing_block, &pbm);
|
||||
let max_box_size = style.content_max_box_size(containing_block, &pbm);
|
||||
let min_box_size = style.content_min_box_size(containing_block, &pbm);
|
||||
|
||||
let available_inline_size = containing_block.inline_size - pbm_sums.inline_sum();
|
||||
let available_block_size = containing_block
|
||||
.block_size
|
||||
.non_auto()
|
||||
.map(|block_size| block_size - pbm_sums.block_sum());
|
||||
let tentative_block_size = box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.map(|size| {
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.maybe_resolve_extrinsic(available_block_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = 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 containing_block_for_children =
|
||||
IndefiniteContainingBlock::new_for_style_and_block_size(
|
||||
&style,
|
||||
tentative_block_size,
|
||||
);
|
||||
non_replaced
|
||||
.inline_content_sizes(layout_context, &containing_block_for_children)
|
||||
};
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#float-width
|
||||
// https://drafts.csswg.org/css2/visudet.html#inlineblock-width
|
||||
let tentative_inline_size = box_size.inline.resolve(
|
||||
Size::fit_content,
|
||||
available_inline_size,
|
||||
&mut get_content_size,
|
||||
);
|
||||
|
||||
// https://drafts.csswg.org/css2/visudet.html#min-max-widths
|
||||
// In this case “applying the rules above again” with a non-auto inline-size
|
||||
// always results in that size.
|
||||
let min_inline_size = min_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_inline_size = max_box_size
|
||||
.inline
|
||||
.resolve_non_initial(available_inline_size, &mut get_content_size);
|
||||
let inline_size =
|
||||
tentative_inline_size.clamp_between_extremums(min_inline_size, max_inline_size);
|
||||
|
||||
let containing_block_for_children = ContainingBlock {
|
||||
inline_size,
|
||||
block_size: tentative_block_size,
|
||||
style: &style,
|
||||
};
|
||||
assert_eq!(
|
||||
container_writing_mode.is_horizontal(),
|
||||
style.writing_mode.is_horizontal(),
|
||||
"Mixed horizontal and vertical writing modes are not supported yet"
|
||||
);
|
||||
|
||||
let independent_layout = non_replaced.layout(
|
||||
layout_context,
|
||||
child_positioning_context,
|
||||
&containing_block_for_children,
|
||||
containing_block,
|
||||
);
|
||||
let (inline_size, block_size) = match independent_layout
|
||||
.content_inline_size_for_table
|
||||
{
|
||||
Some(inline) => (inline, independent_layout.content_block_size),
|
||||
None => {
|
||||
// https://drafts.csswg.org/css2/visudet.html#block-root-margin
|
||||
let stretch_size =
|
||||
available_block_size.unwrap_or(independent_layout.content_block_size);
|
||||
let mut get_content_size = || independent_layout.content_block_size.into();
|
||||
let min_block_size = min_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size)
|
||||
.unwrap_or_default();
|
||||
let max_block_size = max_box_size
|
||||
.block
|
||||
.resolve_non_initial(stretch_size, &mut get_content_size);
|
||||
let block_size = tentative_block_size
|
||||
.auto_is(|| independent_layout.content_block_size)
|
||||
.clamp_between_extremums(min_block_size, max_block_size);
|
||||
(inline_size, block_size)
|
||||
},
|
||||
};
|
||||
|
||||
let content_size = LogicalVec2 {
|
||||
block: block_size,
|
||||
inline: inline_size,
|
||||
}
|
||||
.to_physical_size(container_writing_mode);
|
||||
let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
|
||||
|
||||
(
|
||||
independent_layout.fragments,
|
||||
content_rect,
|
||||
Some(independent_layout.baselines),
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
let fragment = BoxFragment::new(
|
||||
self.base_fragment_info(),
|
||||
self.style().clone(),
|
||||
fragments,
|
||||
content_rect,
|
||||
pbm.padding.to_physical(container_writing_mode),
|
||||
pbm.border.to_physical(container_writing_mode),
|
||||
margin.to_physical(container_writing_mode),
|
||||
// Floats can have clearance, but it's handled internally by the float placement logic,
|
||||
// so there's no need to store it explicitly in the fragment.
|
||||
// And atomic inlines don't have clearance.
|
||||
None, /* clearance */
|
||||
CollapsedBlockMargins::zero(),
|
||||
);
|
||||
|
||||
IndependentLayoutResult {
|
||||
fragment,
|
||||
baselines,
|
||||
pbm_sums,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,8 @@ use crate::dom::NodeExt;
|
|||
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
|
||||
use crate::flexbox::FlexContainer;
|
||||
use crate::flow::BlockFormattingContext;
|
||||
use crate::fragment_tree::{BaseFragmentInfo, Fragment, FragmentFlags};
|
||||
use crate::fragment_tree::{BaseFragmentInfo, BoxFragment, Fragment, FragmentFlags};
|
||||
use crate::geom::LogicalSides;
|
||||
use crate::positioned::PositioningContext;
|
||||
use crate::replaced::ReplacedContent;
|
||||
use crate::sizing::{self, ContentSizes};
|
||||
|
@ -91,6 +92,12 @@ pub(crate) struct IndependentLayout {
|
|||
pub baselines: Baselines,
|
||||
}
|
||||
|
||||
pub(crate) struct IndependentLayoutResult {
|
||||
pub fragment: BoxFragment,
|
||||
pub baselines: Option<Baselines>,
|
||||
pub pbm_sums: LogicalSides<Au>,
|
||||
}
|
||||
|
||||
impl IndependentFormattingContext {
|
||||
pub fn construct<'dom, Node: NodeExt<'dom>>(
|
||||
context: &LayoutContext,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue