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::computed::Size as StyleSize;
22use style::values::specified::align::AlignFlags;
23use style::values::specified::{Display, TextAlignKeyword};
24
25use crate::cell::ArcRefCell;
26use crate::context::LayoutContext;
27use crate::flow::float::{
28 Clear, ContainingBlockPositionInfo, FloatBox, FloatSide, PlacementAmongFloats,
29 SequentialLayoutState,
30};
31use crate::formatting_contexts::{Baselines, IndependentFormattingContext};
32use crate::fragment_tree::{
33 BaseFragmentInfo, BlockLevelLayoutInfo, BoxFragment, CollapsedBlockMargins, CollapsedMargin,
34 Fragment, FragmentFlags,
35};
36use crate::geom::{
37 AuOrAuto, LogicalRect, LogicalSides, LogicalSides1D, LogicalVec2, PhysicalPoint, PhysicalRect,
38 PhysicalSides, ToLogical, ToLogicalWithContainingBlock,
39};
40use crate::layout_box_base::{CacheableLayoutResult, LayoutBoxBase};
41use crate::positioned::{AbsolutelyPositionedBox, PositioningContext, PositioningContextLength};
42use crate::sizing::{
43 self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, LazySize, Size,
44 SizeConstraint, Sizes,
45};
46use crate::style_ext::{AspectRatio, ContentBoxSizesAndPBM, LayoutStyle, PaddingBorderMargin};
47use crate::{ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock};
48
49mod construct;
50pub mod float;
51pub mod inline;
52mod root;
53
54pub(crate) use construct::BlockContainerBuilder;
55pub(crate) use root::BoxTree;
56
57#[derive(Debug, MallocSizeOf)]
58pub(crate) struct BlockFormattingContext {
59 pub contents: BlockContainer,
60 pub contains_floats: bool,
61}
62
63#[derive(Debug, MallocSizeOf)]
64pub(crate) enum BlockContainer {
65 BlockLevelBoxes(Vec<ArcRefCell<BlockLevelBox>>),
66 InlineFormattingContext(InlineFormattingContext),
67}
68
69impl BlockContainer {
70 fn contains_floats(&self) -> bool {
71 match self {
72 BlockContainer::BlockLevelBoxes(boxes) => boxes
73 .iter()
74 .any(|block_level_box| block_level_box.borrow().contains_floats()),
75 BlockContainer::InlineFormattingContext(context) => context.contains_floats,
76 }
77 }
78
79 pub(crate) fn repair_style(
80 &mut self,
81 node: &ServoThreadSafeLayoutNode,
82 new_style: &Arc<ComputedValues>,
83 ) {
84 match self {
85 BlockContainer::BlockLevelBoxes(..) => {},
86 BlockContainer::InlineFormattingContext(inline_formatting_context) => {
87 inline_formatting_context.repair_style(node, new_style)
88 },
89 }
90 }
91}
92
93#[derive(Debug, MallocSizeOf)]
94pub(crate) enum BlockLevelBox {
95 Independent(IndependentFormattingContext),
96 OutOfFlowAbsolutelyPositionedBox(ArcRefCell<AbsolutelyPositionedBox>),
97 OutOfFlowFloatBox(FloatBox),
98 OutsideMarker(OutsideMarker),
99 SameFormattingContextBlock {
100 base: LayoutBoxBase,
101 contents: BlockContainer,
102 contains_floats: bool,
103 },
104}
105
106impl BlockLevelBox {
107 pub(crate) fn repair_style(
108 &mut self,
109 context: &SharedStyleContext,
110 node: &ServoThreadSafeLayoutNode,
111 new_style: &Arc<ComputedValues>,
112 ) {
113 self.with_base_mut(|base| {
114 base.repair_style(new_style);
115 });
116
117 match self {
118 BlockLevelBox::Independent(independent_formatting_context) => {
119 independent_formatting_context.repair_style(context, node, new_style)
120 },
121 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => positioned_box
122 .borrow_mut()
123 .context
124 .repair_style(context, node, new_style),
125 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
126 float_box.contents.repair_style(context, node, new_style)
127 },
128 BlockLevelBox::OutsideMarker(outside_marker) => {
129 outside_marker.repair_style(context, node, new_style)
130 },
131 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
132 base.repair_style(new_style);
133 contents.repair_style(node, new_style);
134 },
135 }
136 }
137
138 pub(crate) fn clear_fragment_layout_cache(&self) {
139 self.with_base(|base| base.clear_fragment_layout_cache());
140 }
141
142 pub(crate) fn with_base<T>(&self, callback: impl FnOnce(&LayoutBoxBase) -> T) -> T {
143 match self {
144 BlockLevelBox::Independent(independent_formatting_context) => {
145 callback(&independent_formatting_context.base)
146 },
147 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
148 callback(&positioned_box.borrow().context.base)
149 },
150 BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&float_box.contents.base),
151 BlockLevelBox::OutsideMarker(outside_marker) => callback(&outside_marker.base),
152 BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base),
153 }
154 }
155
156 pub(crate) fn with_base_mut<T>(&mut self, callback: impl Fn(&mut LayoutBoxBase) -> T) -> T {
157 match self {
158 BlockLevelBox::Independent(independent_formatting_context) => {
159 callback(&mut independent_formatting_context.base)
160 },
161 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(positioned_box) => {
162 callback(&mut positioned_box.borrow_mut().context.base)
163 },
164 BlockLevelBox::OutOfFlowFloatBox(float_box) => callback(&mut float_box.contents.base),
165 BlockLevelBox::OutsideMarker(outside_marker) => callback(&mut outside_marker.base),
166 BlockLevelBox::SameFormattingContextBlock { base, .. } => callback(base),
167 }
168 }
169
170 fn contains_floats(&self) -> bool {
171 match self {
172 BlockLevelBox::SameFormattingContextBlock {
173 contains_floats, ..
174 } => *contains_floats,
175 BlockLevelBox::OutOfFlowFloatBox { .. } => true,
176 _ => false,
177 }
178 }
179
180 fn find_block_margin_collapsing_with_parent(
181 &self,
182 layout_context: &LayoutContext,
183 collected_margin: &mut CollapsedMargin,
184 containing_block: &ContainingBlock,
185 ) -> bool {
186 let layout_style = match self {
187 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
188 contents.layout_style(base)
189 },
190 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
191 BlockLevelBox::OutOfFlowFloatBox(_) => return true,
192 BlockLevelBox::OutsideMarker(_) => return false,
193 BlockLevelBox::Independent(context) => {
194 context.layout_style()
197 },
198 };
199
200 let style = layout_style.style();
202 if style.get_box().clear != StyleClear::None {
203 return false;
204 }
205
206 let ContentBoxSizesAndPBM {
207 content_box_sizes,
208 pbm,
209 ..
210 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
211 let margin = pbm.margin.auto_is(Au::zero);
212 collected_margin.adjoin_assign(&CollapsedMargin::new(margin.block_start));
213
214 let child_boxes = match self {
215 BlockLevelBox::SameFormattingContextBlock { contents, .. } => match contents {
216 BlockContainer::BlockLevelBoxes(boxes) => boxes,
217 BlockContainer::InlineFormattingContext(_) => return false,
218 },
219 _ => return false,
220 };
221
222 if !pbm.padding.block_start.is_zero() || !pbm.border.block_start.is_zero() {
223 return false;
224 }
225
226 let available_inline_size =
227 containing_block.size.inline - pbm.padding_border_sums.inline - margin.inline_sum();
228 let available_block_size = containing_block.size.block.to_definite().map(|block_size| {
229 Au::zero().max(block_size - pbm.padding_border_sums.block - margin.block_sum())
230 });
231
232 let tentative_block_size = content_box_sizes.block.resolve_extrinsic(
233 Size::FitContent,
234 Au::zero(),
235 available_block_size,
236 );
237
238 let get_inline_content_sizes = || {
239 let constraint_space = ConstraintSpace::new(
240 tentative_block_size,
241 style.writing_mode,
242 None, );
244 self.inline_content_sizes(layout_context, &constraint_space)
245 .sizes
246 };
247 let inline_size = content_box_sizes.inline.resolve(
248 Direction::Inline,
249 Size::Stretch,
250 Au::zero,
251 Some(available_inline_size),
252 get_inline_content_sizes,
253 false, );
255
256 let containing_block_for_children = ContainingBlock {
257 size: ContainingBlockSize {
258 inline: inline_size,
259 block: tentative_block_size,
260 },
261 style,
262 };
263
264 if !Self::find_block_margin_collapsing_with_parent_from_slice(
265 layout_context,
266 child_boxes,
267 collected_margin,
268 &containing_block_for_children,
269 ) {
270 return false;
271 }
272
273 if !block_size_is_zero_or_intrinsic(style.content_block_size(), containing_block) ||
274 !block_size_is_zero_or_intrinsic(style.min_block_size(), containing_block) ||
275 !pbm.padding_border_sums.block.is_zero()
276 {
277 return false;
278 }
279
280 collected_margin.adjoin_assign(&CollapsedMargin::new(margin.block_end));
281
282 true
283 }
284
285 fn find_block_margin_collapsing_with_parent_from_slice(
286 layout_context: &LayoutContext,
287 boxes: &[ArcRefCell<BlockLevelBox>],
288 margin: &mut CollapsedMargin,
289 containing_block: &ContainingBlock,
290 ) -> bool {
291 boxes.iter().all(|block_level_box| {
292 block_level_box
293 .borrow()
294 .find_block_margin_collapsing_with_parent(layout_context, margin, containing_block)
295 })
296 }
297}
298
299#[derive(Clone, Copy)]
300pub(crate) struct CollapsibleWithParentStartMargin(bool);
301
302#[derive(Debug, MallocSizeOf)]
305pub(crate) struct OutsideMarker {
306 pub list_item_style: Arc<ComputedValues>,
307 pub base: LayoutBoxBase,
308 pub block_formatting_context: BlockFormattingContext,
309}
310
311impl OutsideMarker {
312 fn inline_content_sizes(
313 &self,
314 layout_context: &LayoutContext,
315 constraint_space: &ConstraintSpace,
316 ) -> InlineContentSizesResult {
317 self.base.inline_content_sizes(
318 layout_context,
319 constraint_space,
320 &self.block_formatting_context.contents,
321 )
322 }
323
324 fn layout(
325 &self,
326 layout_context: &LayoutContext<'_>,
327 containing_block: &ContainingBlock<'_>,
328 positioning_context: &mut PositioningContext,
329 ) -> Fragment {
330 let constraint_space = ConstraintSpace::new_for_style_and_ratio(
331 &self.base.style,
332 None, );
334 let content_sizes = self.inline_content_sizes(layout_context, &constraint_space);
335 let containing_block_for_children = ContainingBlock {
336 size: ContainingBlockSize {
337 inline: content_sizes.sizes.max_content,
338 block: SizeConstraint::default(),
339 },
340 style: &self.base.style,
341 };
342
343 let flow_layout = self.block_formatting_context.layout(
344 layout_context,
345 positioning_context,
346 &containing_block_for_children,
347 );
348
349 let max_inline_size =
350 flow_layout
351 .fragments
352 .iter()
353 .fold(Au::zero(), |current_max, fragment| {
354 current_max.max(
355 match fragment {
356 Fragment::Text(text) => text.borrow().rect,
357 Fragment::Image(image) => image.borrow().rect,
358 Fragment::Positioning(positioning) => positioning.borrow().rect,
359 Fragment::Box(_) |
360 Fragment::Float(_) |
361 Fragment::AbsoluteOrFixedPositioned(_) |
362 Fragment::IFrame(_) => {
363 unreachable!(
364 "Found unexpected fragment type in outside list marker!"
365 );
366 },
367 }
368 .to_logical(&containing_block_for_children)
369 .max_inline_position(),
370 )
371 });
372
373 let pbm_of_list_item =
383 LayoutStyle::Default(&self.list_item_style).padding_border_margin(containing_block);
384 let content_rect = LogicalRect {
385 start_corner: LogicalVec2 {
386 inline: -max_inline_size -
387 (pbm_of_list_item.border.inline_start +
388 pbm_of_list_item.padding.inline_start),
389 block: Zero::zero(),
390 },
391 size: LogicalVec2 {
392 inline: max_inline_size,
393 block: flow_layout.content_block_size,
394 },
395 };
396
397 let mut base_fragment_info = BaseFragmentInfo::anonymous();
398 base_fragment_info.flags |= FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER;
399
400 Fragment::Box(ArcRefCell::new(BoxFragment::new(
401 base_fragment_info,
402 self.base.style.clone(),
403 flow_layout.fragments,
404 content_rect.as_physical(Some(containing_block)),
405 PhysicalSides::zero(),
406 PhysicalSides::zero(),
407 PhysicalSides::zero(),
408 flow_layout.specific_layout_info,
409 )))
410 }
411
412 fn repair_style(
413 &mut self,
414 context: &SharedStyleContext,
415 node: &ServoThreadSafeLayoutNode,
416 new_style: &Arc<ComputedValues>,
417 ) {
418 self.list_item_style = node.style(context);
419 self.base.repair_style(new_style);
420 }
421}
422
423impl BlockFormattingContext {
424 pub(super) fn layout(
425 &self,
426 layout_context: &LayoutContext,
427 positioning_context: &mut PositioningContext,
428 containing_block: &ContainingBlock,
429 ) -> CacheableLayoutResult {
430 let mut sequential_layout_state = if self.contains_floats || !layout_context.use_rayon {
431 Some(SequentialLayoutState::new(containing_block.size.inline))
432 } else {
433 None
434 };
435
436 let ignore_block_margins_for_stretch = LogicalSides1D::new(false, false);
440
441 let flow_layout = self.contents.layout(
442 layout_context,
443 positioning_context,
444 containing_block,
445 sequential_layout_state.as_mut(),
446 CollapsibleWithParentStartMargin(false),
447 ignore_block_margins_for_stretch,
448 );
449 debug_assert!(
450 !flow_layout
451 .collapsible_margins_in_children
452 .collapsed_through
453 );
454
455 let clearance = sequential_layout_state.and_then(|sequential_layout_state| {
459 sequential_layout_state.calculate_clearance(Clear::Both, &CollapsedMargin::zero())
460 });
461
462 CacheableLayoutResult {
463 fragments: flow_layout.fragments,
464 content_block_size: flow_layout.content_block_size +
465 flow_layout.collapsible_margins_in_children.end.solve() +
466 clearance.unwrap_or_default(),
467 content_inline_size_for_table: None,
468 baselines: flow_layout.baselines,
469 depends_on_block_constraints: flow_layout.depends_on_block_constraints,
470 specific_layout_info: None,
471 collapsible_margins_in_children: CollapsedBlockMargins::zero(),
472 }
473 }
474
475 #[inline]
476 pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
477 LayoutStyle::Default(&base.style)
478 }
479
480 pub(crate) fn repair_style(
481 &mut self,
482 node: &ServoThreadSafeLayoutNode,
483 new_style: &Arc<ComputedValues>,
484 ) {
485 self.contents.repair_style(node, new_style);
486 }
487}
488
489fn compute_inline_content_sizes_for_block_level_boxes(
495 boxes: &[ArcRefCell<BlockLevelBox>],
496 layout_context: &LayoutContext,
497 containing_block: &IndefiniteContainingBlock,
498) -> InlineContentSizesResult {
499 let get_box_info = |box_: &ArcRefCell<BlockLevelBox>| {
500 match &*box_.borrow() {
501 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(_) |
502 BlockLevelBox::OutsideMarker { .. } => None,
503 BlockLevelBox::OutOfFlowFloatBox(float_box) => {
504 let inline_content_sizes_result = float_box.contents.outer_inline_content_sizes(
505 layout_context,
506 containing_block,
507 &LogicalVec2::zero(),
508 false, );
510 let style = &float_box.contents.style();
511 Some((
512 inline_content_sizes_result,
513 FloatSide::from_style_and_container_writing_mode(
514 style,
515 containing_block.writing_mode,
516 ),
517 Clear::from_style_and_container_writing_mode(
518 style,
519 containing_block.writing_mode,
520 ),
521 ))
522 },
523 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
524 let inline_content_sizes_result = sizing::outer_inline(
525 &contents.layout_style(base),
526 containing_block,
527 &LogicalVec2::zero(),
528 false, false, !matches!(base.style.pseudo(), Some(PseudoElement::ServoAnonymousBox)),
531 |_| None, |constraint_space| {
533 base.inline_content_sizes(layout_context, constraint_space, contents)
534 },
535 |_aspect_ratio| None,
536 );
537 Some((inline_content_sizes_result, None, Clear::Both))
541 },
542 BlockLevelBox::Independent(independent) => {
543 let inline_content_sizes_result = independent.outer_inline_content_sizes(
544 layout_context,
545 containing_block,
546 &LogicalVec2::zero(),
547 false, );
549 Some((
550 inline_content_sizes_result,
551 None,
552 Clear::from_style_and_container_writing_mode(
553 independent.style(),
554 containing_block.writing_mode,
555 ),
556 ))
557 },
558 }
559 };
560
561 #[derive(Default)]
564 struct AccumulatedData {
565 depends_on_block_constraints: bool,
567 max_size: ContentSizes,
569 start_floats: ContentSizes,
572 end_floats: ContentSizes,
575 }
576
577 impl AccumulatedData {
578 fn max_size_including_uncleared_floats(&self) -> ContentSizes {
579 self.max_size.max(self.start_floats.union(&self.end_floats))
580 }
581 fn clear_floats(&mut self, clear: Clear) {
582 match clear {
583 Clear::InlineStart => {
584 self.max_size = self.max_size_including_uncleared_floats();
585 self.start_floats = ContentSizes::zero();
586 },
587 Clear::InlineEnd => {
588 self.max_size = self.max_size_including_uncleared_floats();
589 self.end_floats = ContentSizes::zero();
590 },
591 Clear::Both => {
592 self.max_size = self.max_size_including_uncleared_floats();
593 self.start_floats = ContentSizes::zero();
594 self.end_floats = ContentSizes::zero();
595 },
596 Clear::None => {},
597 };
598 }
599 }
600
601 let accumulate =
602 |mut data: AccumulatedData,
603 (inline_content_sizes_result, float, clear): (InlineContentSizesResult, _, _)| {
604 let size = inline_content_sizes_result.sizes.max(ContentSizes::zero());
605 let depends_on_block_constraints =
606 inline_content_sizes_result.depends_on_block_constraints;
607 data.depends_on_block_constraints |= depends_on_block_constraints;
608 data.clear_floats(clear);
609 match float {
610 Some(FloatSide::InlineStart) => data.start_floats = data.start_floats.union(&size),
611 Some(FloatSide::InlineEnd) => data.end_floats = data.end_floats.union(&size),
612 None => {
613 data.max_size = data
614 .max_size
615 .max(data.start_floats.union(&data.end_floats).union(&size));
616 data.start_floats = ContentSizes::zero();
617 data.end_floats = ContentSizes::zero();
618 },
619 }
620 data
621 };
622 let data = if layout_context.use_rayon {
623 boxes
624 .par_iter()
625 .filter_map(get_box_info)
626 .collect::<Vec<_>>()
627 .into_iter()
628 .fold(AccumulatedData::default(), accumulate)
629 } else {
630 boxes
631 .iter()
632 .filter_map(get_box_info)
633 .fold(AccumulatedData::default(), accumulate)
634 };
635 InlineContentSizesResult {
636 depends_on_block_constraints: data.depends_on_block_constraints,
637 sizes: data.max_size_including_uncleared_floats(),
638 }
639}
640
641impl BlockContainer {
642 fn layout(
643 &self,
644 layout_context: &LayoutContext,
645 positioning_context: &mut PositioningContext,
646 containing_block: &ContainingBlock,
647 sequential_layout_state: Option<&mut SequentialLayoutState>,
648 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
649 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
650 ) -> CacheableLayoutResult {
651 match self {
652 BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
653 layout_context,
654 positioning_context,
655 child_boxes,
656 containing_block,
657 sequential_layout_state,
658 collapsible_with_parent_start_margin,
659 ignore_block_margins_for_stretch,
660 ),
661 BlockContainer::InlineFormattingContext(ifc) => ifc.layout(
662 layout_context,
663 positioning_context,
664 containing_block,
665 sequential_layout_state,
666 collapsible_with_parent_start_margin,
667 ),
668 }
669 }
670
671 #[inline]
672 pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
673 LayoutStyle::Default(&base.style)
674 }
675}
676
677impl ComputeInlineContentSizes for BlockContainer {
678 fn compute_inline_content_sizes(
679 &self,
680 layout_context: &LayoutContext,
681 constraint_space: &ConstraintSpace,
682 ) -> InlineContentSizesResult {
683 match &self {
684 Self::BlockLevelBoxes(boxes) => compute_inline_content_sizes_for_block_level_boxes(
685 boxes,
686 layout_context,
687 &constraint_space.into(),
688 ),
689 Self::InlineFormattingContext(context) => {
690 context.compute_inline_content_sizes(layout_context, constraint_space)
691 },
692 }
693 }
694}
695
696fn layout_block_level_children(
697 layout_context: &LayoutContext,
698 positioning_context: &mut PositioningContext,
699 child_boxes: &[ArcRefCell<BlockLevelBox>],
700 containing_block: &ContainingBlock,
701 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
702 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
703 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
704) -> CacheableLayoutResult {
705 let mut placement_state =
706 PlacementState::new(collapsible_with_parent_start_margin, containing_block);
707
708 let fragments = match sequential_layout_state {
709 Some(ref mut sequential_layout_state) => layout_block_level_children_sequentially(
710 layout_context,
711 positioning_context,
712 child_boxes,
713 containing_block,
714 sequential_layout_state,
715 &mut placement_state,
716 ignore_block_margins_for_stretch,
717 ),
718 None => layout_block_level_children_in_parallel(
719 layout_context,
720 positioning_context,
721 child_boxes,
722 containing_block,
723 &mut placement_state,
724 ignore_block_margins_for_stretch,
725 ),
726 };
727
728 let depends_on_block_constraints = fragments.iter().any(|fragment| {
729 fragment.base().is_some_and(|base| {
730 base.flags.contains(
731 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
732 )
733 })
734 });
735
736 let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish();
737 CacheableLayoutResult {
738 fragments,
739 content_block_size,
740 collapsible_margins_in_children,
741 baselines,
742 depends_on_block_constraints,
743 content_inline_size_for_table: None,
744 specific_layout_info: None,
745 }
746}
747
748fn layout_block_level_children_in_parallel(
749 layout_context: &LayoutContext,
750 positioning_context: &mut PositioningContext,
751 child_boxes: &[ArcRefCell<BlockLevelBox>],
752 containing_block: &ContainingBlock,
753 placement_state: &mut PlacementState,
754 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
755) -> Vec<Fragment> {
756 let mut layout_results: Vec<(Fragment, PositioningContext)> =
757 Vec::with_capacity(child_boxes.len());
758
759 child_boxes
760 .par_iter()
761 .map(|child_box| {
762 let mut child_positioning_context = PositioningContext::default();
763 let fragment = child_box.borrow().layout(
764 layout_context,
765 &mut child_positioning_context,
766 containing_block,
767 None,
768 None,
769 ignore_block_margins_for_stretch,
770 );
771 (fragment, child_positioning_context)
772 })
773 .collect_into_vec(&mut layout_results);
774
775 layout_results
776 .into_iter()
777 .map(|(mut fragment, mut child_positioning_context)| {
778 placement_state.place_fragment_and_update_baseline(&mut fragment, None);
779 child_positioning_context.adjust_static_position_of_hoisted_fragments(
780 &fragment,
781 PositioningContextLength::zero(),
782 );
783 positioning_context.append(child_positioning_context);
784 fragment
785 })
786 .collect()
787}
788
789fn layout_block_level_children_sequentially(
790 layout_context: &LayoutContext,
791 positioning_context: &mut PositioningContext,
792 child_boxes: &[ArcRefCell<BlockLevelBox>],
793 containing_block: &ContainingBlock,
794 sequential_layout_state: &mut SequentialLayoutState,
795 placement_state: &mut PlacementState,
796 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
797) -> Vec<Fragment> {
798 child_boxes
802 .iter()
803 .map(|child_box| {
804 let positioning_context_length_before_layout = positioning_context.len();
805 let mut fragment = child_box.borrow().layout(
806 layout_context,
807 positioning_context,
808 containing_block,
809 Some(&mut *sequential_layout_state),
810 Some(CollapsibleWithParentStartMargin(
811 placement_state.next_in_flow_margin_collapses_with_parent_start_margin,
812 )),
813 ignore_block_margins_for_stretch,
814 );
815
816 placement_state
817 .place_fragment_and_update_baseline(&mut fragment, Some(sequential_layout_state));
818 positioning_context.adjust_static_position_of_hoisted_fragments(
819 &fragment,
820 positioning_context_length_before_layout,
821 );
822
823 fragment
824 })
825 .collect()
826}
827
828impl BlockLevelBox {
829 fn layout(
830 &self,
831 layout_context: &LayoutContext,
832 positioning_context: &mut PositioningContext,
833 containing_block: &ContainingBlock,
834 sequential_layout_state: Option<&mut SequentialLayoutState>,
835 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
836 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
837 ) -> Fragment {
838 let fragment = match self {
839 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => Fragment::Box(
840 ArcRefCell::new(positioning_context.layout_maybe_position_relative_fragment(
841 layout_context,
842 containing_block,
843 base,
844 |positioning_context| {
845 layout_in_flow_non_replaced_block_level_same_formatting_context(
846 layout_context,
847 positioning_context,
848 containing_block,
849 base,
850 contents,
851 sequential_layout_state,
852 collapsible_with_parent_start_margin,
853 ignore_block_margins_for_stretch,
854 )
855 },
856 )),
857 ),
858 BlockLevelBox::Independent(independent) => Fragment::Box(ArcRefCell::new(
859 positioning_context.layout_maybe_position_relative_fragment(
860 layout_context,
861 containing_block,
862 &independent.base,
863 |positioning_context| {
864 independent.layout_in_flow_block_level(
865 layout_context,
866 positioning_context,
867 containing_block,
868 sequential_layout_state,
869 ignore_block_margins_for_stretch,
870 )
871 },
872 ),
873 )),
874 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
875 let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
879 box_.clone(),
880 PhysicalRect::zero(),
884 LogicalVec2 {
885 inline: AlignFlags::START,
886 block: AlignFlags::START,
887 },
888 containing_block.style.writing_mode,
889 );
890 let hoisted_fragment = hoisted_box.fragment.clone();
891 positioning_context.push(hoisted_box);
892 Fragment::AbsoluteOrFixedPositioned(hoisted_fragment)
893 },
894 BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(ArcRefCell::new(
895 float_box.layout(layout_context, positioning_context, containing_block),
896 )),
897 BlockLevelBox::OutsideMarker(outside_marker) => {
898 outside_marker.layout(layout_context, containing_block, positioning_context)
899 },
900 };
901
902 self.with_base(|base| base.set_fragment(fragment.clone()));
903
904 fragment
905 }
906
907 fn inline_content_sizes(
908 &self,
909 layout_context: &LayoutContext,
910 constraint_space: &ConstraintSpace,
911 ) -> InlineContentSizesResult {
912 let independent_formatting_context = match self {
913 BlockLevelBox::Independent(independent) => independent,
914 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => &box_.borrow().context,
915 BlockLevelBox::OutOfFlowFloatBox(float_box) => &float_box.contents,
916 BlockLevelBox::OutsideMarker(outside_marker) => {
917 return outside_marker.inline_content_sizes(layout_context, constraint_space);
918 },
919 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
920 return base.inline_content_sizes(layout_context, constraint_space, contents);
921 },
922 };
923 independent_formatting_context.inline_content_sizes(layout_context, constraint_space)
924 }
925}
926
927#[allow(clippy::too_many_arguments)]
933fn layout_in_flow_non_replaced_block_level_same_formatting_context(
934 layout_context: &LayoutContext,
935 positioning_context: &mut PositioningContext,
936 containing_block: &ContainingBlock,
937 base: &LayoutBoxBase,
938 contents: &BlockContainer,
939 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
940 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
941 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
942) -> BoxFragment {
943 let style = &base.style;
944 let layout_style = contents.layout_style(base);
945 let containing_block_writing_mode = containing_block.style.writing_mode;
946 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
947 base.inline_content_sizes(layout_context, constraint_space, contents)
948 .sizes
949 };
950 let ContainingBlockPaddingAndBorder {
951 containing_block: containing_block_for_children,
952 pbm,
953 block_sizes,
954 depends_on_block_constraints,
955 available_block_size,
956 justify_self,
957 ..
958 } = solve_containing_block_padding_and_border_for_in_flow_box(
959 containing_block,
960 &layout_style,
961 get_inline_content_sizes,
962 ignore_block_margins_for_stretch,
963 None,
964 );
965 let ResolvedMargins {
966 margin,
967 effective_margin_inline_start,
968 } = solve_margins(
969 containing_block,
970 &pbm,
971 containing_block_for_children.size.inline,
972 justify_self,
973 );
974
975 let computed_block_size = style.content_block_size();
976 let start_margin_can_collapse_with_children =
977 pbm.padding.block_start.is_zero() && pbm.border.block_start.is_zero();
978
979 let mut clearance = None;
980 let parent_containing_block_position_info;
981 match sequential_layout_state {
982 None => parent_containing_block_position_info = None,
983 Some(ref mut sequential_layout_state) => {
984 let clear =
985 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode);
986 let mut block_start_margin = CollapsedMargin::new(margin.block_start);
987
988 let collapsible_with_parent_start_margin = collapsible_with_parent_start_margin.expect(
1000 "We should know whether we are collapsing the block start margin with the parent \
1001 when laying out sequentially",
1002 ).0 && clear == Clear::None;
1003 if !collapsible_with_parent_start_margin && start_margin_can_collapse_with_children {
1004 if let BlockContainer::BlockLevelBoxes(child_boxes) = contents {
1005 BlockLevelBox::find_block_margin_collapsing_with_parent_from_slice(
1006 layout_context,
1007 child_boxes,
1008 &mut block_start_margin,
1009 &containing_block_for_children,
1010 );
1011 }
1012 }
1013
1014 clearance = sequential_layout_state.calculate_clearance(clear, &block_start_margin);
1016 if clearance.is_some() {
1017 sequential_layout_state.collapse_margins();
1018 }
1019 sequential_layout_state.adjoin_assign(&block_start_margin);
1020 if !start_margin_can_collapse_with_children {
1021 sequential_layout_state.collapse_margins();
1022 }
1023
1024 sequential_layout_state.advance_block_position(
1027 pbm.padding.block_start +
1028 pbm.border.block_start +
1029 clearance.unwrap_or_else(Au::zero),
1030 );
1031
1032 let inline_start = sequential_layout_state
1038 .floats
1039 .containing_block_info
1040 .inline_start +
1041 pbm.padding.inline_start +
1042 pbm.border.inline_start +
1043 effective_margin_inline_start;
1044 let new_cb_offsets = ContainingBlockPositionInfo {
1045 block_start: sequential_layout_state.bfc_relative_block_position,
1046 block_start_margins_not_collapsed: sequential_layout_state.current_margin,
1047 inline_start,
1048 inline_end: inline_start + containing_block_for_children.size.inline,
1049 };
1050 parent_containing_block_position_info = Some(
1051 sequential_layout_state.replace_containing_block_position_info(new_cb_offsets),
1052 );
1053 },
1054 };
1055
1056 let ignore_block_margins_for_stretch = LogicalSides1D::new(
1062 pbm.border.block_start.is_zero() && pbm.padding.block_start.is_zero(),
1063 pbm.border.block_end.is_zero() && pbm.padding.block_end.is_zero(),
1064 );
1065
1066 let flow_layout = contents.layout(
1067 layout_context,
1068 positioning_context,
1069 &containing_block_for_children,
1070 sequential_layout_state.as_deref_mut(),
1071 CollapsibleWithParentStartMargin(start_margin_can_collapse_with_children),
1072 ignore_block_margins_for_stretch,
1073 );
1074 let mut content_block_size: Au = flow_layout.content_block_size;
1075
1076 let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1078 let mut collapsible_margins_in_children = flow_layout.collapsible_margins_in_children;
1079 if start_margin_can_collapse_with_children {
1080 block_margins_collapsed_with_children
1081 .start
1082 .adjoin_assign(&collapsible_margins_in_children.start);
1083 if collapsible_margins_in_children.collapsed_through {
1084 block_margins_collapsed_with_children
1085 .start
1086 .adjoin_assign(&std::mem::replace(
1087 &mut collapsible_margins_in_children.end,
1088 CollapsedMargin::zero(),
1089 ));
1090 }
1091 }
1092
1093 let collapsed_through = collapsible_margins_in_children.collapsed_through &&
1094 pbm.padding_border_sums.block.is_zero() &&
1095 block_size_is_zero_or_intrinsic(computed_block_size, containing_block) &&
1096 block_size_is_zero_or_intrinsic(style.min_block_size(), containing_block);
1097 block_margins_collapsed_with_children.collapsed_through = collapsed_through;
1098
1099 let end_margin_can_collapse_with_children = collapsed_through ||
1100 (pbm.padding.block_end.is_zero() &&
1101 pbm.border.block_end.is_zero() &&
1102 !containing_block_for_children.size.block.is_definite());
1103 if end_margin_can_collapse_with_children {
1104 block_margins_collapsed_with_children
1105 .end
1106 .adjoin_assign(&collapsible_margins_in_children.end);
1107 } else {
1108 content_block_size += collapsible_margins_in_children.end.solve();
1109 }
1110
1111 let block_size = block_sizes.resolve(
1112 Direction::Block,
1113 Size::FitContent,
1114 Au::zero,
1115 available_block_size,
1116 || content_block_size.into(),
1117 false, );
1119
1120 if let Some(ref mut sequential_layout_state) = sequential_layout_state {
1121 sequential_layout_state
1124 .replace_containing_block_position_info(parent_containing_block_position_info.unwrap());
1125
1126 sequential_layout_state.advance_block_position(
1136 block_size - content_block_size + pbm.padding.block_end + pbm.border.block_end,
1137 );
1138
1139 if !end_margin_can_collapse_with_children {
1140 sequential_layout_state.collapse_margins();
1141 }
1142 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1143 }
1144
1145 let content_rect = LogicalRect {
1146 start_corner: LogicalVec2 {
1147 block: (pbm.padding.block_start +
1148 pbm.border.block_start +
1149 clearance.unwrap_or_else(Au::zero)),
1150 inline: pbm.padding.inline_start +
1151 pbm.border.inline_start +
1152 effective_margin_inline_start,
1153 },
1154 size: LogicalVec2 {
1155 block: block_size,
1156 inline: containing_block_for_children.size.inline,
1157 },
1158 };
1159
1160 let mut base_fragment_info = base.base_fragment_info;
1161 if depends_on_block_constraints {
1162 base_fragment_info
1163 .flags
1164 .insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM);
1165 }
1166
1167 BoxFragment::new(
1168 base_fragment_info,
1169 style.clone(),
1170 flow_layout.fragments,
1171 content_rect.as_physical(Some(containing_block)),
1172 pbm.padding.to_physical(containing_block_writing_mode),
1173 pbm.border.to_physical(containing_block_writing_mode),
1174 margin.to_physical(containing_block_writing_mode),
1175 flow_layout.specific_layout_info,
1176 )
1177 .with_baselines(flow_layout.baselines)
1178 .with_block_level_layout_info(block_margins_collapsed_with_children, clearance)
1179}
1180
1181impl IndependentFormattingContext {
1182 pub(crate) fn layout_in_flow_block_level(
1190 &self,
1191 layout_context: &LayoutContext,
1192 positioning_context: &mut PositioningContext,
1193 containing_block: &ContainingBlock,
1194 sequential_layout_state: Option<&mut SequentialLayoutState>,
1195 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1196 ) -> BoxFragment {
1197 if let Some(sequential_layout_state) = sequential_layout_state {
1198 return self.layout_in_flow_block_level_sequentially(
1199 layout_context,
1200 positioning_context,
1201 containing_block,
1202 sequential_layout_state,
1203 ignore_block_margins_for_stretch,
1204 );
1205 }
1206
1207 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
1208 self.inline_content_sizes(layout_context, constraint_space)
1209 .sizes
1210 };
1211 let layout_style = self.layout_style();
1212 let ContainingBlockPaddingAndBorder {
1213 containing_block: containing_block_for_children,
1214 pbm,
1215 block_sizes,
1216 depends_on_block_constraints,
1217 available_block_size,
1218 justify_self,
1219 preferred_aspect_ratio,
1220 } = solve_containing_block_padding_and_border_for_in_flow_box(
1221 containing_block,
1222 &layout_style,
1223 get_inline_content_sizes,
1224 ignore_block_margins_for_stretch,
1225 Some(self),
1226 );
1227
1228 let lazy_block_size = LazySize::new(
1229 &block_sizes,
1230 Direction::Block,
1231 Size::FitContent,
1232 Au::zero,
1233 available_block_size,
1234 layout_style.is_table(),
1235 );
1236
1237 let layout = self.layout(
1238 layout_context,
1239 positioning_context,
1240 &containing_block_for_children,
1241 containing_block,
1242 preferred_aspect_ratio,
1243 &lazy_block_size,
1244 );
1245
1246 let inline_size = layout
1247 .content_inline_size_for_table
1248 .unwrap_or(containing_block_for_children.size.inline);
1249 let block_size = lazy_block_size.resolve(|| layout.content_block_size);
1250
1251 let ResolvedMargins {
1252 margin,
1253 effective_margin_inline_start,
1254 } = solve_margins(containing_block, &pbm, inline_size, justify_self);
1255
1256 let content_rect = LogicalRect {
1257 start_corner: LogicalVec2 {
1258 block: pbm.padding.block_start + pbm.border.block_start,
1259 inline: pbm.padding.inline_start +
1260 pbm.border.inline_start +
1261 effective_margin_inline_start,
1262 },
1263 size: LogicalVec2 {
1264 block: block_size,
1265 inline: inline_size,
1266 },
1267 };
1268
1269 let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1270 let containing_block_writing_mode = containing_block.style.writing_mode;
1271
1272 let mut base_fragment_info = self.base.base_fragment_info;
1273 if depends_on_block_constraints {
1274 base_fragment_info.flags.insert(
1275 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1276 );
1277 }
1278 BoxFragment::new(
1279 base_fragment_info,
1280 self.base.style.clone(),
1281 layout.fragments,
1282 content_rect.as_physical(Some(containing_block)),
1283 pbm.padding.to_physical(containing_block_writing_mode),
1284 pbm.border.to_physical(containing_block_writing_mode),
1285 margin.to_physical(containing_block_writing_mode),
1286 layout.specific_layout_info,
1287 )
1288 .with_baselines(layout.baselines)
1289 .with_block_level_layout_info(block_margins_collapsed_with_children, None)
1290 }
1291
1292 fn layout_in_flow_block_level_sequentially(
1296 &self,
1297 layout_context: &LayoutContext<'_>,
1298 positioning_context: &mut PositioningContext,
1299 containing_block: &ContainingBlock<'_>,
1300 sequential_layout_state: &mut SequentialLayoutState,
1301 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1302 ) -> BoxFragment {
1303 let style = &self.base.style;
1304 let containing_block_writing_mode = containing_block.style.writing_mode;
1305 let ContentBoxSizesAndPBM {
1306 content_box_sizes,
1307 pbm,
1308 depends_on_block_constraints,
1309 ..
1310 } = self
1311 .layout_style()
1312 .content_box_sizes_and_padding_border_margin(&containing_block.into());
1313
1314 let (margin_block_start, margin_block_end) =
1315 solve_block_margins_for_in_flow_block_level(&pbm);
1316 let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
1317
1318 let mut content_size;
1329 let mut layout;
1330 let mut placement_rect;
1331
1332 let clear_position = sequential_layout_state.calculate_clear_position(
1336 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
1337 &collapsed_margin_block_start,
1338 );
1339 let ceiling = clear_position.unwrap_or_else(|| {
1340 sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
1341 });
1342
1343 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1345 let available_block_size = containing_block
1346 .size
1347 .block
1348 .to_definite()
1349 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1350 let is_table = self.is_table();
1351 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
1352 let tentative_block_content_size =
1353 self.tentative_block_content_size(preferred_aspect_ratio);
1354 let (preferred_block_size, min_block_size, max_block_size) =
1355 if let Some(block_content_size) = tentative_block_content_size {
1356 let (preferred, min, max) = content_box_sizes.block.resolve_each(
1357 Size::FitContent,
1358 Au::zero,
1359 available_block_size,
1360 || block_content_size,
1361 is_table,
1362 );
1363 (Some(preferred), min, max)
1364 } else {
1365 content_box_sizes.block.resolve_each_extrinsic(
1366 Size::FitContent,
1367 Au::zero(),
1368 available_block_size,
1369 )
1370 };
1371 let tentative_block_size =
1372 SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
1373
1374 let get_inline_content_sizes = || {
1376 let constraint_space = ConstraintSpace::new(
1377 tentative_block_size,
1378 style.writing_mode,
1379 preferred_aspect_ratio,
1380 );
1381 self.inline_content_sizes(layout_context, &constraint_space)
1382 .sizes
1383 };
1384
1385 let justify_self = resolve_justify_self(style, containing_block.style);
1386 let is_replaced = self.is_replaced();
1387 let compute_inline_size = |stretch_size| {
1388 content_box_sizes.inline.resolve(
1389 Direction::Inline,
1390 automatic_inline_size(justify_self, is_table, is_replaced),
1391 Au::zero,
1392 Some(stretch_size),
1393 get_inline_content_sizes,
1394 is_table,
1395 )
1396 };
1397
1398 let get_lazy_block_size = || {
1399 LazySize::new(
1400 &content_box_sizes.block,
1401 Direction::Block,
1402 Size::FitContent,
1403 Au::zero,
1404 available_block_size,
1405 is_table,
1406 )
1407 };
1408
1409 let inline_size_with_no_available_space = compute_inline_size(Au::zero());
1418 if inline_size_with_no_available_space == compute_inline_size(MAX_AU) {
1419 let inline_size = inline_size_with_no_available_space;
1423 let lazy_block_size = get_lazy_block_size();
1424 layout = self.layout(
1425 layout_context,
1426 positioning_context,
1427 &ContainingBlock {
1428 size: ContainingBlockSize {
1429 inline: inline_size,
1430 block: tentative_block_size,
1431 },
1432 style,
1433 },
1434 containing_block,
1435 preferred_aspect_ratio,
1436 &lazy_block_size,
1437 );
1438
1439 content_size = LogicalVec2 {
1440 block: lazy_block_size.resolve(|| layout.content_block_size),
1441 inline: layout.content_inline_size_for_table.unwrap_or(inline_size),
1442 };
1443
1444 let mut placement = PlacementAmongFloats::new(
1445 &sequential_layout_state.floats,
1446 ceiling,
1447 content_size + pbm.padding_border_sums,
1448 &pbm,
1449 );
1450 placement_rect = placement.place();
1451 } else {
1452 let minimum_size_of_block = LogicalVec2 {
1458 inline: inline_size_with_no_available_space,
1462 block: match tentative_block_size {
1463 SizeConstraint::Definite(size) if max_block_size.is_some() => size,
1466 _ => min_block_size,
1469 },
1470 } + pbm.padding_border_sums;
1471 let mut placement = PlacementAmongFloats::new(
1472 &sequential_layout_state.floats,
1473 ceiling,
1474 minimum_size_of_block,
1475 &pbm,
1476 );
1477
1478 loop {
1479 placement_rect = placement.place();
1481 let available_inline_size =
1482 placement_rect.size.inline - pbm.padding_border_sums.inline;
1483 let proposed_inline_size = compute_inline_size(available_inline_size);
1484
1485 let positioning_context_length = positioning_context.len();
1489 let lazy_block_size = get_lazy_block_size();
1490 layout = self.layout(
1491 layout_context,
1492 positioning_context,
1493 &ContainingBlock {
1494 size: ContainingBlockSize {
1495 inline: proposed_inline_size,
1496 block: tentative_block_size,
1497 },
1498 style,
1499 },
1500 containing_block,
1501 preferred_aspect_ratio,
1502 &lazy_block_size,
1503 );
1504
1505 let inline_size = if let Some(inline_size) = layout.content_inline_size_for_table {
1506 debug_assert!(inline_size < proposed_inline_size);
1511 inline_size
1512 } else {
1513 proposed_inline_size
1514 };
1515 content_size = LogicalVec2 {
1516 block: lazy_block_size.resolve(|| layout.content_block_size),
1517 inline: inline_size,
1518 };
1519
1520 if placement.try_to_expand_for_auto_block_size(
1524 content_size.block + pbm.padding_border_sums.block,
1525 &placement_rect.size,
1526 ) {
1527 break;
1528 }
1529
1530 positioning_context.truncate(&positioning_context_length);
1534 }
1535 }
1536
1537 let has_clearance = clear_position.is_some() || placement_rect.start_corner.block > ceiling;
1541 let clearance = has_clearance.then(|| {
1542 placement_rect.start_corner.block -
1543 sequential_layout_state
1544 .position_with_zero_clearance(&collapsed_margin_block_start)
1545 });
1546
1547 let ((margin_inline_start, margin_inline_end), effective_margin_inline_start) =
1548 solve_inline_margins_avoiding_floats(
1549 sequential_layout_state,
1550 containing_block,
1551 &pbm,
1552 content_size.inline + pbm.padding_border_sums.inline,
1553 placement_rect,
1554 justify_self,
1555 );
1556
1557 let margin = LogicalSides {
1558 inline_start: margin_inline_start,
1559 inline_end: margin_inline_end,
1560 block_start: margin_block_start,
1561 block_end: margin_block_end,
1562 };
1563
1564 if clearance.is_some() {
1567 sequential_layout_state.collapse_margins();
1568 }
1569 sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
1570
1571 sequential_layout_state.collapse_margins();
1573 sequential_layout_state.advance_block_position(
1574 pbm.padding_border_sums.block + content_size.block + clearance.unwrap_or_else(Au::zero),
1575 );
1576 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1577
1578 let content_rect = LogicalRect {
1579 start_corner: LogicalVec2 {
1580 block: pbm.padding.block_start +
1581 pbm.border.block_start +
1582 clearance.unwrap_or_else(Au::zero),
1583 inline: pbm.padding.inline_start +
1584 pbm.border.inline_start +
1585 effective_margin_inline_start,
1586 },
1587 size: content_size,
1588 };
1589
1590 let mut base_fragment_info = self.base.base_fragment_info;
1591 if depends_on_block_constraints {
1592 base_fragment_info.flags.insert(
1593 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1594 );
1595 }
1596
1597 BoxFragment::new(
1598 base_fragment_info,
1599 style.clone(),
1600 layout.fragments,
1601 content_rect.as_physical(Some(containing_block)),
1602 pbm.padding.to_physical(containing_block_writing_mode),
1603 pbm.border.to_physical(containing_block_writing_mode),
1604 margin.to_physical(containing_block_writing_mode),
1605 layout.specific_layout_info,
1606 )
1607 .with_baselines(layout.baselines)
1608 .with_block_level_layout_info(CollapsedBlockMargins::from_margin(&margin), clearance)
1609 }
1610}
1611
1612struct ContainingBlockPaddingAndBorder<'a> {
1613 containing_block: ContainingBlock<'a>,
1614 pbm: PaddingBorderMargin,
1615 block_sizes: Sizes,
1616 depends_on_block_constraints: bool,
1617 available_block_size: Option<Au>,
1618 justify_self: AlignFlags,
1619 preferred_aspect_ratio: Option<AspectRatio>,
1620}
1621
1622struct ResolvedMargins {
1623 pub margin: LogicalSides<Au>,
1625
1626 pub effective_margin_inline_start: Au,
1633}
1634
1635fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
1641 containing_block: &ContainingBlock<'_>,
1642 layout_style: &'a LayoutStyle,
1643 get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
1644 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1645 context: Option<&IndependentFormattingContext>,
1646) -> ContainingBlockPaddingAndBorder<'a> {
1647 let style = layout_style.style();
1648 if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
1649 let containing_block_for_children = ContainingBlock {
1653 size: ContainingBlockSize {
1654 inline: containing_block.size.inline,
1655 block: containing_block.size.block,
1656 },
1657 style,
1658 };
1659 return ContainingBlockPaddingAndBorder {
1662 containing_block: containing_block_for_children,
1663 pbm: PaddingBorderMargin::zero(),
1664 block_sizes: Sizes::default(),
1665 depends_on_block_constraints: false,
1666 available_block_size: None,
1669 justify_self: AlignFlags::NORMAL,
1672 preferred_aspect_ratio: None,
1673 };
1674 }
1675
1676 let ContentBoxSizesAndPBM {
1677 content_box_sizes,
1678 pbm,
1679 depends_on_block_constraints,
1680 ..
1681 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
1682
1683 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1684 let writing_mode = style.writing_mode;
1685 let available_inline_size = Au::zero().max(containing_block.size.inline - pbm_sums.inline);
1686 let available_block_size = containing_block
1687 .size
1688 .block
1689 .to_definite()
1690 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1691
1692 let preferred_aspect_ratio =
1695 context.and_then(|context| context.preferred_aspect_ratio(&pbm.padding_border_sums));
1696 let is_table = layout_style.is_table();
1697
1698 let tentative_block_content_size =
1701 context.and_then(|context| context.tentative_block_content_size(preferred_aspect_ratio));
1702 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
1703 SizeConstraint::Definite(content_box_sizes.block.resolve(
1704 Direction::Block,
1705 Size::FitContent,
1706 Au::zero,
1707 available_block_size,
1708 || block_content_size,
1709 is_table,
1710 ))
1711 } else {
1712 content_box_sizes.block.resolve_extrinsic(
1713 Size::FitContent,
1714 Au::zero(),
1715 available_block_size,
1716 )
1717 };
1718
1719 let get_inline_content_sizes = || {
1722 get_inline_content_sizes(&ConstraintSpace::new(
1723 tentative_block_size,
1724 writing_mode,
1725 preferred_aspect_ratio,
1726 ))
1727 };
1728 let justify_self = resolve_justify_self(style, containing_block.style);
1729 let is_replaced = context.is_some_and(|context| context.is_replaced());
1730 let inline_size = content_box_sizes.inline.resolve(
1731 Direction::Inline,
1732 automatic_inline_size(justify_self, is_table, is_replaced),
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.0 {
1809 AlignFlags::AUTO => parent_style.clone_justify_items().computed.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 is_table: bool,
1832 is_replaced: bool,
1833) -> Size<T> {
1834 match justify_self {
1835 AlignFlags::STRETCH => Size::Stretch,
1836 AlignFlags::NORMAL if !is_table && !is_replaced => Size::Stretch,
1837 _ => Size::FitContent,
1838 }
1839}
1840
1841fn justify_self_alignment(
1848 containing_block: &ContainingBlock,
1849 free_space: Au,
1850 justify_self: AlignFlags,
1851) -> Au {
1852 let mut alignment = justify_self.value();
1853 let is_safe = justify_self.flags() == AlignFlags::SAFE || alignment == AlignFlags::NORMAL;
1854 if is_safe && free_space <= Au::zero() {
1855 alignment = AlignFlags::START
1856 }
1857 match alignment {
1858 AlignFlags::NORMAL => {},
1859 AlignFlags::CENTER => return free_space / 2,
1860 AlignFlags::END => return free_space,
1861 _ => return Au::zero(),
1862 }
1863
1864 let style = containing_block.style;
1866 match style.clone_text_align() {
1867 TextAlignKeyword::MozCenter => free_space / 2,
1868 TextAlignKeyword::MozLeft if !style.writing_mode.line_left_is_inline_start() => free_space,
1869 TextAlignKeyword::MozRight if style.writing_mode.line_left_is_inline_start() => free_space,
1870 _ => Au::zero(),
1871 }
1872}
1873
1874fn solve_inline_margins_for_in_flow_block_level(
1887 containing_block: &ContainingBlock,
1888 pbm: &PaddingBorderMargin,
1889 inline_size: Au,
1890 justify_self: AlignFlags,
1891) -> ((Au, Au), Au) {
1892 let free_space = containing_block.size.inline - pbm.padding_border_sums.inline - inline_size;
1893 let mut justification = Au::zero();
1894 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1895 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1896 let start = Au::zero().max(free_space / 2);
1897 (start, free_space - start)
1898 },
1899 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => {
1900 (Au::zero().max(free_space - end), end)
1901 },
1902 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, free_space - start),
1903 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1904 justification =
1909 justify_self_alignment(containing_block, free_space - start - end, justify_self);
1910 (start, end)
1911 },
1912 };
1913 let effective_margin_inline_start = inline_margins.0 + justification;
1914 (inline_margins, effective_margin_inline_start)
1915}
1916
1917fn solve_inline_margins_avoiding_floats(
1927 sequential_layout_state: &SequentialLayoutState,
1928 containing_block: &ContainingBlock,
1929 pbm: &PaddingBorderMargin,
1930 inline_size: Au,
1931 placement_rect: LogicalRect<Au>,
1932 justify_self: AlignFlags,
1933) -> ((Au, Au), Au) {
1934 let free_space = Au::zero().max(placement_rect.size.inline - inline_size);
1938 let cb_info = &sequential_layout_state.floats.containing_block_info;
1939 let start_adjustment = placement_rect.start_corner.inline - cb_info.inline_start;
1940 let end_adjustment = cb_info.inline_end - placement_rect.max_inline_position();
1941 let mut justification = Au::zero();
1942 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1943 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1944 let half = free_space / 2;
1945 (start_adjustment + half, end_adjustment + free_space - half)
1946 },
1947 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (start_adjustment + free_space, end),
1948 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, end_adjustment + free_space),
1949 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1950 justification = justify_self_alignment(containing_block, free_space, justify_self);
1956 (start, end)
1957 },
1958 };
1959 let effective_margin_inline_start = inline_margins.0.max(start_adjustment) + justification;
1960 (inline_margins, effective_margin_inline_start)
1961}
1962
1963struct PlacementState<'container> {
1968 next_in_flow_margin_collapses_with_parent_start_margin: bool,
1969 last_in_flow_margin_collapses_with_parent_end_margin: bool,
1970 start_margin: CollapsedMargin,
1971 current_margin: CollapsedMargin,
1972 current_block_direction_position: Au,
1973 inflow_baselines: Baselines,
1974 is_inline_block_context: bool,
1975
1976 marker_block_size: Option<Au>,
1981
1982 containing_block: &'container ContainingBlock<'container>,
1985}
1986
1987impl<'container> PlacementState<'container> {
1988 fn new(
1989 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1990 containing_block: &'container ContainingBlock<'container>,
1991 ) -> PlacementState<'container> {
1992 let is_inline_block_context =
1993 containing_block.style.get_box().clone_display() == Display::InlineBlock;
1994 PlacementState {
1995 next_in_flow_margin_collapses_with_parent_start_margin:
1996 collapsible_with_parent_start_margin.0,
1997 last_in_flow_margin_collapses_with_parent_end_margin: true,
1998 start_margin: CollapsedMargin::zero(),
1999 current_margin: CollapsedMargin::zero(),
2000 current_block_direction_position: Au::zero(),
2001 inflow_baselines: Baselines::default(),
2002 is_inline_block_context,
2003 marker_block_size: None,
2004 containing_block,
2005 }
2006 }
2007
2008 fn place_fragment_and_update_baseline(
2009 &mut self,
2010 fragment: &mut Fragment,
2011 sequential_layout_state: Option<&mut SequentialLayoutState>,
2012 ) {
2013 self.place_fragment(fragment, sequential_layout_state);
2014
2015 let box_fragment = match fragment {
2016 Fragment::Box(box_fragment) => box_fragment,
2017 _ => return,
2018 };
2019 let box_fragment = box_fragment.borrow();
2020
2021 if self.is_inline_block_context && box_fragment.is_table_wrapper() {
2026 return;
2027 }
2028
2029 let box_block_offset = box_fragment
2030 .content_rect
2031 .origin
2032 .to_logical(self.containing_block)
2033 .block;
2034 let box_fragment_baselines =
2035 box_fragment.baselines(self.containing_block.style.writing_mode);
2036 if let (None, Some(first)) = (self.inflow_baselines.first, box_fragment_baselines.first) {
2037 self.inflow_baselines.first = Some(first + box_block_offset);
2038 }
2039 if let Some(last) = box_fragment_baselines.last {
2040 self.inflow_baselines.last = Some(last + box_block_offset);
2041 }
2042 }
2043
2044 fn place_fragment(
2047 &mut self,
2048 fragment: &mut Fragment,
2049 sequential_layout_state: Option<&mut SequentialLayoutState>,
2050 ) {
2051 match fragment {
2052 Fragment::Box(fragment) => {
2053 let fragment = &mut *fragment.borrow_mut();
2062 let is_outside_marker = fragment
2063 .base
2064 .flags
2065 .contains(FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER);
2066 if is_outside_marker {
2067 assert!(self.marker_block_size.is_none());
2068 self.marker_block_size = Some(
2069 fragment
2070 .content_rect
2071 .size
2072 .to_logical(self.containing_block.style.writing_mode)
2073 .block,
2074 );
2075 return;
2076 }
2077
2078 let BlockLevelLayoutInfo {
2079 clearance,
2080 block_margins_collapsed_with_children: fragment_block_margins,
2081 } = &**fragment
2082 .block_level_layout_info
2083 .as_ref()
2084 .expect("A block-level fragment should have a BlockLevelLayoutInfo.");
2085 let mut fragment_block_size = fragment
2086 .border_rect()
2087 .size
2088 .to_logical(self.containing_block.style.writing_mode)
2089 .block;
2090
2091 if let Some(clearance) = *clearance {
2097 fragment_block_size += clearance;
2098 self.current_block_direction_position += self.current_margin.solve();
2103 self.current_margin = CollapsedMargin::zero();
2104 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2105 if fragment_block_margins.collapsed_through {
2106 self.last_in_flow_margin_collapses_with_parent_end_margin = false;
2107 }
2108 } else if !fragment_block_margins.collapsed_through {
2109 self.last_in_flow_margin_collapses_with_parent_end_margin = true;
2110 }
2111
2112 if self.next_in_flow_margin_collapses_with_parent_start_margin {
2113 debug_assert!(self.current_margin.solve().is_zero());
2114 self.start_margin
2115 .adjoin_assign(&fragment_block_margins.start);
2116 if fragment_block_margins.collapsed_through {
2117 self.start_margin.adjoin_assign(&fragment_block_margins.end);
2118 return;
2119 }
2120 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2121 } else {
2122 self.current_margin
2123 .adjoin_assign(&fragment_block_margins.start);
2124 }
2125
2126 fragment.content_rect.origin += LogicalVec2 {
2127 inline: Au::zero(),
2128 block: self.current_margin.solve() + self.current_block_direction_position,
2129 }
2130 .to_physical_size(self.containing_block.style.writing_mode);
2131
2132 if fragment_block_margins.collapsed_through {
2133 self.current_block_direction_position += fragment_block_size;
2136 self.current_margin
2137 .adjoin_assign(&fragment_block_margins.end);
2138 } else {
2139 self.current_block_direction_position +=
2140 self.current_margin.solve() + fragment_block_size;
2141 self.current_margin = fragment_block_margins.end;
2142 }
2143 },
2144 Fragment::AbsoluteOrFixedPositioned(fragment) => {
2145 fragment.borrow_mut().static_position_rect = LogicalRect {
2148 start_corner: LogicalVec2 {
2149 block: (self.current_margin.solve() +
2150 self.current_block_direction_position),
2151 inline: Au::zero(),
2152 },
2153 size: LogicalVec2::zero(),
2154 }
2155 .as_physical(Some(self.containing_block));
2156 },
2157 Fragment::Float(box_fragment) => {
2158 let sequential_layout_state = sequential_layout_state
2159 .expect("Found float fragment without SequentialLayoutState");
2160 let block_offset_from_containing_block_top =
2161 self.current_block_direction_position + self.current_margin.solve();
2162 let box_fragment = &mut *box_fragment.borrow_mut();
2163 sequential_layout_state.place_float_fragment(
2164 box_fragment,
2165 self.containing_block,
2166 self.start_margin,
2167 block_offset_from_containing_block_top,
2168 );
2169 },
2170 Fragment::Positioning(_) => {},
2171 _ => unreachable!(),
2172 }
2173 }
2174
2175 fn finish(mut self) -> (Au, CollapsedBlockMargins, Baselines) {
2176 if !self.last_in_flow_margin_collapses_with_parent_end_margin {
2177 self.current_block_direction_position += self.current_margin.solve();
2178 self.current_margin = CollapsedMargin::zero();
2179 }
2180 let (total_block_size, collapsed_through) = match self.marker_block_size {
2181 Some(marker_block_size) => (
2182 self.current_block_direction_position.max(marker_block_size),
2183 false,
2186 ),
2187 None => (
2188 self.current_block_direction_position,
2189 self.next_in_flow_margin_collapses_with_parent_start_margin,
2190 ),
2191 };
2192
2193 (
2194 total_block_size,
2195 CollapsedBlockMargins {
2196 collapsed_through,
2197 start: self.start_margin,
2198 end: self.current_margin,
2199 },
2200 self.inflow_baselines,
2201 )
2202 }
2203}
2204
2205fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &ContainingBlock) -> bool {
2206 match size {
2207 StyleSize::Auto |
2208 StyleSize::MinContent |
2209 StyleSize::MaxContent |
2210 StyleSize::FitContent |
2211 StyleSize::FitContentFunction(_) => true,
2212 StyleSize::Stretch => {
2213 !containing_block.size.block.is_definite()
2215 },
2216 StyleSize::LengthPercentage(lp) => {
2217 lp.is_definitely_zero() ||
2219 (lp.0.has_percentage() && !containing_block.size.block.is_definite())
2220 },
2221 StyleSize::AnchorSizeFunction(_) | StyleSize::AnchorContainingCalcFunction(_) => {
2222 unreachable!("anchor-size() should be disabled")
2223 },
2224 }
2225}
2226
2227pub(crate) struct IndependentFloatOrAtomicLayoutResult {
2228 pub fragment: BoxFragment,
2229 pub baselines: Baselines,
2230 pub pbm_sums: LogicalSides<Au>,
2231}
2232
2233impl IndependentFormattingContext {
2234 pub(crate) fn layout_float_or_atomic_inline(
2235 &self,
2236 layout_context: &LayoutContext,
2237 child_positioning_context: &mut PositioningContext,
2238 containing_block: &ContainingBlock,
2239 ) -> IndependentFloatOrAtomicLayoutResult {
2240 let style = self.style();
2241 let writing_mode = style.writing_mode;
2242 let container_writing_mode = containing_block.style.writing_mode;
2243 let layout_style = self.layout_style();
2244 let content_box_sizes_and_pbm =
2245 layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
2246 let pbm = &content_box_sizes_and_pbm.pbm;
2247 let margin = pbm.margin.auto_is(Au::zero);
2248 let pbm_sums = pbm.padding + pbm.border + margin;
2249 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
2250 let is_table = self.is_table();
2251
2252 let available_inline_size =
2253 Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
2254 let available_block_size = containing_block
2255 .size
2256 .block
2257 .to_definite()
2258 .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
2259
2260 let tentative_block_content_size =
2261 self.tentative_block_content_size(preferred_aspect_ratio);
2262 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
2263 SizeConstraint::Definite(content_box_sizes_and_pbm.content_box_sizes.block.resolve(
2264 Direction::Block,
2265 Size::FitContent,
2266 Au::zero,
2267 available_block_size,
2268 || block_content_size,
2269 is_table,
2270 ))
2271 } else {
2272 content_box_sizes_and_pbm
2273 .content_box_sizes
2274 .block
2275 .resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size)
2276 };
2277
2278 let get_content_size = || {
2279 let constraint_space =
2280 ConstraintSpace::new(tentative_block_size, writing_mode, preferred_aspect_ratio);
2281 self.inline_content_sizes(layout_context, &constraint_space)
2282 .sizes
2283 };
2284
2285 let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
2286 Direction::Inline,
2287 Size::FitContent,
2288 Au::zero,
2289 Some(available_inline_size),
2290 get_content_size,
2291 is_table,
2292 );
2293
2294 let containing_block_for_children = ContainingBlock {
2295 size: ContainingBlockSize {
2296 inline: inline_size,
2297 block: tentative_block_size,
2298 },
2299 style,
2300 };
2301 assert_eq!(
2302 container_writing_mode.is_horizontal(),
2303 writing_mode.is_horizontal(),
2304 "Mixed horizontal and vertical writing modes are not supported yet"
2305 );
2306
2307 let lazy_block_size = LazySize::new(
2308 &content_box_sizes_and_pbm.content_box_sizes.block,
2309 Direction::Block,
2310 Size::FitContent,
2311 Au::zero,
2312 available_block_size,
2313 is_table,
2314 );
2315
2316 let CacheableLayoutResult {
2317 content_inline_size_for_table,
2318 content_block_size,
2319 fragments,
2320 baselines,
2321 specific_layout_info,
2322 ..
2323 } = self.layout(
2324 layout_context,
2325 child_positioning_context,
2326 &containing_block_for_children,
2327 containing_block,
2328 preferred_aspect_ratio,
2329 &lazy_block_size,
2330 );
2331
2332 let content_size = LogicalVec2 {
2333 inline: content_inline_size_for_table.unwrap_or(inline_size),
2334 block: lazy_block_size.resolve(|| content_block_size),
2335 }
2336 .to_physical_size(container_writing_mode);
2337 let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
2338
2339 let mut base_fragment_info = self.base_fragment_info();
2340 if content_box_sizes_and_pbm.depends_on_block_constraints {
2341 base_fragment_info.flags.insert(
2342 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2343 );
2344 }
2345
2346 let fragment = BoxFragment::new(
2350 base_fragment_info,
2351 style.clone(),
2352 fragments,
2353 content_rect,
2354 pbm.padding.to_physical(container_writing_mode),
2355 pbm.border.to_physical(container_writing_mode),
2356 margin.to_physical(container_writing_mode),
2357 specific_layout_info,
2358 );
2359
2360 IndependentFloatOrAtomicLayoutResult {
2361 fragment,
2362 baselines,
2363 pbm_sums,
2364 }
2365 }
2366}