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::flow::float::{
27 Clear, ContainingBlockPositionInfo, FloatBox, FloatSide, PlacementAmongFloats,
28 SequentialLayoutState,
29};
30use crate::formatting_contexts::{Baselines, IndependentFormattingContext};
31use crate::fragment_tree::{
32 BaseFragmentInfo, BlockLevelLayoutInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin,
33 Fragment, FragmentFlags,
34};
35use crate::geom::{
36 AuOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
37 PhysicalSides, ToLogical, ToLogicalWithContainingBlock,
38};
39use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
40use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
41use crate::sizing::{
42 self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, LazySize, Size,
43 SizeConstraint, Sizes,
44};
45use crate::style_ext::{AspectRatio, ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin};
46use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock};
47
48mod construct;
49pub mod float;
50pub mod inline;
51mod root;
52
53pub(crate) use construct::BlockContainerBuilder;
54pub(crate) use root::BoxTree;
55
56#[derive(Debug, MallocSizeOf)]
57pub(crate) struct BlockFormattingContext {
58 pub contents: BlockContainer,
59 pub contains_floats: bool,
60}
61
62#[derive(Debug, MallocSizeOf)]
63pub(crate) enum BlockContainer {
64 BlockLevelBoxes(Vec<ArcRefCell<BlockLevelBox>>),
65 InlineFormattingContext(InlineFormattingContext),
66}
67
68impl BlockContainer {
69 fn contains_floats(&self) -> bool {
70 match self {
71 BlockContainer::BlockLevelBoxes(boxes) => boxes
72 .iter()
73 .any(|block_level_box| block_level_box.borrow().contains_floats()),
74 BlockContainer::InlineFormattingContext(context) => context.contains_floats,
75 }
76 }
77
78 pub(crate) fn repair_style(
79 &mut self,
80 node: &ServoThreadSafeLayoutNode,
81 new_style: &Arc<ComputedValues>,
82 ) {
83 match self {
84 BlockContainer::BlockLevelBoxes(..) => {},
85 BlockContainer::InlineFormattingContext(inline_formatting_context) => {
86 inline_formatting_context.repair_style(node, new_style)
87 },
88 }
89 }
90}
91
92#[derive(Debug, MallocSizeOf)]
93pub(crate) enum BlockLevelBox {
94 Independent(IndependentFormattingContext),
95 OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
96 OutOfFlowFloatBox(FloatBox),
97 OutsideMarker(OutsideMarker),
98 SameFormattingContextBlock {
99 base: LayoutBoxBase,
100 contents: BlockContainer,
101 contains_floats: bool,
102 },
103}
104
105impl BlockLevelBox {
106 pub(crate) fn repair_style(
107 &mut self,
108 context: &SharedStyleContext,
109 node: &ServoThreadSafeLayoutNode,
110 new_style: &Arc<ComputedValues>,
111 ) {
112 self.with_base_mut(|base| {
113 base.repair_style(new_style);
114 });
115
116 match self {
117 BlockLevelBox::Independent(independent_formatting_context) => {
118 independent_formatting_context.repair_style(context, node, new_style)
119 },
120 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
121 .borrow_mut()
122 .context
123 .repair_style(context, node, new_style),
124 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
125 float_box.contents.repair_style(context, node, new_style)
126 },
127 BlockLevelBox::OutsideMarker(outside_marker) => {
128 outside_marker.repair_style(context, node, new_style)
129 },
130 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
131 base.repair_style(new_style);
132 contents.repair_style(node, new_style);
133 },
134 }
135 }
136
137 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
138 match self {
139 BlockLevelBox::Independent(independent_formatting_context) => {
140 callback(&independent_formatting_context.base)
141 },
142 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
143 callback(&positioned_box.borrow().context.base)
144 },
145 BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&float_box.contents.base),
146 BlockLevelBox::OutsideMarker(outside_marker) => callback(&outside_marker.base),
147 BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base),
148 }
149 }
150
151 pub(crate) fn with_base_mut<T>(&mut self, callback: impl FnOnce(&mut LayoutBoxBase) -> T) -> T {
152 match self {
153 BlockLevelBox::Independent(independent_formatting_context) => {
154 callback(&mut independent_formatting_context.base)
155 },
156 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
157 callback(&mut positioned_box.borrow_mut().context.base)
158 },
159 BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&mut float_box.contents.base),
160 BlockLevelBox::OutsideMarker(outside_marker) => callback(&mut outside_marker.base),
161 BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base),
162 }
163 }
164
165 fn contains_floats(&self) -> bool {
166 match self {
167 BlockLevelBox::SameFormattingContextBlock {
168 contains_floats, ..
169 } => *contains_floats,
170 BlockLevelBox::OutOfFlowFloatBox { .. } => true,
171 _ => false,
172 }
173 }
174
175 fn find_block_margin_collapsing_with_parent(
176 &self,
177 layout_context: &LayoutContext,
178 collected_margin: &mut CollapsedMargin,
179 containing_block: &ContainingBlock,
180 ) -> bool {
181 let layout_style = match self {
182 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
183 contents.layout_style(base)
184 },
185 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
186 BlockLevelBox::OutOfFlowFloatBox(_) => return true,
187 BlockLevelBox::OutsideMarker(_) => return false,
188 BlockLevelBox::Independent(context) => {
189 context.layout_style()
192 },
193 };
194
195 let style = layout_style.style();
197 if style.get_box().clear != StyleClear::None {
198 return false;
199 }
200
201 let ContentBoxSizesAndPBM {
202 content_box_sizes,
203 pbm,
204 ..
205 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
206 let margin = pbm.margin.auto_is(Au::zero);
207 collected_margin.adjoin_assign(&CollapsedMargin::new(margin.block_start));
208
209 let child_boxes = match self {
210 BlockLevelBox::SameFormattingContextBlock { contents, .. } => match contents {
211 BlockContainer::BlockLevelBoxes(boxes) => boxes,
212 BlockContainer::InlineFormattingContext(_) => return false,
213 },
214 _ => return false,
215 };
216
217 if !pbm.padding.block_start.is_zero() || !pbm.border.block_start.is_zero() {
218 return false;
219 }
220
221 let available_inline_size =
222 containing_block.size.inline - pbm.padding_border_sums.inline - margin.inline_sum();
223 let available_block_size = containing_block.size.block.to_definite().map(|block_size| {
224 Au::zero().max(block_size - pbm.padding_border_sums.block - margin.block_sum())
225 });
226
227 let tentative_block_size = content_box_sizes.block.resolve_extrinsic(
228 Size::FitContent,
229 Au::zero(),
230 available_block_size,
231 );
232
233 let get_inline_content_sizes = || {
234 let constraint_space = ConstraintSpace::new(
235 tentative_block_size,
236 style,
237 None, );
239 self.inline_content_sizes(layout_context, &constraint_space)
240 .sizes
241 };
242 let inline_size = content_box_sizes.inline.resolve(
243 Direction::Inline,
244 Size::Stretch,
245 Au::zero,
246 Some(available_inline_size),
247 get_inline_content_sizes,
248 false, );
250
251 let containing_block_for_children = ContainingBlock {
252 size: ContainingBlockSize {
253 inline: inline_size,
254 block: tentative_block_size,
255 },
256 style,
257 };
258
259 if !Self::find_block_margin_collapsing_with_parent_from_slice(
260 layout_context,
261 child_boxes,
262 collected_margin,
263 &containing_block_for_children,
264 ) {
265 return false;
266 }
267
268 if !tentative_block_size.definite_or_min().is_zero() ||
269 !pbm.padding_border_sums.block.is_zero()
270 {
271 return false;
272 }
273
274 collected_margin.adjoin_assign(&CollapsedMargin::new(margin.block_end));
275
276 true
277 }
278
279 fn find_block_margin_collapsing_with_parent_from_slice(
280 layout_context: &LayoutContext,
281 boxes: &[ArcRefCell<BlockLevelBox>],
282 margin: &mut CollapsedMargin,
283 containing_block: &ContainingBlock,
284 ) -> bool {
285 boxes.iter().all(|block_level_box| {
286 block_level_box
287 .borrow()
288 .find_block_margin_collapsing_with_parent(layout_context, margin, containing_block)
289 })
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 base: LayoutBoxBase,
302 pub block_formatting_context: BlockFormattingContext,
303}
304
305impl OutsideMarker {
306 fn inline_content_sizes(
307 &self,
308 layout_context: &LayoutContext,
309 constraint_space: &ConstraintSpace,
310 ) -> InlineContentSizesResult {
311 self.base.inline_content_sizes(
312 layout_context,
313 constraint_space,
314 &self.block_formatting_context.contents,
315 )
316 }
317
318 fn layout(
319 &self,
320 layout_context: &LayoutContext<'_>,
321 containing_block: &ContainingBlock<'_>,
322 positioning_context: &mut PositioningContext,
323 ) -> Fragment {
324 let constraint_space = ConstraintSpace::new_for_style_and_ratio(
325 &self.base.style,
326 None, );
328 let content_sizes = self.inline_content_sizes(layout_context, &constraint_space);
329 let containing_block_for_children = ContainingBlock {
330 size: ContainingBlockSize {
331 inline: content_sizes.sizes.max_content,
332 block: SizeConstraint::default(),
333 },
334 style: &self.base.style,
335 };
336
337 let flow_layout = self.block_formatting_context.layout(
338 layout_context,
339 positioning_context,
340 &containing_block_for_children,
341 );
342
343 let max_inline_size =
344 flow_layout
345 .fragments
346 .iter()
347 .fold(Au::zero(), |current_max, fragment| {
348 current_max.max(
349 match fragment {
350 Fragment::Text(text) => text.borrow().rect,
351 Fragment::Image(image) => image.borrow().rect,
352 Fragment::Positioning(positioning) => positioning.borrow().rect,
353 Fragment::Box(_) |
354 Fragment::Float(_) |
355 Fragment::AbsoluteOrFixedPositioned(_) |
356 Fragment::IFrame(_) => {
357 unreachable!(
358 "Found unexpected fragment type in outside list marker!"
359 );
360 },
361 }
362 .to_logical(&containing_block_for_children)
363 .max_inline_position(),
364 )
365 });
366
367 let pbm_of_list_item =
377 LayoutStyle::Default(&self.list_item_style).padding_border_margin(containing_block);
378 let content_rect = LogicalRect {
379 start_corner: LogicalVec2 {
380 inline: -max_inline_size -
381 (pbm_of_list_item.border.inline_start +
382 pbm_of_list_item.padding.inline_start),
383 block: Zero::zero(),
384 },
385 size: LogicalVec2 {
386 inline: max_inline_size,
387 block: flow_layout.content_block_size,
388 },
389 };
390
391 let mut base_fragment_info = BaseFragmentInfo::anonymous();
392 base_fragment_info.flags |= FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER;
393
394 Fragment::Box(ArcRefCell::new(BoxFragment::new(
395 base_fragment_info,
396 self.base.style.clone(),
397 flow_layout.fragments,
398 content_rect.as_physical(Some(containing_block)),
399 PhysicalSides::zero(),
400 PhysicalSides::zero(),
401 PhysicalSides::zero(),
402 flow_layout.specific_layout_info,
403 )))
404 }
405
406 fn repair_style(
407 &mut self,
408 context: &SharedStyleContext,
409 node: &ServoThreadSafeLayoutNode,
410 new_style: &Arc<ComputedValues>,
411 ) {
412 self.list_item_style = node.style(context);
413 self.base.repair_style(new_style);
414 }
415}
416
417impl BlockFormattingContext {
418 pub(super) fn layout(
419 &self,
420 layout_context: &LayoutContext,
421 positioning_context: &mut PositioningContext,
422 containing_block: &ContainingBlock,
423 ) -> CacheableLayoutResult {
424 let mut sequential_layout_state = if self.contains_floats || !layout_context.use_rayon {
425 Some(SequentialLayoutState::new(containing_block.size.inline))
426 } else {
427 None
428 };
429
430 let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
434
435 let flow_layout = self.contents.layout(
436 layout_context,
437 positioning_context,
438 containing_block,
439 sequential_layout_state.as_mut(),
440 CollapsibleWithParentStartMargin(false),
441 ignore_block_margins_for_stretch,
442 );
443 debug_assert!(
444 !flow_layout
445 .collapsible_margins_in_children
446 .collapsed_through
447 );
448
449 let clearance = sequential_layout_state.and_then(|sequential_layout_state| {
453 sequential_layout_state.calculate_clearance(Clear::Both, &CollapsedMargin::zero())
454 });
455
456 CacheableLayoutResult {
457 fragments: flow_layout.fragments,
458 content_block_size: flow_layout.content_block_size +
459 flow_layout.collapsible_margins_in_children.end.solve() +
460 clearance.unwrap_or_default(),
461 content_inline_size_for_table: None,
462 baselines: flow_layout.baselines,
463 depends_on_block_constraints: flow_layout.depends_on_block_constraints,
464 specific_layout_info: None,
465 collapsible_margins_in_children: CollapsedBlockMargins::zero(),
466 }
467 }
468
469 #[inline]
470 pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
471 LayoutStyle::Default(&base.style)
472 }
473
474 pub(crate) fn repair_style(
475 &mut self,
476 node: &ServoThreadSafeLayoutNode,
477 new_style: &Arc<ComputedValues>,
478 ) {
479 self.contents.repair_style(node, new_style);
480 }
481}
482
483fn compute_inline_content_sizes_for_block_level_boxes(
489 boxes: &[ArcRefCell<BlockLevelBox>],
490 layout_context: &LayoutContext,
491 containing_block: &IndefiniteContainingBlock,
492) -> InlineContentSizesResult {
493 let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| {
494 match &*box_.borrow() {
495 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
496 BlockLevelBox::OutsideMarker { .. } => None,
497 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
498 let inline_content_sizes_result = float_box.contents.outer_inline_content_sizes(
499 layout_context,
500 containing_block,
501 &LogicalVec2::zero(),
502 false, );
504 let style = &float_box.contents.style();
505 let container_writing_mode = containing_block.style.writing_mode;
506 Some((
507 inline_content_sizes_result,
508 FloatSide::from_style_and_container_writing_mode(style, container_writing_mode),
509 Clear::from_style_and_container_writing_mode(style, container_writing_mode),
510 ))
511 },
512 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
513 let inline_content_sizes_result = sizing::outer_inline(
514 &contents.layout_style(base),
515 containing_block,
516 &LogicalVec2::zero(),
517 false, false, !matches!(base.style.pseudo(), Some(PseudoElement::ServoAnonymousBox)),
520 |_| None, |constraint_space| {
522 base.inline_content_sizes(layout_context, constraint_space, contents)
523 },
524 |_aspect_ratio| None,
525 );
526 Some((inline_content_sizes_result, None, Clear::Both))
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 start_floats: ContentSizes,
561 end_floats: ContentSizes,
564 }
565
566 impl AccumulatedData {
567 fn max_size_including_uncleared_floats(&self) -> ContentSizes {
568 self.max_size.max(self.start_floats.union(&self.end_floats))
569 }
570 fn clear_floats(&mut self, clear: Clear) {
571 match clear {
572 Clear::InlineStart => {
573 self.max_size = self.max_size_including_uncleared_floats();
574 self.start_floats = ContentSizes::zero();
575 },
576 Clear::InlineEnd => {
577 self.max_size = self.max_size_including_uncleared_floats();
578 self.end_floats = ContentSizes::zero();
579 },
580 Clear::Both => {
581 self.max_size = self.max_size_including_uncleared_floats();
582 self.start_floats = ContentSizes::zero();
583 self.end_floats = ContentSizes::zero();
584 },
585 Clear::None => {},
586 };
587 }
588 }
589
590 let accumulate =
591 |mut data: AccumulatedData,
592 (inline_content_sizes_result, float, clear): (InlineContentSizesResult, _, _)| {
593 let size = inline_content_sizes_result.sizes.max(ContentSizes::zero());
594 let depends_on_block_constraints =
595 inline_content_sizes_result.depends_on_block_constraints;
596 data.depends_on_block_constraints |= depends_on_block_constraints;
597 data.clear_floats(clear);
598 match float {
599 Some(FloatSide::InlineStart) => data.start_floats = data.start_floats.union(&size),
600 Some(FloatSide::InlineEnd) => data.end_floats = data.end_floats.union(&size),
601 None => {
602 data.max_size = data
603 .max_size
604 .max(data.start_floats.union(&data.end_floats).union(&size));
605 data.start_floats = ContentSizes::zero();
606 data.end_floats = ContentSizes::zero();
607 },
608 }
609 data
610 };
611 let data = if layout_context.use_rayon {
612 boxes
613 .par_iter()
614 .filter_map(get_box_info)
615 .collect::<Vec<_>>()
616 .into_iter()
617 .fold(AccumulatedData::default(), accumulate)
618 } else {
619 boxes
620 .iter()
621 .filter_map(get_box_info)
622 .fold(AccumulatedData::default(), accumulate)
623 };
624 InlineContentSizesResult {
625 depends_on_block_constraints: data.depends_on_block_constraints,
626 sizes: data.max_size_including_uncleared_floats(),
627 }
628}
629
630impl BlockContainer {
631 fn layout(
632 &self,
633 layout_context: &LayoutContext,
634 positioning_context: &mut PositioningContext,
635 containing_block: &ContainingBlock,
636 sequential_layout_state: Option<&mut SequentialLayoutState>,
637 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
638 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
639 ) -> CacheableLayoutResult {
640 match self {
641 BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
642 layout_context,
643 positioning_context,
644 child_boxes,
645 containing_block,
646 sequential_layout_state,
647 collapsible_with_parent_start_margin,
648 ignore_block_margins_for_stretch,
649 ),
650 BlockContainer::InlineFormattingContext(ifc) => ifc.layout(
651 layout_context,
652 positioning_context,
653 containing_block,
654 sequential_layout_state,
655 collapsible_with_parent_start_margin,
656 ),
657 }
658 }
659
660 #[inline]
661 pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
662 LayoutStyle::Default(&base.style)
663 }
664}
665
666impl ComputeInlineContentSizes for BlockContainer {
667 fn compute_inline_content_sizes(
668 &self,
669 layout_context: &LayoutContext,
670 constraint_space: &ConstraintSpace,
671 ) -> InlineContentSizesResult {
672 match &self {
673 Self::BlockLevelBoxes(boxes) => compute_inline_content_sizes_for_block_level_boxes(
674 boxes,
675 layout_context,
676 &constraint_space.into(),
677 ),
678 Self::InlineFormattingContext(context) => {
679 context.compute_inline_content_sizes(layout_context, constraint_space)
680 },
681 }
682 }
683}
684
685fn layout_block_level_children(
686 layout_context: &LayoutContext,
687 positioning_context: &mut PositioningContext,
688 child_boxes: &[ArcRefCell<BlockLevelBox>],
689 containing_block: &ContainingBlock,
690 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
691 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
692 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
693) -> CacheableLayoutResult {
694 let mut placement_state =
695 PlacementState::new(collapsible_with_parent_start_margin, containing_block);
696
697 let fragments = match sequential_layout_state {
698 Some(ref mut sequential_layout_state) => layout_block_level_children_sequentially(
699 layout_context,
700 positioning_context,
701 child_boxes,
702 containing_block,
703 sequential_layout_state,
704 &mut placement_state,
705 ignore_block_margins_for_stretch,
706 ),
707 None => layout_block_level_children_in_parallel(
708 layout_context,
709 positioning_context,
710 child_boxes,
711 containing_block,
712 &mut placement_state,
713 ignore_block_margins_for_stretch,
714 ),
715 };
716
717 let depends_on_block_constraints = fragments.iter().any(|fragment| {
718 fragment.base().is_some_and(|base| {
719 base.flags.contains(
720 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
721 )
722 })
723 });
724
725 let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish();
726 CacheableLayoutResult {
727 fragments,
728 content_block_size,
729 collapsible_margins_in_children,
730 baselines,
731 depends_on_block_constraints,
732 content_inline_size_for_table: None,
733 specific_layout_info: None,
734 }
735}
736
737fn layout_block_level_children_in_parallel(
738 layout_context: &LayoutContext,
739 positioning_context: &mut PositioningContext,
740 child_boxes: &[ArcRefCell<BlockLevelBox>],
741 containing_block: &ContainingBlock,
742 placement_state: &mut PlacementState,
743 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
744) -> Vec<Fragment> {
745 let mut layout_results: Vec<(Fragment, PositioningContext)> =
746 Vec::with_capacity(child_boxes.len());
747
748 child_boxes
749 .par_iter()
750 .map(|child_box| {
751 let mut child_positioning_context = PositioningContext::default();
752 let fragment = child_box.borrow().layout(
753 layout_context,
754 &mut child_positioning_context,
755 containing_block,
756 None,
757 None,
758 ignore_block_margins_for_stretch,
759 );
760 (fragment, child_positioning_context)
761 })
762 .collect_into_vec(&mut layout_results);
763
764 layout_results
765 .into_iter()
766 .map(|(mut fragment, mut child_positioning_context)| {
767 placement_state.place_fragment_and_update_baseline(&mut fragment, None);
768 child_positioning_context.adjust_static_position_of_hoisted_fragments(
769 &fragment,
770 PositioningContextLength::zero(),
771 );
772 positioning_context.append(child_positioning_context);
773 fragment
774 })
775 .collect()
776}
777
778fn layout_block_level_children_sequentially(
779 layout_context: &LayoutContext,
780 positioning_context: &mut PositioningContext,
781 child_boxes: &[ArcRefCell<BlockLevelBox>],
782 containing_block: &ContainingBlock,
783 sequential_layout_state: &mut SequentialLayoutState,
784 placement_state: &mut PlacementState,
785 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
786) -> Vec<Fragment> {
787 child_boxes
791 .iter()
792 .map(|child_box| {
793 let positioning_context_length_before_layout = positioning_context.len();
794 let mut fragment = child_box.borrow().layout(
795 layout_context,
796 positioning_context,
797 containing_block,
798 Some(&mut *sequential_layout_state),
799 Some(CollapsibleWithParentStartMargin(
800 placement_state.next_in_flow_margin_collapses_with_parent_start_margin,
801 )),
802 ignore_block_margins_for_stretch,
803 );
804
805 placement_state
806 .place_fragment_and_update_baseline(&mut fragment, Some(sequential_layout_state));
807 positioning_context.adjust_static_position_of_hoisted_fragments(
808 &fragment,
809 positioning_context_length_before_layout,
810 );
811
812 fragment
813 })
814 .collect()
815}
816
817impl BlockLevelBox {
818 fn layout(
819 &self,
820 layout_context: &LayoutContext,
821 positioning_context: &mut PositioningContext,
822 containing_block: &ContainingBlock,
823 sequential_layout_state: Option<&mut SequentialLayoutState>,
824 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
825 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
826 ) -> Fragment {
827 let fragment = match self {
828 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => Fragment::Box(
829 ArcRefCell::new(positioning_context.layout_maybe_position_relative_fragment(
830 layout_context,
831 containing_block,
832 base,
833 |positioning_context| {
834 layout_in_flow_non_replaced_block_level_same_formatting_context(
835 layout_context,
836 positioning_context,
837 containing_block,
838 base,
839 contents,
840 sequential_layout_state,
841 collapsible_with_parent_start_margin,
842 ignore_block_margins_for_stretch,
843 )
844 },
845 )),
846 ),
847 BlockLevelBox::Independent(independent) => Fragment::Box(ArcRefCell::new(
848 positioning_context.layout_maybe_position_relative_fragment(
849 layout_context,
850 containing_block,
851 &independent.base,
852 |positioning_context| {
853 independent.layout_in_flow_block_level(
854 layout_context,
855 positioning_context,
856 containing_block,
857 sequential_layout_state,
858 ignore_block_margins_for_stretch,
859 )
860 },
861 ),
862 )),
863 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
864 let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
868 box_.clone(),
869 PhysicalRect::zero(),
873 LogicalVec2 {
874 inline: AlignFlags::START,
875 block: AlignFlags::START,
876 },
877 containing_block.style.writing_mode,
878 );
879 let hoisted_fragment = hoisted_box.fragment.clone();
880 positioning_context.push(hoisted_box);
881 Fragment::AbsoluteOrFixedPositioned(hoisted_fragment)
882 },
883 BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(ArcRefCell::new(
884 float_box.layout(layout_context, positioning_context, containing_block),
885 )),
886 BlockLevelBox::OutsideMarker(outside_marker) => {
887 outside_marker.layout(layout_context, containing_block, positioning_context)
888 },
889 };
890
891 self.with_base(|base| base.set_fragment(fragment.clone()));
892
893 fragment
894 }
895
896 fn inline_content_sizes(
897 &self,
898 layout_context: &LayoutContext,
899 constraint_space: &ConstraintSpace,
900 ) -> InlineContentSizesResult {
901 let independent_formatting_context = match self {
902 BlockLevelBox::Independent(independent) => independent,
903 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => &box_.borrow().context,
904 BlockLevelBox::OutOfFlowFloatBox(float_box) => &float_box.contents,
905 BlockLevelBox::OutsideMarker(outside_marker) => {
906 return outside_marker.inline_content_sizes(layout_context, constraint_space);
907 },
908 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
909 return base.inline_content_sizes(layout_context, constraint_space, contents);
910 },
911 };
912 independent_formatting_context.inline_content_sizes(layout_context, constraint_space)
913 }
914}
915
916#[allow(clippy::too_many_arguments)]
922fn layout_in_flow_non_replaced_block_level_same_formatting_context(
923 layout_context: &LayoutContext,
924 positioning_context: &mut PositioningContext,
925 containing_block: &ContainingBlock,
926 base: &LayoutBoxBase,
927 contents: &BlockContainer,
928 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
929 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
930 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
931) -> BoxFragment {
932 let style = &base.style;
933 let layout_style = contents.layout_style(base);
934 let containing_block_writing_mode = containing_block.style.writing_mode;
935 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
936 base.inline_content_sizes(layout_context, constraint_space, contents)
937 .sizes
938 };
939 let ContainingBlockPaddingAndBorder {
940 containing_block: containing_block_for_children,
941 pbm,
942 block_sizes,
943 depends_on_block_constraints,
944 available_block_size,
945 justify_self,
946 ..
947 } = solve_containing_block_padding_and_border_for_in_flow_box(
948 containing_block,
949 &layout_style,
950 get_inline_content_sizes,
951 ignore_block_margins_for_stretch,
952 None,
953 );
954 let ResolvedMargins {
955 margin,
956 effective_margin_inline_start,
957 } = solve_margins(
958 containing_block,
959 &pbm,
960 containing_block_for_children.size.inline,
961 justify_self,
962 );
963
964 let start_margin_can_collapse_with_children =
965 pbm.padding.block_start.is_zero() && pbm.border.block_start.is_zero();
966
967 let mut clearance = None;
968 let parent_containing_block_position_info;
969 match sequential_layout_state {
970 None => parent_containing_block_position_info = None,
971 Some(ref mut sequential_layout_state) => {
972 let clear =
973 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode);
974 let mut block_start_margin = CollapsedMargin::new(margin.block_start);
975
976 let collapsible_with_parent_start_margin = collapsible_with_parent_start_margin.expect(
988 "We should know whether we are collapsing the block start margin with the parent \
989 when laying out sequentially",
990 ).0 && clear == Clear::None;
991 if !collapsible_with_parent_start_margin && start_margin_can_collapse_with_children {
992 if let BlockContainer::BlockLevelBoxes(child_boxes) = contents {
993 BlockLevelBox::find_block_margin_collapsing_with_parent_from_slice(
994 layout_context,
995 child_boxes,
996 &mut block_start_margin,
997 &containing_block_for_children,
998 );
999 }
1000 }
1001
1002 clearance = sequential_layout_state.calculate_clearance(clear, &block_start_margin);
1004 if clearance.is_some() {
1005 sequential_layout_state.collapse_margins();
1006 }
1007 sequential_layout_state.adjoin_assign(&block_start_margin);
1008 if !start_margin_can_collapse_with_children {
1009 sequential_layout_state.collapse_margins();
1010 }
1011
1012 sequential_layout_state.advance_block_position(
1015 pbm.padding.block_start +
1016 pbm.border.block_start +
1017 clearance.unwrap_or_else(Au::zero),
1018 );
1019
1020 let inline_start = sequential_layout_state
1026 .floats
1027 .containing_block_info
1028 .inline_start +
1029 pbm.padding.inline_start +
1030 pbm.border.inline_start +
1031 effective_margin_inline_start;
1032 let new_cb_offsets = ContainingBlockPositionInfo {
1033 block_start: sequential_layout_state.bfc_relative_block_position,
1034 block_start_margins_not_collapsed: sequential_layout_state.current_margin,
1035 inline_start,
1036 inline_end: inline_start + containing_block_for_children.size.inline,
1037 };
1038 parent_containing_block_position_info = Some(
1039 sequential_layout_state.replace_containing_block_position_info(new_cb_offsets),
1040 );
1041 },
1042 };
1043
1044 let ignore_block_margins_for_stretch = LogicalSides1D::new(
1050 pbm.border.block_start.is_zero() && pbm.padding.block_start.is_zero(),
1051 pbm.border.block_end.is_zero() && pbm.padding.block_end.is_zero(),
1052 );
1053
1054 let flow_layout = contents.layout(
1055 layout_context,
1056 positioning_context,
1057 &containing_block_for_children,
1058 sequential_layout_state.as_deref_mut(),
1059 CollapsibleWithParentStartMargin(start_margin_can_collapse_with_children),
1060 ignore_block_margins_for_stretch,
1061 );
1062 let mut content_block_size = flow_layout.content_block_size;
1063
1064 let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1066 let mut collapsible_margins_in_children = flow_layout.collapsible_margins_in_children;
1067 if start_margin_can_collapse_with_children {
1068 block_margins_collapsed_with_children
1069 .start
1070 .adjoin_assign(&collapsible_margins_in_children.start);
1071 if collapsible_margins_in_children.collapsed_through {
1072 block_margins_collapsed_with_children
1073 .start
1074 .adjoin_assign(&std::mem::replace(
1075 &mut collapsible_margins_in_children.end,
1076 CollapsedMargin::zero(),
1077 ));
1078 }
1079 }
1080
1081 let tentative_block_size = &containing_block_for_children.size.block;
1082 let collapsed_through = collapsible_margins_in_children.collapsed_through &&
1083 pbm.padding_border_sums.block.is_zero() &&
1084 tentative_block_size.definite_or_min().is_zero();
1085 block_margins_collapsed_with_children.collapsed_through = collapsed_through;
1086
1087 let end_margin_can_collapse_with_children =
1088 pbm.padding.block_end.is_zero() && pbm.border.block_end.is_zero();
1089 if !end_margin_can_collapse_with_children {
1090 content_block_size += collapsible_margins_in_children.end.solve();
1091 }
1092
1093 let block_size = block_sizes.resolve(
1094 Direction::Block,
1095 Size::FitContent,
1096 Au::zero,
1097 available_block_size,
1098 || content_block_size.into(),
1099 false, );
1101
1102 let end_margin_can_collapse_with_children = end_margin_can_collapse_with_children &&
1117 block_size == content_block_size &&
1118 (collapsed_through || !tentative_block_size.is_definite());
1119 if end_margin_can_collapse_with_children {
1120 block_margins_collapsed_with_children
1121 .end
1122 .adjoin_assign(&collapsible_margins_in_children.end);
1123 }
1124
1125 if let Some(ref mut sequential_layout_state) = sequential_layout_state {
1126 sequential_layout_state
1129 .replace_containing_block_position_info(parent_containing_block_position_info.unwrap());
1130
1131 sequential_layout_state.advance_block_position(
1141 block_size - content_block_size + pbm.padding.block_end + pbm.border.block_end,
1142 );
1143
1144 if !end_margin_can_collapse_with_children {
1145 sequential_layout_state.collapse_margins();
1146 }
1147 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1148 }
1149
1150 let content_rect = LogicalRect {
1151 start_corner: LogicalVec2 {
1152 block: (pbm.padding.block_start +
1153 pbm.border.block_start +
1154 clearance.unwrap_or_else(Au::zero)),
1155 inline: pbm.padding.inline_start +
1156 pbm.border.inline_start +
1157 effective_margin_inline_start,
1158 },
1159 size: LogicalVec2 {
1160 block: block_size,
1161 inline: containing_block_for_children.size.inline,
1162 },
1163 };
1164
1165 let mut base_fragment_info = base.base_fragment_info;
1166 if depends_on_block_constraints {
1167 base_fragment_info
1168 .flags
1169 .insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM);
1170 }
1171
1172 BoxFragment::new(
1173 base_fragment_info,
1174 style.clone(),
1175 flow_layout.fragments,
1176 content_rect.as_physical(Some(containing_block)),
1177 pbm.padding.to_physical(containing_block_writing_mode),
1178 pbm.border.to_physical(containing_block_writing_mode),
1179 margin.to_physical(containing_block_writing_mode),
1180 flow_layout.specific_layout_info,
1181 )
1182 .with_baselines(flow_layout.baselines)
1183 .with_block_level_layout_info(block_margins_collapsed_with_children, clearance)
1184}
1185
1186impl IndependentFormattingContext {
1187 pub(crate) fn layout_in_flow_block_level(
1195 &self,
1196 layout_context: &LayoutContext,
1197 positioning_context: &mut PositioningContext,
1198 containing_block: &ContainingBlock,
1199 sequential_layout_state: Option<&mut SequentialLayoutState>,
1200 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1201 ) -> BoxFragment {
1202 if let Some(sequential_layout_state) = sequential_layout_state {
1203 return self.layout_in_flow_block_level_sequentially(
1204 layout_context,
1205 positioning_context,
1206 containing_block,
1207 sequential_layout_state,
1208 ignore_block_margins_for_stretch,
1209 );
1210 }
1211
1212 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
1213 self.inline_content_sizes(layout_context, constraint_space)
1214 .sizes
1215 };
1216 let layout_style = self.layout_style();
1217 let ContainingBlockPaddingAndBorder {
1218 containing_block: containing_block_for_children,
1219 pbm,
1220 block_sizes,
1221 depends_on_block_constraints,
1222 available_block_size,
1223 justify_self,
1224 preferred_aspect_ratio,
1225 } = solve_containing_block_padding_and_border_for_in_flow_box(
1226 containing_block,
1227 &layout_style,
1228 get_inline_content_sizes,
1229 ignore_block_margins_for_stretch,
1230 Some(self),
1231 );
1232
1233 let lazy_block_size = LazySize::new(
1234 &block_sizes,
1235 Direction::Block,
1236 Size::FitContent,
1237 Au::zero,
1238 available_block_size,
1239 layout_style.is_table(),
1240 );
1241
1242 let layout = self.layout(
1243 layout_context,
1244 positioning_context,
1245 &containing_block_for_children,
1246 containing_block,
1247 preferred_aspect_ratio,
1248 &lazy_block_size,
1249 );
1250
1251 let inline_size = layout
1252 .content_inline_size_for_table
1253 .unwrap_or(containing_block_for_children.size.inline);
1254 let block_size = lazy_block_size.resolve(|| layout.content_block_size);
1255
1256 let ResolvedMargins {
1257 margin,
1258 effective_margin_inline_start,
1259 } = solve_margins(containing_block, &pbm, inline_size, justify_self);
1260
1261 let content_rect = LogicalRect {
1262 start_corner: LogicalVec2 {
1263 block: pbm.padding.block_start + pbm.border.block_start,
1264 inline: pbm.padding.inline_start +
1265 pbm.border.inline_start +
1266 effective_margin_inline_start,
1267 },
1268 size: LogicalVec2 {
1269 block: block_size,
1270 inline: inline_size,
1271 },
1272 };
1273
1274 let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1275 let containing_block_writing_mode = containing_block.style.writing_mode;
1276
1277 let mut base_fragment_info = self.base.base_fragment_info;
1278 if depends_on_block_constraints {
1279 base_fragment_info.flags.insert(
1280 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1281 );
1282 }
1283 BoxFragment::new(
1284 base_fragment_info,
1285 self.base.style.clone(),
1286 layout.fragments,
1287 content_rect.as_physical(Some(containing_block)),
1288 pbm.padding.to_physical(containing_block_writing_mode),
1289 pbm.border.to_physical(containing_block_writing_mode),
1290 margin.to_physical(containing_block_writing_mode),
1291 layout.specific_layout_info,
1292 )
1293 .with_baselines(layout.baselines)
1294 .with_block_level_layout_info(block_margins_collapsed_with_children, None)
1295 }
1296
1297 fn layout_in_flow_block_level_sequentially(
1301 &self,
1302 layout_context: &LayoutContext<'_>,
1303 positioning_context: &mut PositioningContext,
1304 containing_block: &ContainingBlock<'_>,
1305 sequential_layout_state: &mut SequentialLayoutState,
1306 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1307 ) -> BoxFragment {
1308 let style = &self.base.style;
1309 let containing_block_writing_mode = containing_block.style.writing_mode;
1310 let ContentBoxSizesAndPBM {
1311 content_box_sizes,
1312 pbm,
1313 depends_on_block_constraints,
1314 ..
1315 } = self
1316 .layout_style()
1317 .content_box_sizes_and_padding_border_margin(&containing_block.into());
1318
1319 let (margin_block_start, margin_block_end) =
1320 solve_block_margins_for_in_flow_block_level(&pbm);
1321 let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
1322
1323 let mut content_size;
1334 let mut layout;
1335 let mut placement_rect;
1336
1337 let clear_position = sequential_layout_state.calculate_clear_position(
1341 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
1342 &collapsed_margin_block_start,
1343 );
1344 let ceiling = clear_position.unwrap_or_else(|| {
1345 sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
1346 });
1347
1348 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1350 let available_block_size = containing_block
1351 .size
1352 .block
1353 .to_definite()
1354 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1355 let is_table = self.is_table();
1356 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
1357 let tentative_block_content_size =
1358 self.tentative_block_content_size(preferred_aspect_ratio);
1359 let (preferred_block_size, min_block_size, max_block_size) =
1360 if let Some(block_content_size) = tentative_block_content_size {
1361 let (preferred, min, max) = content_box_sizes.block.resolve_each(
1362 Size::FitContent,
1363 Au::zero,
1364 available_block_size,
1365 || block_content_size,
1366 is_table,
1367 );
1368 (Some(preferred), min, max)
1369 } else {
1370 content_box_sizes.block.resolve_each_extrinsic(
1371 Size::FitContent,
1372 Au::zero(),
1373 available_block_size,
1374 )
1375 };
1376 let tentative_block_size =
1377 SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
1378
1379 let get_inline_content_sizes = || {
1381 let constraint_space =
1382 ConstraintSpace::new(tentative_block_size, style, preferred_aspect_ratio);
1383 self.inline_content_sizes(layout_context, &constraint_space)
1384 .sizes
1385 };
1386
1387 let justify_self = resolve_justify_self(style, containing_block.style);
1388 let automatic_inline_size = automatic_inline_size(justify_self, Some(self));
1389 let compute_inline_size = |stretch_size| {
1390 content_box_sizes.inline.resolve(
1391 Direction::Inline,
1392 automatic_inline_size,
1393 Au::zero,
1394 Some(stretch_size),
1395 get_inline_content_sizes,
1396 is_table,
1397 )
1398 };
1399
1400 let get_lazy_block_size = || {
1401 LazySize::new(
1402 &content_box_sizes.block,
1403 Direction::Block,
1404 Size::FitContent,
1405 Au::zero,
1406 available_block_size,
1407 is_table,
1408 )
1409 };
1410
1411 let inline_size_with_no_available_space = compute_inline_size(Au::zero());
1420 if inline_size_with_no_available_space == compute_inline_size(MAX_AU) {
1421 let inline_size = inline_size_with_no_available_space;
1425 let lazy_block_size = get_lazy_block_size();
1426 layout = self.layout(
1427 layout_context,
1428 positioning_context,
1429 &ContainingBlock {
1430 size: ContainingBlockSize {
1431 inline: inline_size,
1432 block: tentative_block_size,
1433 },
1434 style,
1435 },
1436 containing_block,
1437 preferred_aspect_ratio,
1438 &lazy_block_size,
1439 );
1440
1441 content_size = LogicalVec2 {
1442 block: lazy_block_size.resolve(|| layout.content_block_size),
1443 inline: layout.content_inline_size_for_table.unwrap_or(inline_size),
1444 };
1445
1446 let mut placement = PlacementAmongFloats::new(
1447 &sequential_layout_state.floats,
1448 ceiling,
1449 content_size + pbm.padding_border_sums,
1450 &pbm,
1451 );
1452 placement_rect = placement.place();
1453 } else {
1454 let minimum_size_of_block = LogicalVec2 {
1460 inline: inline_size_with_no_available_space,
1464 block: match tentative_block_size {
1465 SizeConstraint::Definite(size) if max_block_size.is_some() => size,
1468 _ => min_block_size,
1471 },
1472 } + pbm.padding_border_sums;
1473 let mut placement = PlacementAmongFloats::new(
1474 &sequential_layout_state.floats,
1475 ceiling,
1476 minimum_size_of_block,
1477 &pbm,
1478 );
1479
1480 loop {
1481 placement_rect = placement.place();
1483 let available_inline_size =
1484 placement_rect.size.inline - pbm.padding_border_sums.inline;
1485 let proposed_inline_size = compute_inline_size(available_inline_size);
1486
1487 let positioning_context_length = positioning_context.len();
1491 let lazy_block_size = get_lazy_block_size();
1492 layout = self.layout(
1493 layout_context,
1494 positioning_context,
1495 &ContainingBlock {
1496 size: ContainingBlockSize {
1497 inline: proposed_inline_size,
1498 block: tentative_block_size,
1499 },
1500 style,
1501 },
1502 containing_block,
1503 preferred_aspect_ratio,
1504 &lazy_block_size,
1505 );
1506
1507 let inline_size = if let Some(inline_size) = layout.content_inline_size_for_table {
1508 debug_assert!(inline_size < proposed_inline_size);
1513 inline_size
1514 } else {
1515 proposed_inline_size
1516 };
1517 content_size = LogicalVec2 {
1518 block: lazy_block_size.resolve(|| layout.content_block_size),
1519 inline: inline_size,
1520 };
1521
1522 if placement.try_to_expand_for_auto_block_size(
1526 content_size.block + pbm.padding_border_sums.block,
1527 &placement_rect.size,
1528 ) {
1529 break;
1530 }
1531
1532 positioning_context.truncate(&positioning_context_length);
1536 }
1537 }
1538
1539 let has_clearance = clear_position.is_some() || placement_rect.start_corner.block > ceiling;
1543 let clearance = has_clearance.then(|| {
1544 placement_rect.start_corner.block -
1545 sequential_layout_state
1546 .position_with_zero_clearance(&collapsed_margin_block_start)
1547 });
1548
1549 let ((margin_inline_start, margin_inline_end), effective_margin_inline_start) =
1550 solve_inline_margins_avoiding_floats(
1551 sequential_layout_state,
1552 containing_block,
1553 &pbm,
1554 content_size.inline + pbm.padding_border_sums.inline,
1555 placement_rect,
1556 justify_self,
1557 );
1558
1559 let margin = LogicalSides {
1560 inline_start: margin_inline_start,
1561 inline_end: margin_inline_end,
1562 block_start: margin_block_start,
1563 block_end: margin_block_end,
1564 };
1565
1566 if clearance.is_some() {
1569 sequential_layout_state.collapse_margins();
1570 }
1571 sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
1572
1573 sequential_layout_state.collapse_margins();
1575 sequential_layout_state.advance_block_position(
1576 pbm.padding_border_sums.block + content_size.block + clearance.unwrap_or_else(Au::zero),
1577 );
1578 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1579
1580 let content_rect = LogicalRect {
1581 start_corner: LogicalVec2 {
1582 block: pbm.padding.block_start +
1583 pbm.border.block_start +
1584 clearance.unwrap_or_else(Au::zero),
1585 inline: pbm.padding.inline_start +
1586 pbm.border.inline_start +
1587 effective_margin_inline_start,
1588 },
1589 size: content_size,
1590 };
1591
1592 let mut base_fragment_info = self.base.base_fragment_info;
1593 if depends_on_block_constraints {
1594 base_fragment_info.flags.insert(
1595 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1596 );
1597 }
1598
1599 BoxFragment::new(
1600 base_fragment_info,
1601 style.clone(),
1602 layout.fragments,
1603 content_rect.as_physical(Some(containing_block)),
1604 pbm.padding.to_physical(containing_block_writing_mode),
1605 pbm.border.to_physical(containing_block_writing_mode),
1606 margin.to_physical(containing_block_writing_mode),
1607 layout.specific_layout_info,
1608 )
1609 .with_baselines(layout.baselines)
1610 .with_block_level_layout_info(CollapsedBlockMargins::from_margin(&margin), clearance)
1611 }
1612}
1613
1614struct ContainingBlockPaddingAndBorder<'a> {
1615 containing_block: ContainingBlock<'a>,
1616 pbm: PaddingBorderMargin,
1617 block_sizes: Sizes,
1618 depends_on_block_constraints: bool,
1619 available_block_size: Option<Au>,
1620 justify_self: AlignFlags,
1621 preferred_aspect_ratio: Option<AspectRatio>,
1622}
1623
1624struct ResolvedMargins {
1625 pub margin: LogicalSides<Au>,
1627
1628 pub effective_margin_inline_start: Au,
1635}
1636
1637fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
1643 containing_block: &ContainingBlock<'_>,
1644 layout_style: &'a LayoutStyle,
1645 get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
1646 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1647 context: Option<&IndependentFormattingContext>,
1648) -> ContainingBlockPaddingAndBorder<'a> {
1649 let style = layout_style.style();
1650 if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
1651 let containing_block_for_children = ContainingBlock {
1655 size: ContainingBlockSize {
1656 inline: containing_block.size.inline,
1657 block: containing_block.size.block,
1658 },
1659 style,
1660 };
1661 return ContainingBlockPaddingAndBorder {
1664 containing_block: containing_block_for_children,
1665 pbm: PaddingBorderMargin::zero(),
1666 block_sizes: Sizes::default(),
1667 depends_on_block_constraints: false,
1668 available_block_size: None,
1671 justify_self: AlignFlags::NORMAL,
1674 preferred_aspect_ratio: None,
1675 };
1676 }
1677
1678 let ContentBoxSizesAndPBM {
1679 content_box_sizes,
1680 pbm,
1681 depends_on_block_constraints,
1682 ..
1683 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
1684
1685 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1686 let available_inline_size = Au::zero().max(containing_block.size.inline - pbm_sums.inline);
1687 let available_block_size = containing_block
1688 .size
1689 .block
1690 .to_definite()
1691 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1692
1693 let preferred_aspect_ratio =
1696 context.and_then(|context| context.preferred_aspect_ratio(&pbm.padding_border_sums));
1697 let is_table = layout_style.is_table();
1698
1699 let tentative_block_content_size =
1702 context.and_then(|context| context.tentative_block_content_size(preferred_aspect_ratio));
1703 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
1704 SizeConstraint::Definite(content_box_sizes.block.resolve(
1705 Direction::Block,
1706 Size::FitContent,
1707 Au::zero,
1708 available_block_size,
1709 || block_content_size,
1710 is_table,
1711 ))
1712 } else {
1713 content_box_sizes.block.resolve_extrinsic(
1714 Size::FitContent,
1715 Au::zero(),
1716 available_block_size,
1717 )
1718 };
1719
1720 let get_inline_content_sizes = || {
1723 get_inline_content_sizes(&ConstraintSpace::new(
1724 tentative_block_size,
1725 style,
1726 preferred_aspect_ratio,
1727 ))
1728 };
1729 let justify_self = resolve_justify_self(style, containing_block.style);
1730 let inline_size = content_box_sizes.inline.resolve(
1731 Direction::Inline,
1732 automatic_inline_size(justify_self, context),
1733 Au::zero,
1734 Some(available_inline_size),
1735 get_inline_content_sizes,
1736 is_table,
1737 );
1738
1739 let containing_block_for_children = ContainingBlock {
1740 size: ContainingBlockSize {
1741 inline: inline_size,
1742 block: tentative_block_size,
1743 },
1744 style,
1745 };
1746 assert_eq!(
1748 containing_block.style.writing_mode.is_horizontal(),
1749 containing_block_for_children
1750 .style
1751 .writing_mode
1752 .is_horizontal(),
1753 "Vertical writing modes are not supported yet"
1754 );
1755 ContainingBlockPaddingAndBorder {
1756 containing_block: containing_block_for_children,
1757 pbm,
1758 block_sizes: content_box_sizes.block,
1759 depends_on_block_constraints,
1760 available_block_size,
1761 justify_self,
1762 preferred_aspect_ratio,
1763 }
1764}
1765
1766fn solve_margins(
1771 containing_block: &ContainingBlock<'_>,
1772 pbm: &PaddingBorderMargin,
1773 inline_size: Au,
1774 justify_self: AlignFlags,
1775) -> ResolvedMargins {
1776 let (inline_margins, effective_margin_inline_start) =
1777 solve_inline_margins_for_in_flow_block_level(
1778 containing_block,
1779 pbm,
1780 inline_size,
1781 justify_self,
1782 );
1783 let block_margins = solve_block_margins_for_in_flow_block_level(pbm);
1784 ResolvedMargins {
1785 margin: LogicalSides {
1786 inline_start: inline_margins.0,
1787 inline_end: inline_margins.1,
1788 block_start: block_margins.0,
1789 block_end: block_margins.1,
1790 },
1791 effective_margin_inline_start,
1792 }
1793}
1794
1795fn solve_block_margins_for_in_flow_block_level(pbm: &PaddingBorderMargin) -> (Au, Au) {
1799 (
1800 pbm.margin.block_start.auto_is(Au::zero),
1801 pbm.margin.block_end.auto_is(Au::zero),
1802 )
1803}
1804
1805fn resolve_justify_self(style: &ComputedValues, parent_style: &ComputedValues) -> AlignFlags {
1807 let is_ltr = |style: &ComputedValues| style.writing_mode.line_left_is_inline_start();
1808 let alignment = match style.clone_justify_self().0 {
1809 AlignFlags::AUTO => parent_style.clone_justify_items().computed.0.0,
1810 alignment => alignment,
1811 };
1812 let alignment_value = match alignment.value() {
1813 AlignFlags::LEFT if is_ltr(parent_style) => AlignFlags::START,
1814 AlignFlags::LEFT => AlignFlags::END,
1815 AlignFlags::RIGHT if is_ltr(parent_style) => AlignFlags::END,
1816 AlignFlags::RIGHT => AlignFlags::START,
1817 AlignFlags::SELF_START if is_ltr(parent_style) == is_ltr(style) => AlignFlags::START,
1818 AlignFlags::SELF_START => AlignFlags::END,
1819 AlignFlags::SELF_END if is_ltr(parent_style) == is_ltr(style) => AlignFlags::END,
1820 AlignFlags::SELF_END => AlignFlags::START,
1821 alignment_value => alignment_value,
1822 };
1823 alignment.flags() | alignment_value
1824}
1825
1826#[inline]
1829fn automatic_inline_size<T>(
1830 justify_self: AlignFlags,
1831 context: Option<&IndependentFormattingContext>,
1832) -> Size<T> {
1833 let normal_stretches = || {
1834 !context.is_some_and(|context| {
1835 context
1836 .base
1837 .base_fragment_info
1838 .flags
1839 .intersects(FragmentFlags::IS_REPLACED | FragmentFlags::IS_WIDGET) ||
1840 context.is_table()
1841 })
1842 };
1843 match justify_self {
1844 AlignFlags::STRETCH => Size::Stretch,
1845 AlignFlags::NORMAL if normal_stretches() => Size::Stretch,
1846 _ => Size::FitContent,
1847 }
1848}
1849
1850fn justify_self_alignment(
1857 containing_block: &ContainingBlock,
1858 free_space: Au,
1859 justify_self: AlignFlags,
1860) -> Au {
1861 let mut alignment = justify_self.value();
1862 let is_safe = justify_self.flags() == AlignFlags::SAFE || alignment == AlignFlags::NORMAL;
1863 if is_safe && free_space <= Au::zero() {
1864 alignment = AlignFlags::START
1865 }
1866 match alignment {
1867 AlignFlags::NORMAL => {},
1868 AlignFlags::CENTER => return free_space / 2,
1869 AlignFlags::END => return free_space,
1870 _ => return Au::zero(),
1871 }
1872
1873 let style = containing_block.style;
1875 match style.clone_text_align() {
1876 TextAlignKeyword::MozCenter => free_space / 2,
1877 TextAlignKeyword::MozLeft if !style.writing_mode.line_left_is_inline_start() => free_space,
1878 TextAlignKeyword::MozRight if style.writing_mode.line_left_is_inline_start() => free_space,
1879 _ => Au::zero(),
1880 }
1881}
1882
1883fn solve_inline_margins_for_in_flow_block_level(
1896 containing_block: &ContainingBlock,
1897 pbm: &PaddingBorderMargin,
1898 inline_size: Au,
1899 justify_self: AlignFlags,
1900) -> ((Au, Au), Au) {
1901 let free_space = containing_block.size.inline - pbm.padding_border_sums.inline - inline_size;
1902 let mut justification = Au::zero();
1903 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1904 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1905 let start = Au::zero().max(free_space / 2);
1906 (start, free_space - start)
1907 },
1908 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => {
1909 (Au::zero().max(free_space - end), end)
1910 },
1911 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, free_space - start),
1912 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1913 justification =
1918 justify_self_alignment(containing_block, free_space - start - end, justify_self);
1919 (start, end)
1920 },
1921 };
1922 let effective_margin_inline_start = inline_margins.0 + justification;
1923 (inline_margins, effective_margin_inline_start)
1924}
1925
1926fn solve_inline_margins_avoiding_floats(
1936 sequential_layout_state: &SequentialLayoutState,
1937 containing_block: &ContainingBlock,
1938 pbm: &PaddingBorderMargin,
1939 inline_size: Au,
1940 placement_rect: LogicalRect<Au>,
1941 justify_self: AlignFlags,
1942) -> ((Au, Au), Au) {
1943 let free_space = Au::zero().max(placement_rect.size.inline - inline_size);
1947 let cb_info = &sequential_layout_state.floats.containing_block_info;
1948 let start_adjustment = placement_rect.start_corner.inline - cb_info.inline_start;
1949 let end_adjustment = cb_info.inline_end - placement_rect.max_inline_position();
1950 let mut justification = Au::zero();
1951 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1952 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1953 let half = free_space / 2;
1954 (start_adjustment + half, end_adjustment + free_space - half)
1955 },
1956 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (start_adjustment + free_space, end),
1957 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, end_adjustment + free_space),
1958 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1959 justification = justify_self_alignment(containing_block, free_space, justify_self);
1965 (start, end)
1966 },
1967 };
1968 let effective_margin_inline_start = inline_margins.0.max(start_adjustment) + justification;
1969 (inline_margins, effective_margin_inline_start)
1970}
1971
1972struct PlacementState<'container> {
1977 next_in_flow_margin_collapses_with_parent_start_margin: bool,
1978 last_in_flow_margin_collapses_with_parent_end_margin: bool,
1979 start_margin: CollapsedMargin,
1980 current_margin: CollapsedMargin,
1981 current_block_direction_position: Au,
1982 inflow_baselines: Baselines,
1983 is_inline_block_context: bool,
1984
1985 marker_block_size: Option<Au>,
1990
1991 containing_block: &'container ContainingBlock<'container>,
1994}
1995
1996impl<'container> PlacementState<'container> {
1997 fn new(
1998 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1999 containing_block: &'container ContainingBlock<'container>,
2000 ) -> PlacementState<'container> {
2001 let is_inline_block_context =
2002 containing_block.style.get_box().clone_display() == Display::InlineBlock;
2003 PlacementState {
2004 next_in_flow_margin_collapses_with_parent_start_margin:
2005 collapsible_with_parent_start_margin.0,
2006 last_in_flow_margin_collapses_with_parent_end_margin: true,
2007 start_margin: CollapsedMargin::zero(),
2008 current_margin: CollapsedMargin::zero(),
2009 current_block_direction_position: Au::zero(),
2010 inflow_baselines: Baselines::default(),
2011 is_inline_block_context,
2012 marker_block_size: None,
2013 containing_block,
2014 }
2015 }
2016
2017 fn place_fragment_and_update_baseline(
2018 &mut self,
2019 fragment: &mut Fragment,
2020 sequential_layout_state: Option<&mut SequentialLayoutState>,
2021 ) {
2022 self.place_fragment(fragment, sequential_layout_state);
2023
2024 let box_fragment = match fragment {
2025 Fragment::Box(box_fragment) => box_fragment,
2026 _ => return,
2027 };
2028 let box_fragment = box_fragment.borrow();
2029
2030 if self.is_inline_block_context && box_fragment.is_table_wrapper() {
2035 return;
2036 }
2037
2038 let box_block_offset = box_fragment
2039 .content_rect
2040 .origin
2041 .to_logical(self.containing_block)
2042 .block;
2043 let box_fragment_baselines =
2044 box_fragment.baselines(self.containing_block.style.writing_mode);
2045 if let (None, Some(first)) = (self.inflow_baselines.first, box_fragment_baselines.first) {
2046 self.inflow_baselines.first = Some(first + box_block_offset);
2047 }
2048 if let Some(last) = box_fragment_baselines.last {
2049 self.inflow_baselines.last = Some(last + box_block_offset);
2050 }
2051 }
2052
2053 fn place_fragment(
2056 &mut self,
2057 fragment: &mut Fragment,
2058 sequential_layout_state: Option<&mut SequentialLayoutState>,
2059 ) {
2060 match fragment {
2061 Fragment::Box(fragment) => {
2062 let fragment = &mut *fragment.borrow_mut();
2071 let is_outside_marker = fragment
2072 .base
2073 .flags
2074 .contains(FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER);
2075 if is_outside_marker {
2076 assert!(self.marker_block_size.is_none());
2077 self.marker_block_size = Some(
2078 fragment
2079 .content_rect
2080 .size
2081 .to_logical(self.containing_block.style.writing_mode)
2082 .block,
2083 );
2084 return;
2085 }
2086
2087 let BlockLevelLayoutInfo {
2088 clearance,
2089 block_margins_collapsed_with_children: fragment_block_margins,
2090 } = &**fragment
2091 .block_level_layout_info
2092 .as_ref()
2093 .expect("A block-level fragment should have a BlockLevelLayoutInfo.");
2094 let mut fragment_block_size = fragment
2095 .border_rect()
2096 .size
2097 .to_logical(self.containing_block.style.writing_mode)
2098 .block;
2099
2100 if let Some(clearance) = *clearance {
2106 fragment_block_size += clearance;
2107 self.current_block_direction_position += self.current_margin.solve();
2112 self.current_margin = CollapsedMargin::zero();
2113 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2114 if fragment_block_margins.collapsed_through {
2115 self.last_in_flow_margin_collapses_with_parent_end_margin = false;
2116 }
2117 } else if !fragment_block_margins.collapsed_through {
2118 self.last_in_flow_margin_collapses_with_parent_end_margin = true;
2119 }
2120
2121 if self.next_in_flow_margin_collapses_with_parent_start_margin {
2122 debug_assert!(self.current_margin.solve().is_zero());
2123 self.start_margin
2124 .adjoin_assign(&fragment_block_margins.start);
2125 if fragment_block_margins.collapsed_through {
2126 self.start_margin.adjoin_assign(&fragment_block_margins.end);
2127 return;
2128 }
2129 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2130 } else {
2131 self.current_margin
2132 .adjoin_assign(&fragment_block_margins.start);
2133 }
2134
2135 fragment.content_rect.origin += LogicalVec2 {
2136 inline: Au::zero(),
2137 block: self.current_margin.solve() + self.current_block_direction_position,
2138 }
2139 .to_physical_size(self.containing_block.style.writing_mode);
2140
2141 if fragment_block_margins.collapsed_through {
2142 self.current_block_direction_position += fragment_block_size;
2145 self.current_margin
2146 .adjoin_assign(&fragment_block_margins.end);
2147 } else {
2148 self.current_block_direction_position +=
2149 self.current_margin.solve() + fragment_block_size;
2150 self.current_margin = fragment_block_margins.end;
2151 }
2152 },
2153 Fragment::AbsoluteOrFixedPositioned(fragment) => {
2154 fragment.borrow_mut().original_static_position_rect = LogicalRect {
2157 start_corner: LogicalVec2 {
2158 block: (self.current_margin.solve() +
2159 self.current_block_direction_position),
2160 inline: Au::zero(),
2161 },
2162 size: LogicalVec2::zero(),
2163 }
2164 .as_physical(Some(self.containing_block));
2165 },
2166 Fragment::Float(box_fragment) => {
2167 let sequential_layout_state = sequential_layout_state
2168 .expect("Found float fragment without SequentialLayoutState");
2169 let block_offset_from_containing_block_top =
2170 self.current_block_direction_position + self.current_margin.solve();
2171 let box_fragment = &mut *box_fragment.borrow_mut();
2172 sequential_layout_state.place_float_fragment(
2173 box_fragment,
2174 self.containing_block,
2175 self.start_margin,
2176 block_offset_from_containing_block_top,
2177 );
2178 },
2179 Fragment::Positioning(_) => {},
2180 _ => unreachable!(),
2181 }
2182 }
2183
2184 fn finish(mut self) -> (Au, CollapsedBlockMargins, Baselines) {
2185 if !self.last_in_flow_margin_collapses_with_parent_end_margin {
2186 self.current_block_direction_position += self.current_margin.solve();
2187 self.current_margin = CollapsedMargin::zero();
2188 }
2189 let (total_block_size, collapsed_through) = match self.marker_block_size {
2190 Some(marker_block_size) => (
2191 self.current_block_direction_position.max(marker_block_size),
2192 false,
2195 ),
2196 None => (
2197 self.current_block_direction_position,
2198 self.next_in_flow_margin_collapses_with_parent_start_margin,
2199 ),
2200 };
2201
2202 (
2203 total_block_size,
2204 CollapsedBlockMargins {
2205 collapsed_through,
2206 start: self.start_margin,
2207 end: self.current_margin,
2208 },
2209 self.inflow_baselines,
2210 )
2211 }
2212}
2213
2214pub(crate) struct IndependentFloatOrAtomicLayoutResult {
2215 pub fragment: BoxFragment,
2216 pub baselines: Baselines,
2217 pub pbm_sums: LogicalSides<Au>,
2218}
2219
2220impl IndependentFormattingContext {
2221 pub(crate) fn layout_float_or_atomic_inline(
2222 &self,
2223 layout_context: &LayoutContext,
2224 child_positioning_context: &mut PositioningContext,
2225 containing_block: &ContainingBlock,
2226 ) -> IndependentFloatOrAtomicLayoutResult {
2227 let style = self.style();
2228 let container_writing_mode = containing_block.style.writing_mode;
2229 let layout_style = self.layout_style();
2230 let content_box_sizes_and_pbm =
2231 layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
2232 let pbm = &content_box_sizes_and_pbm.pbm;
2233 let margin = pbm.margin.auto_is(Au::zero);
2234 let pbm_sums = pbm.padding + pbm.border + margin;
2235 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
2236 let is_table = self.is_table();
2237
2238 let available_inline_size =
2239 Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
2240 let available_block_size = containing_block
2241 .size
2242 .block
2243 .to_definite()
2244 .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
2245
2246 let tentative_block_content_size =
2247 self.tentative_block_content_size(preferred_aspect_ratio);
2248 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
2249 SizeConstraint::Definite(content_box_sizes_and_pbm.content_box_sizes.block.resolve(
2250 Direction::Block,
2251 Size::FitContent,
2252 Au::zero,
2253 available_block_size,
2254 || block_content_size,
2255 is_table,
2256 ))
2257 } else {
2258 content_box_sizes_and_pbm
2259 .content_box_sizes
2260 .block
2261 .resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size)
2262 };
2263
2264 let get_content_size = || {
2265 let constraint_space =
2266 ConstraintSpace::new(tentative_block_size, style, preferred_aspect_ratio);
2267 self.inline_content_sizes(layout_context, &constraint_space)
2268 .sizes
2269 };
2270
2271 let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
2272 Direction::Inline,
2273 Size::FitContent,
2274 Au::zero,
2275 Some(available_inline_size),
2276 get_content_size,
2277 is_table,
2278 );
2279
2280 let containing_block_for_children = ContainingBlock {
2281 size: ContainingBlockSize {
2282 inline: inline_size,
2283 block: tentative_block_size,
2284 },
2285 style,
2286 };
2287 assert_eq!(
2288 container_writing_mode.is_horizontal(),
2289 style.writing_mode.is_horizontal(),
2290 "Mixed horizontal and vertical writing modes are not supported yet"
2291 );
2292
2293 let lazy_block_size = LazySize::new(
2294 &content_box_sizes_and_pbm.content_box_sizes.block,
2295 Direction::Block,
2296 Size::FitContent,
2297 Au::zero,
2298 available_block_size,
2299 is_table,
2300 );
2301
2302 let CacheableLayoutResult {
2303 content_inline_size_for_table,
2304 content_block_size,
2305 fragments,
2306 baselines,
2307 specific_layout_info,
2308 ..
2309 } = self.layout(
2310 layout_context,
2311 child_positioning_context,
2312 &containing_block_for_children,
2313 containing_block,
2314 preferred_aspect_ratio,
2315 &lazy_block_size,
2316 );
2317
2318 let content_size = LogicalVec2 {
2319 inline: content_inline_size_for_table.unwrap_or(inline_size),
2320 block: lazy_block_size.resolve(|| content_block_size),
2321 }
2322 .to_physical_size(container_writing_mode);
2323 let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
2324
2325 let mut base_fragment_info = self.base_fragment_info();
2326 if content_box_sizes_and_pbm.depends_on_block_constraints {
2327 base_fragment_info.flags.insert(
2328 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2329 );
2330 }
2331
2332 let fragment = BoxFragment::new(
2336 base_fragment_info,
2337 style.clone(),
2338 fragments,
2339 content_rect,
2340 pbm.padding.to_physical(container_writing_mode),
2341 pbm.border.to_physical(container_writing_mode),
2342 margin.to_physical(container_writing_mode),
2343 specific_layout_info,
2344 );
2345
2346 IndependentFloatOrAtomicLayoutResult {
2347 fragment,
2348 baselines,
2349 pbm_sums,
2350 }
2351 }
2352}