1#![allow(rustdoc::private_intra_doc_links)]
5
6use app_units::{Au, MAX_AU};
9use inline::InlineFormattingContext;
10use layout_api::wrapper_traits::ThreadSafeLayoutNode;
11use malloc_size_of_derive::MallocSizeOf;
12use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
13use script::layout_dom::ServoThreadSafeLayoutNode;
14use servo_arc::Arc;
15use style::Zero;
16use style::computed_values::clear::T as StyleClear;
17use style::context::SharedStyleContext;
18use style::logical_geometry::Direction;
19use style::properties::ComputedValues;
20use style::servo::selector_parser::PseudoElement;
21use style::values::specified::align::AlignFlags;
22use style::values::specified::{Display, TextAlignKeyword};
23
24use crate::cell::ArcRefCell;
25use crate::context::LayoutContext;
26use crate::dom::WeakLayoutBox;
27use crate::flow::float::{
28 Clear, ContainingBlockPositionInfo, FloatBox, FloatSide, PlacementAmongFloats,
29 SequentialLayoutState,
30};
31use crate::formatting_contexts::{Baselines, IndependentFormattingContext};
32use crate::fragment_tree::{
33 BaseFragmentInfo, BlockLevelLayoutInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin,
34 Fragment, FragmentFlags,
35};
36use crate::geom::{
37 AuOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
38 PhysicalSides, ToLogical, ToLogicalWithContainingBlock,
39};
40use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
41use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
42use crate::sizing::{
43 self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, LazySize, Size,
44 SizeConstraint, Sizes,
45};
46use crate::style_ext::{AspectRatio, ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin};
47use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock};
48
49mod construct;
50pub mod float;
51pub mod inline;
52mod root;
53
54pub(crate) use construct::{BlockContainerBuilder, BlockLevelCreator};
55pub(crate) use root::BoxTree;
56
57#[derive(Debug, MallocSizeOf)]
58pub(crate) struct BlockFormattingContext {
59 pub contents: BlockContainer,
60 pub contains_floats: bool,
61}
62
63#[derive(Debug, MallocSizeOf)]
64pub(crate) enum BlockContainer {
65 BlockLevelBoxes(Vec<ArcRefCell<BlockLevelBox>>),
66 InlineFormattingContext(InlineFormattingContext),
67}
68
69impl BlockContainer {
70 fn contains_floats(&self) -> bool {
71 match self {
72 BlockContainer::BlockLevelBoxes(boxes) => boxes
73 .iter()
74 .any(|block_level_box| block_level_box.borrow().contains_floats()),
75 BlockContainer::InlineFormattingContext(context) => context.contains_floats,
76 }
77 }
78
79 pub(crate) fn repair_style(
80 &mut self,
81 context: &SharedStyleContext,
82 node: &ServoThreadSafeLayoutNode,
83 new_style: &Arc<ComputedValues>,
84 ) {
85 match self {
86 BlockContainer::BlockLevelBoxes(..) => {},
87 BlockContainer::InlineFormattingContext(inline_formatting_context) => {
88 inline_formatting_context.repair_style(context, node, new_style)
89 },
90 }
91 }
92}
93
94#[derive(Debug, MallocSizeOf)]
95pub(crate) enum BlockLevelBox {
96 Independent(IndependentFormattingContext),
97 OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
98 OutOfFlowFloatBox(FloatBox),
99 OutsideMarker(OutsideMarker),
100 SameFormattingContextBlock {
101 base: LayoutBoxBase,
102 contents: BlockContainer,
103 contains_floats: bool,
104 },
105}
106
107impl BlockLevelBox {
108 pub(crate) fn repair_style(
109 &mut self,
110 context: &SharedStyleContext,
111 node: &ServoThreadSafeLayoutNode,
112 new_style: &Arc<ComputedValues>,
113 ) {
114 match self {
115 BlockLevelBox::Independent(independent_formatting_context) => {
116 independent_formatting_context.repair_style(context, node, new_style)
117 },
118 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
119 .borrow_mut()
120 .context
121 .repair_style(context, node, new_style),
122 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
123 float_box.contents.repair_style(context, node, new_style)
124 },
125 BlockLevelBox::OutsideMarker(outside_marker) => {
126 outside_marker.repair_style(context, node, new_style)
127 },
128 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
129 base.repair_style(new_style);
130 contents.repair_style(context, node, new_style);
131 },
132 }
133 }
134
135 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
136 match self {
137 BlockLevelBox::Independent(independent_formatting_context) => {
138 callback(&independent_formatting_context.base)
139 },
140 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
141 callback(&positioned_box.borrow().context.base)
142 },
143 BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&float_box.contents.base),
144 BlockLevelBox::OutsideMarker(outside_marker) => callback(&outside_marker.context.base),
145 BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base),
146 }
147 }
148
149 pub(crate) fn with_base_mut<T>(&mut self, callback: impl FnOnce(&mut LayoutBoxBase) -> T) -> T {
150 match self {
151 BlockLevelBox::Independent(independent_formatting_context) => {
152 callback(&mut independent_formatting_context.base)
153 },
154 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
155 callback(&mut positioned_box.borrow_mut().context.base)
156 },
157 BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&mut float_box.contents.base),
158 BlockLevelBox::OutsideMarker(outside_marker) => {
159 callback(&mut outside_marker.context.base)
160 },
161 BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base),
162 }
163 }
164
165 pub(crate) fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
166 match self {
167 Self::Independent(independent_formatting_context) => {
168 independent_formatting_context.attached_to_tree(layout_box)
169 },
170 Self::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
171 positioned_box.borrow().context.attached_to_tree(layout_box)
172 },
173 Self::OutOfFlowFloatBox(float_box) => float_box.contents.attached_to_tree(layout_box),
174 Self::OutsideMarker(outside_marker) => {
175 outside_marker.context.attached_to_tree(layout_box)
176 },
177 Self::SameFormattingContextBlock { contents, .. } => {
178 contents.attached_to_tree(layout_box)
179 },
180 }
181 }
182
183 fn contains_floats(&self) -> bool {
184 match self {
185 BlockLevelBox::SameFormattingContextBlock {
186 contains_floats, ..
187 } => *contains_floats,
188 BlockLevelBox::OutOfFlowFloatBox { .. } => true,
189 _ => false,
190 }
191 }
192
193 fn find_block_margin_collapsing_with_parent(
194 &self,
195 layout_context: &LayoutContext,
196 collected_margin: &mut CollapsedMargin,
197 containing_block: &ContainingBlock,
198 ) -> bool {
199 let layout_style = match self {
200 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
201 contents.layout_style(base)
202 },
203 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
204 BlockLevelBox::OutOfFlowFloatBox(_) => return true,
205 BlockLevelBox::OutsideMarker(_) => return false,
206 BlockLevelBox::Independent(context) => {
207 context.layout_style()
210 },
211 };
212
213 let style = layout_style.style();
215 if style.get_box().clear != StyleClear::None {
216 return false;
217 }
218
219 let ContentBoxSizesAndPBM {
220 content_box_sizes,
221 pbm,
222 ..
223 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
224 let margin = pbm.margin.auto_is(Au::zero);
225 collected_margin.adjoin_assign(&CollapsedMargin::new(margin.block_start));
226
227 let BlockLevelBox::SameFormattingContextBlock { contents, .. } = self else {
228 return false;
229 };
230
231 if !pbm.padding.block_start.is_zero() || !pbm.border.block_start.is_zero() {
232 return false;
233 }
234
235 let available_inline_size =
236 containing_block.size.inline - pbm.padding_border_sums.inline - margin.inline_sum();
237 let available_block_size = containing_block.size.block.to_definite().map(|block_size| {
238 Au::zero().max(block_size - pbm.padding_border_sums.block - margin.block_sum())
239 });
240
241 let tentative_block_size = content_box_sizes.block.resolve_extrinsic(
242 Size::FitContent,
243 Au::zero(),
244 available_block_size,
245 );
246
247 let get_inline_content_sizes = || {
248 let constraint_space = ConstraintSpace::new(
249 tentative_block_size,
250 style,
251 None, );
253 self.inline_content_sizes(layout_context, &constraint_space)
254 .sizes
255 };
256 let inline_size = content_box_sizes.inline.resolve(
257 Direction::Inline,
258 Size::Stretch,
259 Au::zero,
260 Some(available_inline_size),
261 get_inline_content_sizes,
262 false, );
264
265 let containing_block_for_children = ContainingBlock {
266 size: ContainingBlockSize {
267 inline: inline_size,
268 block: tentative_block_size,
269 },
270 style,
271 };
272
273 if !contents.find_block_margin_collapsing_with_parent(
274 layout_context,
275 collected_margin,
276 &containing_block_for_children,
277 ) {
278 return false;
279 }
280
281 if !tentative_block_size.definite_or_min().is_zero() ||
282 !pbm.padding_border_sums.block.is_zero()
283 {
284 return false;
285 }
286
287 collected_margin.adjoin_assign(&CollapsedMargin::new(margin.block_end));
288
289 true
290 }
291}
292
293#[derive(Clone, Copy)]
294pub(crate) struct CollapsibleWithParentStartMargin(bool);
295
296#[derive(Debug, MallocSizeOf)]
299pub(crate) struct OutsideMarker {
300 pub list_item_style: Arc<ComputedValues>,
301 pub context: IndependentFormattingContext,
302}
303
304impl OutsideMarker {
305 fn layout(
306 &self,
307 layout_context: &LayoutContext<'_>,
308 containing_block: &ContainingBlock<'_>,
309 positioning_context: &mut PositioningContext,
310 ) -> Fragment {
311 let style = &self.context.base.style;
312 let preferred_aspect_ratio = self.context.preferred_aspect_ratio(&LogicalVec2::zero());
313 let constraint_space =
314 ConstraintSpace::new(SizeConstraint::default(), style, preferred_aspect_ratio);
315 let content_sizes = self
316 .context
317 .inline_content_sizes(layout_context, &constraint_space);
318 let containing_block_for_children = ContainingBlock {
319 size: ContainingBlockSize {
320 inline: content_sizes.sizes.max_content,
321 block: SizeConstraint::default(),
322 },
323 style,
324 };
325
326 let layout = self.context.layout(
327 layout_context,
328 positioning_context,
329 &containing_block_for_children,
330 containing_block,
331 preferred_aspect_ratio,
332 &LazySize::intrinsic(),
333 );
334
335 let max_inline_size = layout
336 .fragments
337 .iter()
338 .map(|fragment| {
339 fragment
340 .base()
341 .map(|base| base.rect)
342 .unwrap_or_default()
343 .to_logical(&containing_block_for_children)
344 .max_inline_position()
345 })
346 .max()
347 .unwrap_or_default();
348
349 let pbm_of_list_item =
359 LayoutStyle::Default(&self.list_item_style).padding_border_margin(containing_block);
360 let content_rect = LogicalRect {
361 start_corner: LogicalVec2 {
362 inline: -max_inline_size -
363 (pbm_of_list_item.border.inline_start +
364 pbm_of_list_item.padding.inline_start),
365 block: Zero::zero(),
366 },
367 size: LogicalVec2 {
368 inline: max_inline_size,
369 block: layout.content_block_size,
370 },
371 };
372
373 let mut base_fragment_info = BaseFragmentInfo::anonymous();
374 base_fragment_info.flags |= FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER;
375
376 Fragment::Box(ArcRefCell::new(BoxFragment::new(
377 base_fragment_info,
378 style.clone(),
379 layout.fragments,
380 content_rect.as_physical(Some(containing_block)),
381 PhysicalSides::zero(),
382 PhysicalSides::zero(),
383 PhysicalSides::zero(),
384 layout.specific_layout_info,
385 )))
386 }
387
388 fn repair_style(
389 &mut self,
390 context: &SharedStyleContext,
391 node: &ServoThreadSafeLayoutNode,
392 new_style: &Arc<ComputedValues>,
393 ) {
394 self.list_item_style = node.parent_style(context);
395 self.context.repair_style(context, node, new_style);
396 }
397}
398
399impl BlockFormattingContext {
400 pub(super) fn layout(
401 &self,
402 layout_context: &LayoutContext,
403 positioning_context: &mut PositioningContext,
404 containing_block: &ContainingBlock,
405 ) -> CacheableLayoutResult {
406 let mut sequential_layout_state = if self.contains_floats || !layout_context.use_rayon {
407 Some(SequentialLayoutState::new(containing_block.size.inline))
408 } else {
409 None
410 };
411
412 let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
416
417 let flow_layout = self.contents.layout(
418 layout_context,
419 positioning_context,
420 containing_block,
421 sequential_layout_state.as_mut(),
422 CollapsibleWithParentStartMargin(false),
423 ignore_block_margins_for_stretch,
424 );
425 debug_assert!(
426 !flow_layout
427 .collapsible_margins_in_children
428 .collapsed_through
429 );
430
431 let clearance = sequential_layout_state.and_then(|sequential_layout_state| {
435 sequential_layout_state.calculate_clearance(Clear::Both, &CollapsedMargin::zero())
436 });
437
438 CacheableLayoutResult {
439 fragments: flow_layout.fragments,
440 content_block_size: flow_layout.content_block_size +
441 flow_layout.collapsible_margins_in_children.end.solve() +
442 clearance.unwrap_or_default(),
443 content_inline_size_for_table: None,
444 baselines: flow_layout.baselines,
445 depends_on_block_constraints: flow_layout.depends_on_block_constraints,
446 specific_layout_info: None,
447 collapsible_margins_in_children: CollapsedBlockMargins::zero(),
448 }
449 }
450
451 #[inline]
452 pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
453 LayoutStyle::Default(&base.style)
454 }
455
456 pub(crate) fn repair_style(
457 &mut self,
458 context: &SharedStyleContext,
459 node: &ServoThreadSafeLayoutNode,
460 new_style: &Arc<ComputedValues>,
461 ) {
462 self.contents.repair_style(context, node, new_style);
463 }
464
465 pub(crate) fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
466 self.contents.attached_to_tree(layout_box);
467 }
468}
469
470fn compute_inline_content_sizes_for_block_level_boxes(
476 boxes: &[ArcRefCell<BlockLevelBox>],
477 layout_context: &LayoutContext,
478 containing_block: &IndefiniteContainingBlock,
479) -> InlineContentSizesResult {
480 let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| {
481 match &*box_.borrow() {
482 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
483 BlockLevelBox::OutsideMarker { .. } => None,
484 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
485 let inline_content_sizes_result = float_box.contents.outer_inline_content_sizes(
486 layout_context,
487 containing_block,
488 &LogicalVec2::zero(),
489 false, );
491 let style = &float_box.contents.style();
492 let container_writing_mode = containing_block.style.writing_mode;
493 Some((
494 inline_content_sizes_result,
495 FloatSide::from_style_and_container_writing_mode(style, container_writing_mode),
496 Clear::from_style_and_container_writing_mode(style, container_writing_mode),
497 ))
498 },
499 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
500 let is_anonymous_block =
501 matches!(base.style.pseudo(), Some(PseudoElement::ServoAnonymousBox));
502 let inline_content_sizes_result = sizing::outer_inline(
503 base,
504 &contents.layout_style(base),
505 containing_block,
506 &LogicalVec2::zero(),
507 false, false, !is_anonymous_block, |_| None, |constraint_space| {
512 base.inline_content_sizes(layout_context, constraint_space, contents)
513 },
514 |_aspect_ratio| None,
515 );
516 let clear = if is_anonymous_block {
525 Clear::None
526 } else {
527 Clear::Both
528 };
529 Some((inline_content_sizes_result, None, clear))
530 },
531 BlockLevelBox::Independent(independent) => {
532 let inline_content_sizes_result = independent.outer_inline_content_sizes(
533 layout_context,
534 containing_block,
535 &LogicalVec2::zero(),
536 false, );
538 Some((
539 inline_content_sizes_result,
540 None,
541 Clear::from_style_and_container_writing_mode(
542 independent.style(),
543 containing_block.style.writing_mode,
544 ),
545 ))
546 },
547 }
548 };
549
550 #[derive(Default)]
553 struct AccumulatedData {
554 depends_on_block_constraints: bool,
556 max_size: ContentSizes,
558 floats: LogicalSides1D<ContentSizes>,
561 }
562
563 impl AccumulatedData {
564 fn max_size_including_uncleared_floats(&self) -> ContentSizes {
565 self.max_size.max(self.floats.start.union(&self.floats.end))
566 }
567 fn clear_floats(&mut self, clear: Clear) {
568 match clear {
569 Clear::InlineStart => {
570 self.max_size = self.max_size_including_uncleared_floats();
571 self.floats.start = ContentSizes::default();
572 },
573 Clear::InlineEnd => {
574 self.max_size = self.max_size_including_uncleared_floats();
575 self.floats.end = ContentSizes::default();
576 },
577 Clear::Both => {
578 self.max_size = self.max_size_including_uncleared_floats();
579 self.floats = LogicalSides1D::default();
580 },
581 Clear::None => {},
582 };
583 }
584 }
585
586 let accumulate =
587 |mut data: AccumulatedData,
588 (inline_content_sizes_result, float, clear): (InlineContentSizesResult, _, _)| {
589 let size = inline_content_sizes_result.sizes.max(ContentSizes::zero());
590 let depends_on_block_constraints =
591 inline_content_sizes_result.depends_on_block_constraints;
592 data.depends_on_block_constraints |= depends_on_block_constraints;
593 data.clear_floats(clear);
594 match float {
595 Some(FloatSide::InlineStart) => data.floats.start.union_assign(&size),
596 Some(FloatSide::InlineEnd) => data.floats.end.union_assign(&size),
597 None => {
598 data.max_size
599 .max_assign(data.floats.start.union(&data.floats.end).union(&size));
600 data.floats = LogicalSides1D::default();
601 },
602 }
603 data
604 };
605 let data = if layout_context.use_rayon {
606 boxes
607 .par_iter()
608 .filter_map(get_box_info)
609 .collect::<Vec<_>>()
610 .into_iter()
611 .fold(AccumulatedData::default(), accumulate)
612 } else {
613 boxes
614 .iter()
615 .filter_map(get_box_info)
616 .fold(AccumulatedData::default(), accumulate)
617 };
618 InlineContentSizesResult {
619 depends_on_block_constraints: data.depends_on_block_constraints,
620 sizes: data.max_size_including_uncleared_floats(),
621 }
622}
623
624impl BlockContainer {
625 fn layout(
626 &self,
627 layout_context: &LayoutContext,
628 positioning_context: &mut PositioningContext,
629 containing_block: &ContainingBlock,
630 sequential_layout_state: Option<&mut SequentialLayoutState>,
631 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
632 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
633 ) -> CacheableLayoutResult {
634 match self {
635 BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
636 layout_context,
637 positioning_context,
638 child_boxes,
639 containing_block,
640 sequential_layout_state,
641 collapsible_with_parent_start_margin,
642 ignore_block_margins_for_stretch,
643 ),
644 BlockContainer::InlineFormattingContext(ifc) => ifc.layout(
645 layout_context,
646 positioning_context,
647 containing_block,
648 sequential_layout_state,
649 collapsible_with_parent_start_margin,
650 ),
651 }
652 }
653
654 #[inline]
655 pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
656 LayoutStyle::Default(&base.style)
657 }
658
659 pub(crate) fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
660 match self {
661 Self::BlockLevelBoxes(child_boxes) => {
662 for child_box in child_boxes {
663 child_box.borrow_mut().with_base_mut(|base| {
664 base.parent_box.replace(layout_box.clone());
665 });
666 }
667 },
668 Self::InlineFormattingContext(ifc) => ifc.attached_to_tree(layout_box),
669 }
670 }
671
672 fn find_block_margin_collapsing_with_parent(
673 &self,
674 layout_context: &LayoutContext,
675 collected_margin: &mut CollapsedMargin,
676 containing_block_for_children: &ContainingBlock,
677 ) -> bool {
678 match self {
679 BlockContainer::BlockLevelBoxes(boxes) => boxes.iter().all(|block_level_box| {
680 block_level_box
681 .borrow()
682 .find_block_margin_collapsing_with_parent(
683 layout_context,
684 collected_margin,
685 containing_block_for_children,
686 )
687 }),
688 BlockContainer::InlineFormattingContext(context) => context
689 .find_block_margin_collapsing_with_parent(
690 layout_context,
691 collected_margin,
692 containing_block_for_children,
693 ),
694 }
695 }
696}
697
698impl ComputeInlineContentSizes for BlockContainer {
699 fn compute_inline_content_sizes(
700 &self,
701 layout_context: &LayoutContext,
702 constraint_space: &ConstraintSpace,
703 ) -> InlineContentSizesResult {
704 match &self {
705 Self::BlockLevelBoxes(boxes) => compute_inline_content_sizes_for_block_level_boxes(
706 boxes,
707 layout_context,
708 &constraint_space.into(),
709 ),
710 Self::InlineFormattingContext(context) => {
711 context.compute_inline_content_sizes(layout_context, constraint_space)
712 },
713 }
714 }
715}
716
717fn layout_block_level_children(
718 layout_context: &LayoutContext,
719 positioning_context: &mut PositioningContext,
720 child_boxes: &[ArcRefCell<BlockLevelBox>],
721 containing_block: &ContainingBlock,
722 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
723 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
724 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
725) -> CacheableLayoutResult {
726 let mut placement_state =
727 PlacementState::new(collapsible_with_parent_start_margin, containing_block);
728
729 let fragments = match sequential_layout_state {
730 Some(ref mut sequential_layout_state) => layout_block_level_children_sequentially(
731 layout_context,
732 positioning_context,
733 child_boxes,
734 containing_block,
735 sequential_layout_state,
736 &mut placement_state,
737 ignore_block_margins_for_stretch,
738 ),
739 None => layout_block_level_children_in_parallel(
740 layout_context,
741 positioning_context,
742 child_boxes,
743 containing_block,
744 &mut placement_state,
745 ignore_block_margins_for_stretch,
746 ),
747 };
748
749 let depends_on_block_constraints = fragments.iter().any(|fragment| {
750 fragment.base().is_some_and(|base| {
751 base.flags.contains(
752 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
753 )
754 })
755 });
756
757 let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish();
758 CacheableLayoutResult {
759 fragments,
760 content_block_size,
761 collapsible_margins_in_children,
762 baselines,
763 depends_on_block_constraints,
764 content_inline_size_for_table: None,
765 specific_layout_info: None,
766 }
767}
768
769fn layout_block_level_children_in_parallel(
770 layout_context: &LayoutContext,
771 positioning_context: &mut PositioningContext,
772 child_boxes: &[ArcRefCell<BlockLevelBox>],
773 containing_block: &ContainingBlock,
774 placement_state: &mut PlacementState,
775 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
776) -> Vec<Fragment> {
777 let mut layout_results: Vec<(Fragment, PositioningContext)> =
778 Vec::with_capacity(child_boxes.len());
779
780 child_boxes
781 .par_iter()
782 .map(|child_box| {
783 let mut child_positioning_context = PositioningContext::default();
784 let fragment = child_box.borrow().layout(
785 layout_context,
786 &mut child_positioning_context,
787 containing_block,
788 None,
789 None,
790 ignore_block_margins_for_stretch,
791 );
792 (fragment, child_positioning_context)
793 })
794 .collect_into_vec(&mut layout_results);
795
796 layout_results
797 .into_iter()
798 .map(|(mut fragment, mut child_positioning_context)| {
799 placement_state.place_fragment_and_update_baseline(&mut fragment, None);
800 child_positioning_context.adjust_static_position_of_hoisted_fragments(
801 &fragment,
802 PositioningContextLength::zero(),
803 );
804 positioning_context.append(child_positioning_context);
805 fragment
806 })
807 .collect()
808}
809
810fn layout_block_level_children_sequentially(
811 layout_context: &LayoutContext,
812 positioning_context: &mut PositioningContext,
813 child_boxes: &[ArcRefCell<BlockLevelBox>],
814 containing_block: &ContainingBlock,
815 sequential_layout_state: &mut SequentialLayoutState,
816 placement_state: &mut PlacementState,
817 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
818) -> Vec<Fragment> {
819 child_boxes
823 .iter()
824 .map(|child_box| {
825 let positioning_context_length_before_layout = positioning_context.len();
826 let mut fragment = child_box.borrow().layout(
827 layout_context,
828 positioning_context,
829 containing_block,
830 Some(&mut *sequential_layout_state),
831 Some(CollapsibleWithParentStartMargin(
832 placement_state.next_in_flow_margin_collapses_with_parent_start_margin,
833 )),
834 ignore_block_margins_for_stretch,
835 );
836
837 placement_state
838 .place_fragment_and_update_baseline(&mut fragment, Some(sequential_layout_state));
839 positioning_context.adjust_static_position_of_hoisted_fragments(
840 &fragment,
841 positioning_context_length_before_layout,
842 );
843
844 fragment
845 })
846 .collect()
847}
848
849impl BlockLevelBox {
850 fn layout(
851 &self,
852 layout_context: &LayoutContext,
853 positioning_context: &mut PositioningContext,
854 containing_block: &ContainingBlock,
855 sequential_layout_state: Option<&mut SequentialLayoutState>,
856 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
857 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
858 ) -> Fragment {
859 let fragment = match self {
860 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => Fragment::Box(
861 ArcRefCell::new(positioning_context.layout_maybe_position_relative_fragment(
862 layout_context,
863 containing_block,
864 base,
865 |positioning_context| {
866 layout_in_flow_non_replaced_block_level_same_formatting_context(
867 layout_context,
868 positioning_context,
869 containing_block,
870 base,
871 contents,
872 sequential_layout_state,
873 collapsible_with_parent_start_margin,
874 ignore_block_margins_for_stretch,
875 )
876 },
877 )),
878 ),
879 BlockLevelBox::Independent(independent) => Fragment::Box(ArcRefCell::new(
880 positioning_context.layout_maybe_position_relative_fragment(
881 layout_context,
882 containing_block,
883 &independent.base,
884 |positioning_context| {
885 independent.layout_in_flow_block_level(
886 layout_context,
887 positioning_context,
888 containing_block,
889 sequential_layout_state,
890 ignore_block_margins_for_stretch,
891 )
892 },
893 ),
894 )),
895 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
896 let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
900 box_.clone(),
901 PhysicalRect::zero(),
905 LogicalVec2 {
906 inline: AlignFlags::START,
907 block: AlignFlags::START,
908 },
909 containing_block.style.writing_mode,
910 );
911 let hoisted_fragment = hoisted_box.fragment.clone();
912 positioning_context.push(hoisted_box);
913 Fragment::AbsoluteOrFixedPositioned(hoisted_fragment)
914 },
915 BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(ArcRefCell::new(
916 float_box.layout(layout_context, positioning_context, containing_block),
917 )),
918 BlockLevelBox::OutsideMarker(outside_marker) => {
919 outside_marker.layout(layout_context, containing_block, positioning_context)
920 },
921 };
922
923 self.with_base(|base| base.set_fragment(fragment.clone()));
924
925 fragment
926 }
927
928 fn inline_content_sizes(
929 &self,
930 layout_context: &LayoutContext,
931 constraint_space: &ConstraintSpace,
932 ) -> InlineContentSizesResult {
933 let independent_formatting_context = match self {
934 BlockLevelBox::Independent(independent) => independent,
935 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => &box_.borrow().context,
936 BlockLevelBox::OutOfFlowFloatBox(float_box) => &float_box.contents,
937 BlockLevelBox::OutsideMarker(outside_marker) => &outside_marker.context,
938 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
939 return base.inline_content_sizes(layout_context, constraint_space, contents);
940 },
941 };
942 independent_formatting_context.inline_content_sizes(layout_context, constraint_space)
943 }
944}
945
946#[allow(clippy::too_many_arguments)]
952pub(crate) fn layout_in_flow_non_replaced_block_level_same_formatting_context(
953 layout_context: &LayoutContext,
954 positioning_context: &mut PositioningContext,
955 containing_block: &ContainingBlock,
956 base: &LayoutBoxBase,
957 contents: &BlockContainer,
958 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
959 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
960 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
961) -> BoxFragment {
962 let style = &base.style;
963 let layout_style = contents.layout_style(base);
964 let containing_block_writing_mode = containing_block.style.writing_mode;
965 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
966 base.inline_content_sizes(layout_context, constraint_space, contents)
967 .sizes
968 };
969 let ContainingBlockPaddingAndBorder {
970 containing_block: containing_block_for_children,
971 pbm,
972 block_sizes,
973 depends_on_block_constraints,
974 available_block_size,
975 justify_self,
976 ..
977 } = solve_containing_block_padding_and_border_for_in_flow_box(
978 containing_block,
979 &layout_style,
980 get_inline_content_sizes,
981 ignore_block_margins_for_stretch,
982 None,
983 );
984 let ResolvedMargins {
985 margin,
986 effective_margin_inline_start,
987 } = solve_margins(
988 containing_block,
989 &pbm,
990 containing_block_for_children.size.inline,
991 justify_self,
992 );
993
994 let start_margin_can_collapse_with_children =
995 pbm.padding.block_start.is_zero() && pbm.border.block_start.is_zero();
996
997 let mut clearance = None;
998 let parent_containing_block_position_info;
999 match sequential_layout_state {
1000 None => parent_containing_block_position_info = None,
1001 Some(ref mut sequential_layout_state) => {
1002 let clear =
1003 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode);
1004 let mut block_start_margin = CollapsedMargin::new(margin.block_start);
1005
1006 let collapsible_with_parent_start_margin = collapsible_with_parent_start_margin.expect(
1018 "We should know whether we are collapsing the block start margin with the parent \
1019 when laying out sequentially",
1020 ).0 && clear == Clear::None;
1021 if !collapsible_with_parent_start_margin && start_margin_can_collapse_with_children {
1022 contents.find_block_margin_collapsing_with_parent(
1023 layout_context,
1024 &mut block_start_margin,
1025 &containing_block_for_children,
1026 );
1027 }
1028
1029 clearance = sequential_layout_state.calculate_clearance(clear, &block_start_margin);
1031 if clearance.is_some() {
1032 sequential_layout_state.collapse_margins();
1033 }
1034 sequential_layout_state.adjoin_assign(&block_start_margin);
1035 if !start_margin_can_collapse_with_children {
1036 sequential_layout_state.collapse_margins();
1037 }
1038
1039 sequential_layout_state.advance_block_position(
1042 pbm.padding.block_start +
1043 pbm.border.block_start +
1044 clearance.unwrap_or_else(Au::zero),
1045 );
1046
1047 let inline_start = sequential_layout_state
1053 .floats
1054 .containing_block_info
1055 .inline_start +
1056 pbm.padding.inline_start +
1057 pbm.border.inline_start +
1058 effective_margin_inline_start;
1059 let new_cb_offsets = ContainingBlockPositionInfo {
1060 block_start: sequential_layout_state.bfc_relative_block_position,
1061 block_start_margins_not_collapsed: sequential_layout_state.current_margin,
1062 inline_start,
1063 inline_end: inline_start + containing_block_for_children.size.inline,
1064 };
1065 parent_containing_block_position_info = Some(
1066 sequential_layout_state.replace_containing_block_position_info(new_cb_offsets),
1067 );
1068 },
1069 };
1070
1071 let ignore_block_margins_for_stretch = LogicalSides1D::new(
1077 pbm.border.block_start.is_zero() && pbm.padding.block_start.is_zero(),
1078 pbm.border.block_end.is_zero() && pbm.padding.block_end.is_zero(),
1079 );
1080
1081 let flow_layout = contents.layout(
1082 layout_context,
1083 positioning_context,
1084 &containing_block_for_children,
1085 sequential_layout_state.as_deref_mut(),
1086 CollapsibleWithParentStartMargin(start_margin_can_collapse_with_children),
1087 ignore_block_margins_for_stretch,
1088 );
1089 let mut content_block_size = flow_layout.content_block_size;
1090
1091 let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1093 let mut collapsible_margins_in_children = flow_layout.collapsible_margins_in_children;
1094 if start_margin_can_collapse_with_children {
1095 block_margins_collapsed_with_children
1096 .start
1097 .adjoin_assign(&collapsible_margins_in_children.start);
1098 if collapsible_margins_in_children.collapsed_through {
1099 block_margins_collapsed_with_children
1100 .start
1101 .adjoin_assign(&std::mem::replace(
1102 &mut collapsible_margins_in_children.end,
1103 CollapsedMargin::zero(),
1104 ));
1105 }
1106 }
1107
1108 let is_anonymous = matches!(base.style.pseudo(), Some(PseudoElement::ServoAnonymousBox));
1109 let tentative_block_size = if is_anonymous {
1110 &Default::default()
1114 } else {
1115 &containing_block_for_children.size.block
1116 };
1117 let collapsed_through = collapsible_margins_in_children.collapsed_through &&
1118 pbm.padding_border_sums.block.is_zero() &&
1119 tentative_block_size.definite_or_min().is_zero();
1120 block_margins_collapsed_with_children.collapsed_through = collapsed_through;
1121
1122 let end_margin_can_collapse_with_children =
1123 pbm.padding.block_end.is_zero() && pbm.border.block_end.is_zero();
1124 if !end_margin_can_collapse_with_children {
1125 content_block_size += collapsible_margins_in_children.end.solve();
1126 }
1127
1128 let block_size = block_sizes.resolve(
1129 Direction::Block,
1130 Size::FitContent,
1131 Au::zero,
1132 available_block_size,
1133 || content_block_size.into(),
1134 false, );
1136
1137 let end_margin_can_collapse_with_children = end_margin_can_collapse_with_children &&
1152 block_size == content_block_size &&
1153 (collapsed_through || !tentative_block_size.is_definite());
1154 if end_margin_can_collapse_with_children {
1155 block_margins_collapsed_with_children
1156 .end
1157 .adjoin_assign(&collapsible_margins_in_children.end);
1158 }
1159
1160 if let Some(ref mut sequential_layout_state) = sequential_layout_state {
1161 sequential_layout_state
1164 .replace_containing_block_position_info(parent_containing_block_position_info.unwrap());
1165
1166 sequential_layout_state.advance_block_position(
1176 block_size - content_block_size + pbm.padding.block_end + pbm.border.block_end,
1177 );
1178
1179 if !end_margin_can_collapse_with_children {
1180 sequential_layout_state.collapse_margins();
1181 }
1182 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1183 }
1184
1185 let content_rect = LogicalRect {
1186 start_corner: LogicalVec2 {
1187 block: (pbm.padding.block_start +
1188 pbm.border.block_start +
1189 clearance.unwrap_or_else(Au::zero)),
1190 inline: pbm.padding.inline_start +
1191 pbm.border.inline_start +
1192 effective_margin_inline_start,
1193 },
1194 size: LogicalVec2 {
1195 block: block_size,
1196 inline: containing_block_for_children.size.inline,
1197 },
1198 };
1199
1200 let mut base_fragment_info = base.base_fragment_info;
1201
1202 if depends_on_block_constraints || (is_anonymous && flow_layout.depends_on_block_constraints) {
1206 base_fragment_info
1207 .flags
1208 .insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM);
1209 }
1210
1211 BoxFragment::new(
1212 base_fragment_info,
1213 style.clone(),
1214 flow_layout.fragments,
1215 content_rect.as_physical(Some(containing_block)),
1216 pbm.padding.to_physical(containing_block_writing_mode),
1217 pbm.border.to_physical(containing_block_writing_mode),
1218 margin.to_physical(containing_block_writing_mode),
1219 flow_layout.specific_layout_info,
1220 )
1221 .with_baselines(flow_layout.baselines)
1222 .with_block_level_layout_info(block_margins_collapsed_with_children, clearance)
1223}
1224
1225impl IndependentFormattingContext {
1226 pub(crate) fn layout_in_flow_block_level(
1234 &self,
1235 layout_context: &LayoutContext,
1236 positioning_context: &mut PositioningContext,
1237 containing_block: &ContainingBlock,
1238 sequential_layout_state: Option<&mut SequentialLayoutState>,
1239 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1240 ) -> BoxFragment {
1241 if let Some(sequential_layout_state) = sequential_layout_state {
1242 return self.layout_in_flow_block_level_sequentially(
1243 layout_context,
1244 positioning_context,
1245 containing_block,
1246 sequential_layout_state,
1247 ignore_block_margins_for_stretch,
1248 );
1249 }
1250
1251 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
1252 self.inline_content_sizes(layout_context, constraint_space)
1253 .sizes
1254 };
1255 let layout_style = self.layout_style();
1256 let ContainingBlockPaddingAndBorder {
1257 containing_block: containing_block_for_children,
1258 pbm,
1259 block_sizes,
1260 depends_on_block_constraints,
1261 available_block_size,
1262 justify_self,
1263 preferred_aspect_ratio,
1264 } = solve_containing_block_padding_and_border_for_in_flow_box(
1265 containing_block,
1266 &layout_style,
1267 get_inline_content_sizes,
1268 ignore_block_margins_for_stretch,
1269 Some(self),
1270 );
1271
1272 let lazy_block_size = LazySize::new(
1273 &block_sizes,
1274 Direction::Block,
1275 Size::FitContent,
1276 Au::zero,
1277 available_block_size,
1278 layout_style.is_table(),
1279 );
1280
1281 let layout = self.layout(
1282 layout_context,
1283 positioning_context,
1284 &containing_block_for_children,
1285 containing_block,
1286 preferred_aspect_ratio,
1287 &lazy_block_size,
1288 );
1289
1290 let inline_size = layout
1291 .content_inline_size_for_table
1292 .unwrap_or(containing_block_for_children.size.inline);
1293 let block_size = lazy_block_size.resolve(|| layout.content_block_size);
1294
1295 let ResolvedMargins {
1296 margin,
1297 effective_margin_inline_start,
1298 } = solve_margins(containing_block, &pbm, inline_size, justify_self);
1299
1300 let content_rect = LogicalRect {
1301 start_corner: LogicalVec2 {
1302 block: pbm.padding.block_start + pbm.border.block_start,
1303 inline: pbm.padding.inline_start +
1304 pbm.border.inline_start +
1305 effective_margin_inline_start,
1306 },
1307 size: LogicalVec2 {
1308 block: block_size,
1309 inline: inline_size,
1310 },
1311 };
1312
1313 let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1314 let containing_block_writing_mode = containing_block.style.writing_mode;
1315
1316 let mut base_fragment_info = self.base.base_fragment_info;
1317 if depends_on_block_constraints {
1318 base_fragment_info.flags.insert(
1319 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1320 );
1321 }
1322 BoxFragment::new(
1323 base_fragment_info,
1324 self.base.style.clone(),
1325 layout.fragments,
1326 content_rect.as_physical(Some(containing_block)),
1327 pbm.padding.to_physical(containing_block_writing_mode),
1328 pbm.border.to_physical(containing_block_writing_mode),
1329 margin.to_physical(containing_block_writing_mode),
1330 layout.specific_layout_info,
1331 )
1332 .with_baselines(layout.baselines)
1333 .with_block_level_layout_info(block_margins_collapsed_with_children, None)
1334 }
1335
1336 fn layout_in_flow_block_level_sequentially(
1340 &self,
1341 layout_context: &LayoutContext<'_>,
1342 positioning_context: &mut PositioningContext,
1343 containing_block: &ContainingBlock<'_>,
1344 sequential_layout_state: &mut SequentialLayoutState,
1345 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1346 ) -> BoxFragment {
1347 let style = &self.base.style;
1348 let containing_block_writing_mode = containing_block.style.writing_mode;
1349 let ContentBoxSizesAndPBM {
1350 content_box_sizes,
1351 pbm,
1352 depends_on_block_constraints,
1353 ..
1354 } = self
1355 .layout_style()
1356 .content_box_sizes_and_padding_border_margin(&containing_block.into());
1357
1358 let (margin_block_start, margin_block_end) =
1359 solve_block_margins_for_in_flow_block_level(&pbm);
1360 let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
1361
1362 let mut content_size;
1373 let mut layout;
1374 let mut placement_rect;
1375
1376 let clear_position = sequential_layout_state.calculate_clear_position(
1380 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
1381 &collapsed_margin_block_start,
1382 );
1383 let ceiling = clear_position.unwrap_or_else(|| {
1384 sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
1385 });
1386
1387 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1389 let available_block_size = containing_block
1390 .size
1391 .block
1392 .to_definite()
1393 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1394 let is_table = self.is_table();
1395 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
1396 let tentative_block_content_size =
1397 self.tentative_block_content_size(preferred_aspect_ratio);
1398 let (preferred_block_size, min_block_size, max_block_size) =
1399 if let Some(block_content_size) = tentative_block_content_size {
1400 let (preferred, min, max) = content_box_sizes.block.resolve_each(
1401 Size::FitContent,
1402 Au::zero,
1403 available_block_size,
1404 || block_content_size,
1405 is_table,
1406 );
1407 (Some(preferred), min, max)
1408 } else {
1409 content_box_sizes.block.resolve_each_extrinsic(
1410 Size::FitContent,
1411 Au::zero(),
1412 available_block_size,
1413 )
1414 };
1415 let tentative_block_size =
1416 SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
1417
1418 let get_inline_content_sizes = || {
1420 let constraint_space =
1421 ConstraintSpace::new(tentative_block_size, style, preferred_aspect_ratio);
1422 self.inline_content_sizes(layout_context, &constraint_space)
1423 .sizes
1424 };
1425
1426 let justify_self = resolve_justify_self(style, containing_block.style);
1427 let automatic_inline_size = automatic_inline_size(justify_self, Some(self));
1428 let compute_inline_size = |stretch_size| {
1429 content_box_sizes.inline.resolve(
1430 Direction::Inline,
1431 automatic_inline_size,
1432 Au::zero,
1433 Some(stretch_size),
1434 get_inline_content_sizes,
1435 is_table,
1436 )
1437 };
1438
1439 let get_lazy_block_size = || {
1440 LazySize::new(
1441 &content_box_sizes.block,
1442 Direction::Block,
1443 Size::FitContent,
1444 Au::zero,
1445 available_block_size,
1446 is_table,
1447 )
1448 };
1449
1450 let inline_size_with_no_available_space = compute_inline_size(Au::zero());
1459 if inline_size_with_no_available_space == compute_inline_size(MAX_AU) {
1460 let inline_size = inline_size_with_no_available_space;
1464 let lazy_block_size = get_lazy_block_size();
1465 layout = self.layout(
1466 layout_context,
1467 positioning_context,
1468 &ContainingBlock {
1469 size: ContainingBlockSize {
1470 inline: inline_size,
1471 block: tentative_block_size,
1472 },
1473 style,
1474 },
1475 containing_block,
1476 preferred_aspect_ratio,
1477 &lazy_block_size,
1478 );
1479
1480 content_size = LogicalVec2 {
1481 block: lazy_block_size.resolve(|| layout.content_block_size),
1482 inline: layout.content_inline_size_for_table.unwrap_or(inline_size),
1483 };
1484
1485 let mut placement = PlacementAmongFloats::new(
1486 &sequential_layout_state.floats,
1487 ceiling,
1488 content_size + pbm.padding_border_sums,
1489 &pbm,
1490 );
1491 placement_rect = placement.place();
1492 } else {
1493 let minimum_size_of_block = LogicalVec2 {
1499 inline: inline_size_with_no_available_space,
1503 block: match tentative_block_size {
1504 SizeConstraint::Definite(size) if max_block_size.is_some() => size,
1507 _ => min_block_size,
1510 },
1511 } + pbm.padding_border_sums;
1512 let mut placement = PlacementAmongFloats::new(
1513 &sequential_layout_state.floats,
1514 ceiling,
1515 minimum_size_of_block,
1516 &pbm,
1517 );
1518
1519 loop {
1520 placement_rect = placement.place();
1522 let available_inline_size =
1523 placement_rect.size.inline - pbm.padding_border_sums.inline;
1524 let proposed_inline_size = compute_inline_size(available_inline_size);
1525
1526 let positioning_context_length = positioning_context.len();
1530 let lazy_block_size = get_lazy_block_size();
1531 layout = self.layout(
1532 layout_context,
1533 positioning_context,
1534 &ContainingBlock {
1535 size: ContainingBlockSize {
1536 inline: proposed_inline_size,
1537 block: tentative_block_size,
1538 },
1539 style,
1540 },
1541 containing_block,
1542 preferred_aspect_ratio,
1543 &lazy_block_size,
1544 );
1545
1546 let inline_size = if let Some(inline_size) = layout.content_inline_size_for_table {
1547 debug_assert!(inline_size < proposed_inline_size);
1552 inline_size
1553 } else {
1554 proposed_inline_size
1555 };
1556 content_size = LogicalVec2 {
1557 block: lazy_block_size.resolve(|| layout.content_block_size),
1558 inline: inline_size,
1559 };
1560
1561 if placement.try_to_expand_for_auto_block_size(
1565 content_size.block + pbm.padding_border_sums.block,
1566 &placement_rect.size,
1567 ) {
1568 break;
1569 }
1570
1571 positioning_context.truncate(&positioning_context_length);
1575 }
1576 }
1577
1578 let has_clearance = clear_position.is_some() || placement_rect.start_corner.block > ceiling;
1582 let clearance = has_clearance.then(|| {
1583 placement_rect.start_corner.block -
1584 sequential_layout_state
1585 .position_with_zero_clearance(&collapsed_margin_block_start)
1586 });
1587
1588 let ((margin_inline_start, margin_inline_end), effective_margin_inline_start) =
1589 solve_inline_margins_avoiding_floats(
1590 sequential_layout_state,
1591 containing_block,
1592 &pbm,
1593 content_size.inline + pbm.padding_border_sums.inline,
1594 placement_rect,
1595 justify_self,
1596 );
1597
1598 let margin = LogicalSides {
1599 inline_start: margin_inline_start,
1600 inline_end: margin_inline_end,
1601 block_start: margin_block_start,
1602 block_end: margin_block_end,
1603 };
1604
1605 if clearance.is_some() {
1608 sequential_layout_state.collapse_margins();
1609 }
1610 sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
1611
1612 sequential_layout_state.collapse_margins();
1614 sequential_layout_state.advance_block_position(
1615 pbm.padding_border_sums.block + content_size.block + clearance.unwrap_or_else(Au::zero),
1616 );
1617 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1618
1619 let content_rect = LogicalRect {
1620 start_corner: LogicalVec2 {
1621 block: pbm.padding.block_start +
1622 pbm.border.block_start +
1623 clearance.unwrap_or_else(Au::zero),
1624 inline: pbm.padding.inline_start +
1625 pbm.border.inline_start +
1626 effective_margin_inline_start,
1627 },
1628 size: content_size,
1629 };
1630
1631 let mut base_fragment_info = self.base.base_fragment_info;
1632 if depends_on_block_constraints {
1633 base_fragment_info.flags.insert(
1634 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1635 );
1636 }
1637
1638 BoxFragment::new(
1639 base_fragment_info,
1640 style.clone(),
1641 layout.fragments,
1642 content_rect.as_physical(Some(containing_block)),
1643 pbm.padding.to_physical(containing_block_writing_mode),
1644 pbm.border.to_physical(containing_block_writing_mode),
1645 margin.to_physical(containing_block_writing_mode),
1646 layout.specific_layout_info,
1647 )
1648 .with_baselines(layout.baselines)
1649 .with_block_level_layout_info(CollapsedBlockMargins::from_margin(&margin), clearance)
1650 }
1651}
1652
1653struct ContainingBlockPaddingAndBorder<'a> {
1654 containing_block: ContainingBlock<'a>,
1655 pbm: PaddingBorderMargin,
1656 block_sizes: Sizes,
1657 depends_on_block_constraints: bool,
1658 available_block_size: Option<Au>,
1659 justify_self: AlignFlags,
1660 preferred_aspect_ratio: Option<AspectRatio>,
1661}
1662
1663struct ResolvedMargins {
1664 pub margin: LogicalSides<Au>,
1666
1667 pub effective_margin_inline_start: Au,
1674}
1675
1676fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
1682 containing_block: &ContainingBlock<'_>,
1683 layout_style: &'a LayoutStyle,
1684 get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
1685 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1686 context: Option<&IndependentFormattingContext>,
1687) -> ContainingBlockPaddingAndBorder<'a> {
1688 let style = layout_style.style();
1689 if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
1690 let containing_block_for_children = ContainingBlock {
1694 size: ContainingBlockSize {
1695 inline: containing_block.size.inline,
1696 block: containing_block.size.block,
1697 },
1698 style,
1699 };
1700 return ContainingBlockPaddingAndBorder {
1703 containing_block: containing_block_for_children,
1704 pbm: PaddingBorderMargin::zero(),
1705 block_sizes: Sizes::default(),
1706 depends_on_block_constraints: false,
1707 available_block_size: None,
1710 justify_self: AlignFlags::NORMAL,
1713 preferred_aspect_ratio: None,
1714 };
1715 }
1716
1717 let ContentBoxSizesAndPBM {
1718 content_box_sizes,
1719 pbm,
1720 depends_on_block_constraints,
1721 ..
1722 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
1723
1724 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1725 let available_inline_size = Au::zero().max(containing_block.size.inline - pbm_sums.inline);
1726 let available_block_size = containing_block
1727 .size
1728 .block
1729 .to_definite()
1730 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1731
1732 let preferred_aspect_ratio =
1735 context.and_then(|context| context.preferred_aspect_ratio(&pbm.padding_border_sums));
1736 let is_table = layout_style.is_table();
1737
1738 let tentative_block_content_size =
1741 context.and_then(|context| context.tentative_block_content_size(preferred_aspect_ratio));
1742 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
1743 SizeConstraint::Definite(content_box_sizes.block.resolve(
1744 Direction::Block,
1745 Size::FitContent,
1746 Au::zero,
1747 available_block_size,
1748 || block_content_size,
1749 is_table,
1750 ))
1751 } else {
1752 content_box_sizes.block.resolve_extrinsic(
1753 Size::FitContent,
1754 Au::zero(),
1755 available_block_size,
1756 )
1757 };
1758
1759 let get_inline_content_sizes = || {
1762 get_inline_content_sizes(&ConstraintSpace::new(
1763 tentative_block_size,
1764 style,
1765 preferred_aspect_ratio,
1766 ))
1767 };
1768 let justify_self = resolve_justify_self(style, containing_block.style);
1769 let inline_size = content_box_sizes.inline.resolve(
1770 Direction::Inline,
1771 automatic_inline_size(justify_self, context),
1772 Au::zero,
1773 Some(available_inline_size),
1774 get_inline_content_sizes,
1775 is_table,
1776 );
1777
1778 let containing_block_for_children = ContainingBlock {
1779 size: ContainingBlockSize {
1780 inline: inline_size,
1781 block: tentative_block_size,
1782 },
1783 style,
1784 };
1785 assert_eq!(
1787 containing_block.style.writing_mode.is_horizontal(),
1788 containing_block_for_children
1789 .style
1790 .writing_mode
1791 .is_horizontal(),
1792 "Vertical writing modes are not supported yet"
1793 );
1794 ContainingBlockPaddingAndBorder {
1795 containing_block: containing_block_for_children,
1796 pbm,
1797 block_sizes: content_box_sizes.block,
1798 depends_on_block_constraints,
1799 available_block_size,
1800 justify_self,
1801 preferred_aspect_ratio,
1802 }
1803}
1804
1805fn solve_margins(
1810 containing_block: &ContainingBlock<'_>,
1811 pbm: &PaddingBorderMargin,
1812 inline_size: Au,
1813 justify_self: AlignFlags,
1814) -> ResolvedMargins {
1815 let (inline_margins, effective_margin_inline_start) =
1816 solve_inline_margins_for_in_flow_block_level(
1817 containing_block,
1818 pbm,
1819 inline_size,
1820 justify_self,
1821 );
1822 let block_margins = solve_block_margins_for_in_flow_block_level(pbm);
1823 ResolvedMargins {
1824 margin: LogicalSides {
1825 inline_start: inline_margins.0,
1826 inline_end: inline_margins.1,
1827 block_start: block_margins.0,
1828 block_end: block_margins.1,
1829 },
1830 effective_margin_inline_start,
1831 }
1832}
1833
1834fn solve_block_margins_for_in_flow_block_level(pbm: &PaddingBorderMargin) -> (Au, Au) {
1838 (
1839 pbm.margin.block_start.auto_is(Au::zero),
1840 pbm.margin.block_end.auto_is(Au::zero),
1841 )
1842}
1843
1844fn resolve_justify_self(style: &ComputedValues, parent_style: &ComputedValues) -> AlignFlags {
1846 let is_ltr = |style: &ComputedValues| style.writing_mode.line_left_is_inline_start();
1847 let alignment = match style.clone_justify_self().0 {
1848 AlignFlags::AUTO => parent_style.clone_justify_items().computed.0.0,
1849 alignment => alignment,
1850 };
1851 let alignment_value = match alignment.value() {
1852 AlignFlags::LEFT if is_ltr(parent_style) => AlignFlags::START,
1853 AlignFlags::LEFT => AlignFlags::END,
1854 AlignFlags::RIGHT if is_ltr(parent_style) => AlignFlags::END,
1855 AlignFlags::RIGHT => AlignFlags::START,
1856 AlignFlags::SELF_START if is_ltr(parent_style) == is_ltr(style) => AlignFlags::START,
1857 AlignFlags::SELF_START => AlignFlags::END,
1858 AlignFlags::SELF_END if is_ltr(parent_style) == is_ltr(style) => AlignFlags::END,
1859 AlignFlags::SELF_END => AlignFlags::START,
1860 alignment_value => alignment_value,
1861 };
1862 alignment.flags() | alignment_value
1863}
1864
1865#[inline]
1868fn automatic_inline_size<T>(
1869 justify_self: AlignFlags,
1870 context: Option<&IndependentFormattingContext>,
1871) -> Size<T> {
1872 let normal_stretches = || {
1873 !context.is_some_and(|context| {
1874 context
1875 .base
1876 .base_fragment_info
1877 .flags
1878 .intersects(FragmentFlags::IS_REPLACED | FragmentFlags::IS_WIDGET) ||
1879 context.is_table()
1880 })
1881 };
1882 match justify_self {
1883 AlignFlags::STRETCH => Size::Stretch,
1884 AlignFlags::NORMAL if normal_stretches() => Size::Stretch,
1885 _ => Size::FitContent,
1886 }
1887}
1888
1889fn justify_self_alignment(
1896 containing_block: &ContainingBlock,
1897 free_space: Au,
1898 justify_self: AlignFlags,
1899) -> Au {
1900 let mut alignment = justify_self.value();
1901 let is_safe = justify_self.flags() == AlignFlags::SAFE || alignment == AlignFlags::NORMAL;
1902 if is_safe && free_space <= Au::zero() {
1903 alignment = AlignFlags::START
1904 }
1905 match alignment {
1906 AlignFlags::NORMAL => {},
1907 AlignFlags::CENTER => return free_space / 2,
1908 AlignFlags::END => return free_space,
1909 _ => return Au::zero(),
1910 }
1911
1912 let style = containing_block.style;
1914 match style.clone_text_align() {
1915 TextAlignKeyword::MozCenter => free_space / 2,
1916 TextAlignKeyword::MozLeft if !style.writing_mode.line_left_is_inline_start() => free_space,
1917 TextAlignKeyword::MozRight if style.writing_mode.line_left_is_inline_start() => free_space,
1918 _ => Au::zero(),
1919 }
1920}
1921
1922fn solve_inline_margins_for_in_flow_block_level(
1935 containing_block: &ContainingBlock,
1936 pbm: &PaddingBorderMargin,
1937 inline_size: Au,
1938 justify_self: AlignFlags,
1939) -> ((Au, Au), Au) {
1940 let free_space = containing_block.size.inline - pbm.padding_border_sums.inline - inline_size;
1941 let mut justification = Au::zero();
1942 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1943 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1944 let start = Au::zero().max(free_space / 2);
1945 (start, free_space - start)
1946 },
1947 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => {
1948 (Au::zero().max(free_space - end), end)
1949 },
1950 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, free_space - start),
1951 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1952 justification =
1957 justify_self_alignment(containing_block, free_space - start - end, justify_self);
1958 (start, end)
1959 },
1960 };
1961 let effective_margin_inline_start = inline_margins.0 + justification;
1962 (inline_margins, effective_margin_inline_start)
1963}
1964
1965fn solve_inline_margins_avoiding_floats(
1975 sequential_layout_state: &SequentialLayoutState,
1976 containing_block: &ContainingBlock,
1977 pbm: &PaddingBorderMargin,
1978 inline_size: Au,
1979 placement_rect: LogicalRect<Au>,
1980 justify_self: AlignFlags,
1981) -> ((Au, Au), Au) {
1982 let free_space = Au::zero().max(placement_rect.size.inline - inline_size);
1986 let cb_info = &sequential_layout_state.floats.containing_block_info;
1987 let start_adjustment = placement_rect.start_corner.inline - cb_info.inline_start;
1988 let end_adjustment = cb_info.inline_end - placement_rect.max_inline_position();
1989 let mut justification = Au::zero();
1990 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1991 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1992 let half = free_space / 2;
1993 (start_adjustment + half, end_adjustment + free_space - half)
1994 },
1995 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (start_adjustment + free_space, end),
1996 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, end_adjustment + free_space),
1997 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1998 justification = justify_self_alignment(containing_block, free_space, justify_self);
2004 (start, end)
2005 },
2006 };
2007 let effective_margin_inline_start = inline_margins.0.max(start_adjustment) + justification;
2008 (inline_margins, effective_margin_inline_start)
2009}
2010
2011struct PlacementState<'container> {
2016 next_in_flow_margin_collapses_with_parent_start_margin: bool,
2017 last_in_flow_margin_collapses_with_parent_end_margin: bool,
2018 start_margin: CollapsedMargin,
2019 current_margin: CollapsedMargin,
2020 current_block_direction_position: Au,
2021 inflow_baselines: Baselines,
2022 is_inline_block_context: bool,
2023
2024 marker_block_size: Option<Au>,
2029
2030 containing_block: &'container ContainingBlock<'container>,
2033}
2034
2035impl<'container> PlacementState<'container> {
2036 fn new(
2037 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
2038 containing_block: &'container ContainingBlock<'container>,
2039 ) -> PlacementState<'container> {
2040 let is_inline_block_context =
2041 containing_block.style.get_box().clone_display() == Display::InlineBlock;
2042 PlacementState {
2043 next_in_flow_margin_collapses_with_parent_start_margin:
2044 collapsible_with_parent_start_margin.0,
2045 last_in_flow_margin_collapses_with_parent_end_margin: true,
2046 start_margin: CollapsedMargin::zero(),
2047 current_margin: CollapsedMargin::zero(),
2048 current_block_direction_position: Au::zero(),
2049 inflow_baselines: Baselines::default(),
2050 is_inline_block_context,
2051 marker_block_size: None,
2052 containing_block,
2053 }
2054 }
2055
2056 fn place_fragment_and_update_baseline(
2057 &mut self,
2058 fragment: &mut Fragment,
2059 sequential_layout_state: Option<&mut SequentialLayoutState>,
2060 ) {
2061 self.place_fragment(fragment, sequential_layout_state);
2062
2063 let box_fragment = match fragment {
2064 Fragment::Box(box_fragment) => box_fragment,
2065 _ => return,
2066 };
2067 let box_fragment = box_fragment.borrow();
2068
2069 if self.is_inline_block_context && box_fragment.is_table_wrapper() {
2074 return;
2075 }
2076
2077 let box_block_offset = box_fragment
2078 .content_rect()
2079 .origin
2080 .to_logical(self.containing_block)
2081 .block;
2082 let box_fragment_baselines =
2083 box_fragment.baselines(self.containing_block.style.writing_mode);
2084 if let (None, Some(first)) = (self.inflow_baselines.first, box_fragment_baselines.first) {
2085 self.inflow_baselines.first = Some(first + box_block_offset);
2086 }
2087 if let Some(last) = box_fragment_baselines.last {
2088 self.inflow_baselines.last = Some(last + box_block_offset);
2089 }
2090 }
2091
2092 fn place_fragment(
2095 &mut self,
2096 fragment: &mut Fragment,
2097 sequential_layout_state: Option<&mut SequentialLayoutState>,
2098 ) {
2099 match fragment {
2100 Fragment::Box(fragment) => {
2101 let fragment = &mut *fragment.borrow_mut();
2110 let is_outside_marker = fragment
2111 .base
2112 .flags
2113 .contains(FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER);
2114 if is_outside_marker {
2115 assert!(self.marker_block_size.is_none());
2116 self.marker_block_size = Some(
2117 fragment
2118 .content_rect()
2119 .size
2120 .to_logical(self.containing_block.style.writing_mode)
2121 .block,
2122 );
2123 return;
2124 }
2125
2126 let BlockLevelLayoutInfo {
2127 clearance,
2128 block_margins_collapsed_with_children: fragment_block_margins,
2129 } = &**fragment
2130 .block_level_layout_info
2131 .as_ref()
2132 .expect("A block-level fragment should have a BlockLevelLayoutInfo.");
2133 let mut fragment_block_size = fragment
2134 .border_rect()
2135 .size
2136 .to_logical(self.containing_block.style.writing_mode)
2137 .block;
2138
2139 if let Some(clearance) = *clearance {
2145 fragment_block_size += clearance;
2146 self.current_block_direction_position += self.current_margin.solve();
2151 self.current_margin = CollapsedMargin::zero();
2152 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2153 if fragment_block_margins.collapsed_through {
2154 self.last_in_flow_margin_collapses_with_parent_end_margin = false;
2155 }
2156 } else if !fragment_block_margins.collapsed_through {
2157 self.last_in_flow_margin_collapses_with_parent_end_margin = true;
2158 }
2159
2160 if self.next_in_flow_margin_collapses_with_parent_start_margin {
2161 debug_assert!(self.current_margin.solve().is_zero());
2162 self.start_margin
2163 .adjoin_assign(&fragment_block_margins.start);
2164 if fragment_block_margins.collapsed_through {
2165 self.start_margin.adjoin_assign(&fragment_block_margins.end);
2166 return;
2167 }
2168 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2169 } else {
2170 self.current_margin
2171 .adjoin_assign(&fragment_block_margins.start);
2172 }
2173
2174 fragment.base.rect.origin += LogicalVec2 {
2175 inline: Au::zero(),
2176 block: self.current_margin.solve() + self.current_block_direction_position,
2177 }
2178 .to_physical_size(self.containing_block.style.writing_mode);
2179
2180 if fragment_block_margins.collapsed_through {
2181 self.current_block_direction_position += fragment_block_size;
2184 self.current_margin
2185 .adjoin_assign(&fragment_block_margins.end);
2186 } else {
2187 self.current_block_direction_position +=
2188 self.current_margin.solve() + fragment_block_size;
2189 self.current_margin = fragment_block_margins.end;
2190 }
2191 },
2192 Fragment::AbsoluteOrFixedPositioned(fragment) => {
2193 fragment.borrow_mut().original_static_position_rect = LogicalRect {
2196 start_corner: LogicalVec2 {
2197 block: (self.current_margin.solve() +
2198 self.current_block_direction_position),
2199 inline: Au::zero(),
2200 },
2201 size: LogicalVec2::zero(),
2202 }
2203 .as_physical(Some(self.containing_block));
2204 },
2205 Fragment::Float(box_fragment) => {
2206 let sequential_layout_state = sequential_layout_state
2207 .expect("Found float fragment without SequentialLayoutState");
2208 let block_offset_from_containing_block_top =
2209 self.current_block_direction_position + self.current_margin.solve();
2210 let box_fragment = &mut *box_fragment.borrow_mut();
2211 sequential_layout_state.place_float_fragment(
2212 box_fragment,
2213 self.containing_block,
2214 self.start_margin,
2215 block_offset_from_containing_block_top,
2216 );
2217 },
2218 Fragment::Positioning(_) => {},
2219 _ => unreachable!(),
2220 }
2221 }
2222
2223 fn finish(mut self) -> (Au, CollapsedBlockMargins, Baselines) {
2224 if !self.last_in_flow_margin_collapses_with_parent_end_margin {
2225 self.current_block_direction_position += self.current_margin.solve();
2226 self.current_margin = CollapsedMargin::zero();
2227 }
2228 let (total_block_size, collapsed_through) = match self.marker_block_size {
2229 Some(marker_block_size) => (
2230 self.current_block_direction_position.max(marker_block_size),
2231 false,
2234 ),
2235 None => (
2236 self.current_block_direction_position,
2237 self.next_in_flow_margin_collapses_with_parent_start_margin,
2238 ),
2239 };
2240
2241 (
2242 total_block_size,
2243 CollapsedBlockMargins {
2244 collapsed_through,
2245 start: self.start_margin,
2246 end: self.current_margin,
2247 },
2248 self.inflow_baselines,
2249 )
2250 }
2251}
2252
2253pub(crate) struct IndependentFloatOrAtomicLayoutResult {
2254 pub fragment: BoxFragment,
2255 pub baselines: Baselines,
2256 pub pbm_sums: LogicalSides<Au>,
2257}
2258
2259impl IndependentFormattingContext {
2260 pub(crate) fn layout_float_or_atomic_inline(
2261 &self,
2262 layout_context: &LayoutContext,
2263 child_positioning_context: &mut PositioningContext,
2264 containing_block: &ContainingBlock,
2265 ) -> IndependentFloatOrAtomicLayoutResult {
2266 let style = self.style();
2267 let container_writing_mode = containing_block.style.writing_mode;
2268 let layout_style = self.layout_style();
2269 let content_box_sizes_and_pbm =
2270 layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
2271 let pbm = &content_box_sizes_and_pbm.pbm;
2272 let margin = pbm.margin.auto_is(Au::zero);
2273 let pbm_sums = pbm.padding + pbm.border + margin;
2274 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
2275 let is_table = self.is_table();
2276
2277 let available_inline_size =
2278 Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
2279 let available_block_size = containing_block
2280 .size
2281 .block
2282 .to_definite()
2283 .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
2284
2285 let tentative_block_content_size =
2286 self.tentative_block_content_size(preferred_aspect_ratio);
2287 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
2288 SizeConstraint::Definite(content_box_sizes_and_pbm.content_box_sizes.block.resolve(
2289 Direction::Block,
2290 Size::FitContent,
2291 Au::zero,
2292 available_block_size,
2293 || block_content_size,
2294 is_table,
2295 ))
2296 } else {
2297 content_box_sizes_and_pbm
2298 .content_box_sizes
2299 .block
2300 .resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size)
2301 };
2302
2303 let get_content_size = || {
2304 let constraint_space =
2305 ConstraintSpace::new(tentative_block_size, style, preferred_aspect_ratio);
2306 self.inline_content_sizes(layout_context, &constraint_space)
2307 .sizes
2308 };
2309
2310 let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
2311 Direction::Inline,
2312 Size::FitContent,
2313 Au::zero,
2314 Some(available_inline_size),
2315 get_content_size,
2316 is_table,
2317 );
2318
2319 let containing_block_for_children = ContainingBlock {
2320 size: ContainingBlockSize {
2321 inline: inline_size,
2322 block: tentative_block_size,
2323 },
2324 style,
2325 };
2326 assert_eq!(
2327 container_writing_mode.is_horizontal(),
2328 style.writing_mode.is_horizontal(),
2329 "Mixed horizontal and vertical writing modes are not supported yet"
2330 );
2331
2332 let lazy_block_size = LazySize::new(
2333 &content_box_sizes_and_pbm.content_box_sizes.block,
2334 Direction::Block,
2335 Size::FitContent,
2336 Au::zero,
2337 available_block_size,
2338 is_table,
2339 );
2340
2341 let CacheableLayoutResult {
2342 content_inline_size_for_table,
2343 content_block_size,
2344 fragments,
2345 baselines,
2346 specific_layout_info,
2347 ..
2348 } = self.layout(
2349 layout_context,
2350 child_positioning_context,
2351 &containing_block_for_children,
2352 containing_block,
2353 preferred_aspect_ratio,
2354 &lazy_block_size,
2355 );
2356
2357 let content_size = LogicalVec2 {
2358 inline: content_inline_size_for_table.unwrap_or(inline_size),
2359 block: lazy_block_size.resolve(|| content_block_size),
2360 }
2361 .to_physical_size(container_writing_mode);
2362 let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
2363
2364 let mut base_fragment_info = self.base_fragment_info();
2365 if content_box_sizes_and_pbm.depends_on_block_constraints {
2366 base_fragment_info.flags.insert(
2367 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2368 );
2369 }
2370
2371 let fragment = BoxFragment::new(
2375 base_fragment_info,
2376 style.clone(),
2377 fragments,
2378 content_rect,
2379 pbm.padding.to_physical(container_writing_mode),
2380 pbm.border.to_physical(container_writing_mode),
2381 margin.to_physical(container_writing_mode),
2382 specific_layout_info,
2383 );
2384
2385 IndependentFloatOrAtomicLayoutResult {
2386 fragment,
2387 baselines,
2388 pbm_sums,
2389 }
2390 }
2391}