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 =
1389 automatic_inline_size(justify_self, is_table, self.is_replaced());
1390 let compute_inline_size = |stretch_size| {
1391 content_box_sizes.inline.resolve(
1392 Direction::Inline,
1393 automatic_inline_size,
1394 Au::zero,
1395 Some(stretch_size),
1396 get_inline_content_sizes,
1397 is_table,
1398 )
1399 };
1400
1401 let get_lazy_block_size = || {
1402 LazySize::new(
1403 &content_box_sizes.block,
1404 Direction::Block,
1405 Size::FitContent,
1406 Au::zero,
1407 available_block_size,
1408 is_table,
1409 )
1410 };
1411
1412 let inline_size_with_no_available_space = compute_inline_size(Au::zero());
1421 if inline_size_with_no_available_space == compute_inline_size(MAX_AU) {
1422 let inline_size = inline_size_with_no_available_space;
1426 let lazy_block_size = get_lazy_block_size();
1427 layout = self.layout(
1428 layout_context,
1429 positioning_context,
1430 &ContainingBlock {
1431 size: ContainingBlockSize {
1432 inline: inline_size,
1433 block: tentative_block_size,
1434 },
1435 style,
1436 },
1437 containing_block,
1438 preferred_aspect_ratio,
1439 &lazy_block_size,
1440 );
1441
1442 content_size = LogicalVec2 {
1443 block: lazy_block_size.resolve(|| layout.content_block_size),
1444 inline: layout.content_inline_size_for_table.unwrap_or(inline_size),
1445 };
1446
1447 let mut placement = PlacementAmongFloats::new(
1448 &sequential_layout_state.floats,
1449 ceiling,
1450 content_size + pbm.padding_border_sums,
1451 &pbm,
1452 );
1453 placement_rect = placement.place();
1454 } else {
1455 let minimum_size_of_block = LogicalVec2 {
1461 inline: inline_size_with_no_available_space,
1465 block: match tentative_block_size {
1466 SizeConstraint::Definite(size) if max_block_size.is_some() => size,
1469 _ => min_block_size,
1472 },
1473 } + pbm.padding_border_sums;
1474 let mut placement = PlacementAmongFloats::new(
1475 &sequential_layout_state.floats,
1476 ceiling,
1477 minimum_size_of_block,
1478 &pbm,
1479 );
1480
1481 loop {
1482 placement_rect = placement.place();
1484 let available_inline_size =
1485 placement_rect.size.inline - pbm.padding_border_sums.inline;
1486 let proposed_inline_size = compute_inline_size(available_inline_size);
1487
1488 let positioning_context_length = positioning_context.len();
1492 let lazy_block_size = get_lazy_block_size();
1493 layout = self.layout(
1494 layout_context,
1495 positioning_context,
1496 &ContainingBlock {
1497 size: ContainingBlockSize {
1498 inline: proposed_inline_size,
1499 block: tentative_block_size,
1500 },
1501 style,
1502 },
1503 containing_block,
1504 preferred_aspect_ratio,
1505 &lazy_block_size,
1506 );
1507
1508 let inline_size = if let Some(inline_size) = layout.content_inline_size_for_table {
1509 debug_assert!(inline_size < proposed_inline_size);
1514 inline_size
1515 } else {
1516 proposed_inline_size
1517 };
1518 content_size = LogicalVec2 {
1519 block: lazy_block_size.resolve(|| layout.content_block_size),
1520 inline: inline_size,
1521 };
1522
1523 if placement.try_to_expand_for_auto_block_size(
1527 content_size.block + pbm.padding_border_sums.block,
1528 &placement_rect.size,
1529 ) {
1530 break;
1531 }
1532
1533 positioning_context.truncate(&positioning_context_length);
1537 }
1538 }
1539
1540 let has_clearance = clear_position.is_some() || placement_rect.start_corner.block > ceiling;
1544 let clearance = has_clearance.then(|| {
1545 placement_rect.start_corner.block -
1546 sequential_layout_state
1547 .position_with_zero_clearance(&collapsed_margin_block_start)
1548 });
1549
1550 let ((margin_inline_start, margin_inline_end), effective_margin_inline_start) =
1551 solve_inline_margins_avoiding_floats(
1552 sequential_layout_state,
1553 containing_block,
1554 &pbm,
1555 content_size.inline + pbm.padding_border_sums.inline,
1556 placement_rect,
1557 justify_self,
1558 );
1559
1560 let margin = LogicalSides {
1561 inline_start: margin_inline_start,
1562 inline_end: margin_inline_end,
1563 block_start: margin_block_start,
1564 block_end: margin_block_end,
1565 };
1566
1567 if clearance.is_some() {
1570 sequential_layout_state.collapse_margins();
1571 }
1572 sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
1573
1574 sequential_layout_state.collapse_margins();
1576 sequential_layout_state.advance_block_position(
1577 pbm.padding_border_sums.block + content_size.block + clearance.unwrap_or_else(Au::zero),
1578 );
1579 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1580
1581 let content_rect = LogicalRect {
1582 start_corner: LogicalVec2 {
1583 block: pbm.padding.block_start +
1584 pbm.border.block_start +
1585 clearance.unwrap_or_else(Au::zero),
1586 inline: pbm.padding.inline_start +
1587 pbm.border.inline_start +
1588 effective_margin_inline_start,
1589 },
1590 size: content_size,
1591 };
1592
1593 let mut base_fragment_info = self.base.base_fragment_info;
1594 if depends_on_block_constraints {
1595 base_fragment_info.flags.insert(
1596 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1597 );
1598 }
1599
1600 BoxFragment::new(
1601 base_fragment_info,
1602 style.clone(),
1603 layout.fragments,
1604 content_rect.as_physical(Some(containing_block)),
1605 pbm.padding.to_physical(containing_block_writing_mode),
1606 pbm.border.to_physical(containing_block_writing_mode),
1607 margin.to_physical(containing_block_writing_mode),
1608 layout.specific_layout_info,
1609 )
1610 .with_baselines(layout.baselines)
1611 .with_block_level_layout_info(CollapsedBlockMargins::from_margin(&margin), clearance)
1612 }
1613}
1614
1615struct ContainingBlockPaddingAndBorder<'a> {
1616 containing_block: ContainingBlock<'a>,
1617 pbm: PaddingBorderMargin,
1618 block_sizes: Sizes,
1619 depends_on_block_constraints: bool,
1620 available_block_size: Option<Au>,
1621 justify_self: AlignFlags,
1622 preferred_aspect_ratio: Option<AspectRatio>,
1623}
1624
1625struct ResolvedMargins {
1626 pub margin: LogicalSides<Au>,
1628
1629 pub effective_margin_inline_start: Au,
1636}
1637
1638fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
1644 containing_block: &ContainingBlock<'_>,
1645 layout_style: &'a LayoutStyle,
1646 get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
1647 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1648 context: Option<&IndependentFormattingContext>,
1649) -> ContainingBlockPaddingAndBorder<'a> {
1650 let style = layout_style.style();
1651 if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
1652 let containing_block_for_children = ContainingBlock {
1656 size: ContainingBlockSize {
1657 inline: containing_block.size.inline,
1658 block: containing_block.size.block,
1659 },
1660 style,
1661 };
1662 return ContainingBlockPaddingAndBorder {
1665 containing_block: containing_block_for_children,
1666 pbm: PaddingBorderMargin::zero(),
1667 block_sizes: Sizes::default(),
1668 depends_on_block_constraints: false,
1669 available_block_size: None,
1672 justify_self: AlignFlags::NORMAL,
1675 preferred_aspect_ratio: None,
1676 };
1677 }
1678
1679 let ContentBoxSizesAndPBM {
1680 content_box_sizes,
1681 pbm,
1682 depends_on_block_constraints,
1683 ..
1684 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
1685
1686 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1687 let available_inline_size = Au::zero().max(containing_block.size.inline - pbm_sums.inline);
1688 let available_block_size = containing_block
1689 .size
1690 .block
1691 .to_definite()
1692 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1693
1694 let preferred_aspect_ratio =
1697 context.and_then(|context| context.preferred_aspect_ratio(&pbm.padding_border_sums));
1698 let is_table = layout_style.is_table();
1699
1700 let tentative_block_content_size =
1703 context.and_then(|context| context.tentative_block_content_size(preferred_aspect_ratio));
1704 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
1705 SizeConstraint::Definite(content_box_sizes.block.resolve(
1706 Direction::Block,
1707 Size::FitContent,
1708 Au::zero,
1709 available_block_size,
1710 || block_content_size,
1711 is_table,
1712 ))
1713 } else {
1714 content_box_sizes.block.resolve_extrinsic(
1715 Size::FitContent,
1716 Au::zero(),
1717 available_block_size,
1718 )
1719 };
1720
1721 let get_inline_content_sizes = || {
1724 get_inline_content_sizes(&ConstraintSpace::new(
1725 tentative_block_size,
1726 style,
1727 preferred_aspect_ratio,
1728 ))
1729 };
1730 let justify_self = resolve_justify_self(style, containing_block.style);
1731 let is_replaced = context.is_some_and(|context| context.is_replaced());
1732 let inline_size = content_box_sizes.inline.resolve(
1733 Direction::Inline,
1734 automatic_inline_size(justify_self, is_table, is_replaced),
1735 Au::zero,
1736 Some(available_inline_size),
1737 get_inline_content_sizes,
1738 is_table,
1739 );
1740
1741 let containing_block_for_children = ContainingBlock {
1742 size: ContainingBlockSize {
1743 inline: inline_size,
1744 block: tentative_block_size,
1745 },
1746 style,
1747 };
1748 assert_eq!(
1750 containing_block.style.writing_mode.is_horizontal(),
1751 containing_block_for_children
1752 .style
1753 .writing_mode
1754 .is_horizontal(),
1755 "Vertical writing modes are not supported yet"
1756 );
1757 ContainingBlockPaddingAndBorder {
1758 containing_block: containing_block_for_children,
1759 pbm,
1760 block_sizes: content_box_sizes.block,
1761 depends_on_block_constraints,
1762 available_block_size,
1763 justify_self,
1764 preferred_aspect_ratio,
1765 }
1766}
1767
1768fn solve_margins(
1773 containing_block: &ContainingBlock<'_>,
1774 pbm: &PaddingBorderMargin,
1775 inline_size: Au,
1776 justify_self: AlignFlags,
1777) -> ResolvedMargins {
1778 let (inline_margins, effective_margin_inline_start) =
1779 solve_inline_margins_for_in_flow_block_level(
1780 containing_block,
1781 pbm,
1782 inline_size,
1783 justify_self,
1784 );
1785 let block_margins = solve_block_margins_for_in_flow_block_level(pbm);
1786 ResolvedMargins {
1787 margin: LogicalSides {
1788 inline_start: inline_margins.0,
1789 inline_end: inline_margins.1,
1790 block_start: block_margins.0,
1791 block_end: block_margins.1,
1792 },
1793 effective_margin_inline_start,
1794 }
1795}
1796
1797fn solve_block_margins_for_in_flow_block_level(pbm: &PaddingBorderMargin) -> (Au, Au) {
1801 (
1802 pbm.margin.block_start.auto_is(Au::zero),
1803 pbm.margin.block_end.auto_is(Au::zero),
1804 )
1805}
1806
1807fn resolve_justify_self(style: &ComputedValues, parent_style: &ComputedValues) -> AlignFlags {
1809 let is_ltr = |style: &ComputedValues| style.writing_mode.line_left_is_inline_start();
1810 let alignment = match style.clone_justify_self().0.0 {
1811 AlignFlags::AUTO => parent_style.clone_justify_items().computed.0,
1812 alignment => alignment,
1813 };
1814 let alignment_value = match alignment.value() {
1815 AlignFlags::LEFT if is_ltr(parent_style) => AlignFlags::START,
1816 AlignFlags::LEFT => AlignFlags::END,
1817 AlignFlags::RIGHT if is_ltr(parent_style) => AlignFlags::END,
1818 AlignFlags::RIGHT => AlignFlags::START,
1819 AlignFlags::SELF_START if is_ltr(parent_style) == is_ltr(style) => AlignFlags::START,
1820 AlignFlags::SELF_START => AlignFlags::END,
1821 AlignFlags::SELF_END if is_ltr(parent_style) == is_ltr(style) => AlignFlags::END,
1822 AlignFlags::SELF_END => AlignFlags::START,
1823 alignment_value => alignment_value,
1824 };
1825 alignment.flags() | alignment_value
1826}
1827
1828#[inline]
1831fn automatic_inline_size<T>(
1832 justify_self: AlignFlags,
1833 is_table: bool,
1834 is_replaced: bool,
1835) -> Size<T> {
1836 match justify_self {
1838 AlignFlags::STRETCH => Size::Stretch,
1839 AlignFlags::NORMAL if !is_table && !is_replaced => Size::Stretch,
1840 _ => Size::FitContent,
1841 }
1842}
1843
1844fn justify_self_alignment(
1851 containing_block: &ContainingBlock,
1852 free_space: Au,
1853 justify_self: AlignFlags,
1854) -> Au {
1855 let mut alignment = justify_self.value();
1856 let is_safe = justify_self.flags() == AlignFlags::SAFE || alignment == AlignFlags::NORMAL;
1857 if is_safe && free_space <= Au::zero() {
1858 alignment = AlignFlags::START
1859 }
1860 match alignment {
1861 AlignFlags::NORMAL => {},
1862 AlignFlags::CENTER => return free_space / 2,
1863 AlignFlags::END => return free_space,
1864 _ => return Au::zero(),
1865 }
1866
1867 let style = containing_block.style;
1869 match style.clone_text_align() {
1870 TextAlignKeyword::MozCenter => free_space / 2,
1871 TextAlignKeyword::MozLeft if !style.writing_mode.line_left_is_inline_start() => free_space,
1872 TextAlignKeyword::MozRight if style.writing_mode.line_left_is_inline_start() => free_space,
1873 _ => Au::zero(),
1874 }
1875}
1876
1877fn solve_inline_margins_for_in_flow_block_level(
1890 containing_block: &ContainingBlock,
1891 pbm: &PaddingBorderMargin,
1892 inline_size: Au,
1893 justify_self: AlignFlags,
1894) -> ((Au, Au), Au) {
1895 let free_space = containing_block.size.inline - pbm.padding_border_sums.inline - inline_size;
1896 let mut justification = Au::zero();
1897 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1898 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1899 let start = Au::zero().max(free_space / 2);
1900 (start, free_space - start)
1901 },
1902 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => {
1903 (Au::zero().max(free_space - end), end)
1904 },
1905 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, free_space - start),
1906 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1907 justification =
1912 justify_self_alignment(containing_block, free_space - start - end, justify_self);
1913 (start, end)
1914 },
1915 };
1916 let effective_margin_inline_start = inline_margins.0 + justification;
1917 (inline_margins, effective_margin_inline_start)
1918}
1919
1920fn solve_inline_margins_avoiding_floats(
1930 sequential_layout_state: &SequentialLayoutState,
1931 containing_block: &ContainingBlock,
1932 pbm: &PaddingBorderMargin,
1933 inline_size: Au,
1934 placement_rect: LogicalRect<Au>,
1935 justify_self: AlignFlags,
1936) -> ((Au, Au), Au) {
1937 let free_space = Au::zero().max(placement_rect.size.inline - inline_size);
1941 let cb_info = &sequential_layout_state.floats.containing_block_info;
1942 let start_adjustment = placement_rect.start_corner.inline - cb_info.inline_start;
1943 let end_adjustment = cb_info.inline_end - placement_rect.max_inline_position();
1944 let mut justification = Au::zero();
1945 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1946 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1947 let half = free_space / 2;
1948 (start_adjustment + half, end_adjustment + free_space - half)
1949 },
1950 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (start_adjustment + free_space, end),
1951 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, end_adjustment + free_space),
1952 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1953 justification = justify_self_alignment(containing_block, free_space, justify_self);
1959 (start, end)
1960 },
1961 };
1962 let effective_margin_inline_start = inline_margins.0.max(start_adjustment) + justification;
1963 (inline_margins, effective_margin_inline_start)
1964}
1965
1966struct PlacementState<'container> {
1971 next_in_flow_margin_collapses_with_parent_start_margin: bool,
1972 last_in_flow_margin_collapses_with_parent_end_margin: bool,
1973 start_margin: CollapsedMargin,
1974 current_margin: CollapsedMargin,
1975 current_block_direction_position: Au,
1976 inflow_baselines: Baselines,
1977 is_inline_block_context: bool,
1978
1979 marker_block_size: Option<Au>,
1984
1985 containing_block: &'container ContainingBlock<'container>,
1988}
1989
1990impl<'container> PlacementState<'container> {
1991 fn new(
1992 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1993 containing_block: &'container ContainingBlock<'container>,
1994 ) -> PlacementState<'container> {
1995 let is_inline_block_context =
1996 containing_block.style.get_box().clone_display() == Display::InlineBlock;
1997 PlacementState {
1998 next_in_flow_margin_collapses_with_parent_start_margin:
1999 collapsible_with_parent_start_margin.0,
2000 last_in_flow_margin_collapses_with_parent_end_margin: true,
2001 start_margin: CollapsedMargin::zero(),
2002 current_margin: CollapsedMargin::zero(),
2003 current_block_direction_position: Au::zero(),
2004 inflow_baselines: Baselines::default(),
2005 is_inline_block_context,
2006 marker_block_size: None,
2007 containing_block,
2008 }
2009 }
2010
2011 fn place_fragment_and_update_baseline(
2012 &mut self,
2013 fragment: &mut Fragment,
2014 sequential_layout_state: Option<&mut SequentialLayoutState>,
2015 ) {
2016 self.place_fragment(fragment, sequential_layout_state);
2017
2018 let box_fragment = match fragment {
2019 Fragment::Box(box_fragment) => box_fragment,
2020 _ => return,
2021 };
2022 let box_fragment = box_fragment.borrow();
2023
2024 if self.is_inline_block_context && box_fragment.is_table_wrapper() {
2029 return;
2030 }
2031
2032 let box_block_offset = box_fragment
2033 .content_rect
2034 .origin
2035 .to_logical(self.containing_block)
2036 .block;
2037 let box_fragment_baselines =
2038 box_fragment.baselines(self.containing_block.style.writing_mode);
2039 if let (None, Some(first)) = (self.inflow_baselines.first, box_fragment_baselines.first) {
2040 self.inflow_baselines.first = Some(first + box_block_offset);
2041 }
2042 if let Some(last) = box_fragment_baselines.last {
2043 self.inflow_baselines.last = Some(last + box_block_offset);
2044 }
2045 }
2046
2047 fn place_fragment(
2050 &mut self,
2051 fragment: &mut Fragment,
2052 sequential_layout_state: Option<&mut SequentialLayoutState>,
2053 ) {
2054 match fragment {
2055 Fragment::Box(fragment) => {
2056 let fragment = &mut *fragment.borrow_mut();
2065 let is_outside_marker = fragment
2066 .base
2067 .flags
2068 .contains(FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER);
2069 if is_outside_marker {
2070 assert!(self.marker_block_size.is_none());
2071 self.marker_block_size = Some(
2072 fragment
2073 .content_rect
2074 .size
2075 .to_logical(self.containing_block.style.writing_mode)
2076 .block,
2077 );
2078 return;
2079 }
2080
2081 let BlockLevelLayoutInfo {
2082 clearance,
2083 block_margins_collapsed_with_children: fragment_block_margins,
2084 } = &**fragment
2085 .block_level_layout_info
2086 .as_ref()
2087 .expect("A block-level fragment should have a BlockLevelLayoutInfo.");
2088 let mut fragment_block_size = fragment
2089 .border_rect()
2090 .size
2091 .to_logical(self.containing_block.style.writing_mode)
2092 .block;
2093
2094 if let Some(clearance) = *clearance {
2100 fragment_block_size += clearance;
2101 self.current_block_direction_position += self.current_margin.solve();
2106 self.current_margin = CollapsedMargin::zero();
2107 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2108 if fragment_block_margins.collapsed_through {
2109 self.last_in_flow_margin_collapses_with_parent_end_margin = false;
2110 }
2111 } else if !fragment_block_margins.collapsed_through {
2112 self.last_in_flow_margin_collapses_with_parent_end_margin = true;
2113 }
2114
2115 if self.next_in_flow_margin_collapses_with_parent_start_margin {
2116 debug_assert!(self.current_margin.solve().is_zero());
2117 self.start_margin
2118 .adjoin_assign(&fragment_block_margins.start);
2119 if fragment_block_margins.collapsed_through {
2120 self.start_margin.adjoin_assign(&fragment_block_margins.end);
2121 return;
2122 }
2123 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2124 } else {
2125 self.current_margin
2126 .adjoin_assign(&fragment_block_margins.start);
2127 }
2128
2129 fragment.content_rect.origin += LogicalVec2 {
2130 inline: Au::zero(),
2131 block: self.current_margin.solve() + self.current_block_direction_position,
2132 }
2133 .to_physical_size(self.containing_block.style.writing_mode);
2134
2135 if fragment_block_margins.collapsed_through {
2136 self.current_block_direction_position += fragment_block_size;
2139 self.current_margin
2140 .adjoin_assign(&fragment_block_margins.end);
2141 } else {
2142 self.current_block_direction_position +=
2143 self.current_margin.solve() + fragment_block_size;
2144 self.current_margin = fragment_block_margins.end;
2145 }
2146 },
2147 Fragment::AbsoluteOrFixedPositioned(fragment) => {
2148 fragment.borrow_mut().original_static_position_rect = LogicalRect {
2151 start_corner: LogicalVec2 {
2152 block: (self.current_margin.solve() +
2153 self.current_block_direction_position),
2154 inline: Au::zero(),
2155 },
2156 size: LogicalVec2::zero(),
2157 }
2158 .as_physical(Some(self.containing_block));
2159 },
2160 Fragment::Float(box_fragment) => {
2161 let sequential_layout_state = sequential_layout_state
2162 .expect("Found float fragment without SequentialLayoutState");
2163 let block_offset_from_containing_block_top =
2164 self.current_block_direction_position + self.current_margin.solve();
2165 let box_fragment = &mut *box_fragment.borrow_mut();
2166 sequential_layout_state.place_float_fragment(
2167 box_fragment,
2168 self.containing_block,
2169 self.start_margin,
2170 block_offset_from_containing_block_top,
2171 );
2172 },
2173 Fragment::Positioning(_) => {},
2174 _ => unreachable!(),
2175 }
2176 }
2177
2178 fn finish(mut self) -> (Au, CollapsedBlockMargins, Baselines) {
2179 if !self.last_in_flow_margin_collapses_with_parent_end_margin {
2180 self.current_block_direction_position += self.current_margin.solve();
2181 self.current_margin = CollapsedMargin::zero();
2182 }
2183 let (total_block_size, collapsed_through) = match self.marker_block_size {
2184 Some(marker_block_size) => (
2185 self.current_block_direction_position.max(marker_block_size),
2186 false,
2189 ),
2190 None => (
2191 self.current_block_direction_position,
2192 self.next_in_flow_margin_collapses_with_parent_start_margin,
2193 ),
2194 };
2195
2196 (
2197 total_block_size,
2198 CollapsedBlockMargins {
2199 collapsed_through,
2200 start: self.start_margin,
2201 end: self.current_margin,
2202 },
2203 self.inflow_baselines,
2204 )
2205 }
2206}
2207
2208pub(crate) struct IndependentFloatOrAtomicLayoutResult {
2209 pub fragment: BoxFragment,
2210 pub baselines: Baselines,
2211 pub pbm_sums: LogicalSides<Au>,
2212}
2213
2214impl IndependentFormattingContext {
2215 pub(crate) fn layout_float_or_atomic_inline(
2216 &self,
2217 layout_context: &LayoutContext,
2218 child_positioning_context: &mut PositioningContext,
2219 containing_block: &ContainingBlock,
2220 ) -> IndependentFloatOrAtomicLayoutResult {
2221 let style = self.style();
2222 let container_writing_mode = containing_block.style.writing_mode;
2223 let layout_style = self.layout_style();
2224 let content_box_sizes_and_pbm =
2225 layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
2226 let pbm = &content_box_sizes_and_pbm.pbm;
2227 let margin = pbm.margin.auto_is(Au::zero);
2228 let pbm_sums = pbm.padding + pbm.border + margin;
2229 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
2230 let is_table = self.is_table();
2231
2232 let available_inline_size =
2233 Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
2234 let available_block_size = containing_block
2235 .size
2236 .block
2237 .to_definite()
2238 .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
2239
2240 let tentative_block_content_size =
2241 self.tentative_block_content_size(preferred_aspect_ratio);
2242 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
2243 SizeConstraint::Definite(content_box_sizes_and_pbm.content_box_sizes.block.resolve(
2244 Direction::Block,
2245 Size::FitContent,
2246 Au::zero,
2247 available_block_size,
2248 || block_content_size,
2249 is_table,
2250 ))
2251 } else {
2252 content_box_sizes_and_pbm
2253 .content_box_sizes
2254 .block
2255 .resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size)
2256 };
2257
2258 let get_content_size = || {
2259 let constraint_space =
2260 ConstraintSpace::new(tentative_block_size, style, preferred_aspect_ratio);
2261 self.inline_content_sizes(layout_context, &constraint_space)
2262 .sizes
2263 };
2264
2265 let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
2266 Direction::Inline,
2267 Size::FitContent,
2268 Au::zero,
2269 Some(available_inline_size),
2270 get_content_size,
2271 is_table,
2272 );
2273
2274 let containing_block_for_children = ContainingBlock {
2275 size: ContainingBlockSize {
2276 inline: inline_size,
2277 block: tentative_block_size,
2278 },
2279 style,
2280 };
2281 assert_eq!(
2282 container_writing_mode.is_horizontal(),
2283 style.writing_mode.is_horizontal(),
2284 "Mixed horizontal and vertical writing modes are not supported yet"
2285 );
2286
2287 let lazy_block_size = LazySize::new(
2288 &content_box_sizes_and_pbm.content_box_sizes.block,
2289 Direction::Block,
2290 Size::FitContent,
2291 Au::zero,
2292 available_block_size,
2293 is_table,
2294 );
2295
2296 let CacheableLayoutResult {
2297 content_inline_size_for_table,
2298 content_block_size,
2299 fragments,
2300 baselines,
2301 specific_layout_info,
2302 ..
2303 } = self.layout(
2304 layout_context,
2305 child_positioning_context,
2306 &containing_block_for_children,
2307 containing_block,
2308 preferred_aspect_ratio,
2309 &lazy_block_size,
2310 );
2311
2312 let content_size = LogicalVec2 {
2313 inline: content_inline_size_for_table.unwrap_or(inline_size),
2314 block: lazy_block_size.resolve(|| content_block_size),
2315 }
2316 .to_physical_size(container_writing_mode);
2317 let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
2318
2319 let mut base_fragment_info = self.base_fragment_info();
2320 if content_box_sizes_and_pbm.depends_on_block_constraints {
2321 base_fragment_info.flags.insert(
2322 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2323 );
2324 }
2325
2326 let fragment = BoxFragment::new(
2330 base_fragment_info,
2331 style.clone(),
2332 fragments,
2333 content_rect,
2334 pbm.padding.to_physical(container_writing_mode),
2335 pbm.border.to_physical(container_writing_mode),
2336 margin.to_physical(container_writing_mode),
2337 specific_layout_info,
2338 );
2339
2340 IndependentFloatOrAtomicLayoutResult {
2341 fragment,
2342 baselines,
2343 pbm_sums,
2344 }
2345 }
2346}