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 FnOnce(&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,
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 let container_writing_mode = containing_block.style.writing_mode;
512 Some((
513 inline_content_sizes_result,
514 FloatSide::from_style_and_container_writing_mode(style, container_writing_mode),
515 Clear::from_style_and_container_writing_mode(style, container_writing_mode),
516 ))
517 },
518 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
519 let inline_content_sizes_result = sizing::outer_inline(
520 &contents.layout_style(base),
521 containing_block,
522 &LogicalVec2::zero(),
523 false, false, !matches!(base.style.pseudo(), Some(PseudoElement::ServoAnonymousBox)),
526 |_| None, |constraint_space| {
528 base.inline_content_sizes(layout_context, constraint_space, contents)
529 },
530 |_aspect_ratio| None,
531 );
532 Some((inline_content_sizes_result, None, Clear::Both))
536 },
537 BlockLevelBox::Independent(independent) => {
538 let inline_content_sizes_result = independent.outer_inline_content_sizes(
539 layout_context,
540 containing_block,
541 &LogicalVec2::zero(),
542 false, );
544 Some((
545 inline_content_sizes_result,
546 None,
547 Clear::from_style_and_container_writing_mode(
548 independent.style(),
549 containing_block.style.writing_mode,
550 ),
551 ))
552 },
553 }
554 };
555
556 #[derive(Default)]
559 struct AccumulatedData {
560 depends_on_block_constraints: bool,
562 max_size: ContentSizes,
564 start_floats: ContentSizes,
567 end_floats: ContentSizes,
570 }
571
572 impl AccumulatedData {
573 fn max_size_including_uncleared_floats(&self) -> ContentSizes {
574 self.max_size.max(self.start_floats.union(&self.end_floats))
575 }
576 fn clear_floats(&mut self, clear: Clear) {
577 match clear {
578 Clear::InlineStart => {
579 self.max_size = self.max_size_including_uncleared_floats();
580 self.start_floats = ContentSizes::zero();
581 },
582 Clear::InlineEnd => {
583 self.max_size = self.max_size_including_uncleared_floats();
584 self.end_floats = ContentSizes::zero();
585 },
586 Clear::Both => {
587 self.max_size = self.max_size_including_uncleared_floats();
588 self.start_floats = ContentSizes::zero();
589 self.end_floats = ContentSizes::zero();
590 },
591 Clear::None => {},
592 };
593 }
594 }
595
596 let accumulate =
597 |mut data: AccumulatedData,
598 (inline_content_sizes_result, float, clear): (InlineContentSizesResult, _, _)| {
599 let size = inline_content_sizes_result.sizes.max(ContentSizes::zero());
600 let depends_on_block_constraints =
601 inline_content_sizes_result.depends_on_block_constraints;
602 data.depends_on_block_constraints |= depends_on_block_constraints;
603 data.clear_floats(clear);
604 match float {
605 Some(FloatSide::InlineStart) => data.start_floats = data.start_floats.union(&size),
606 Some(FloatSide::InlineEnd) => data.end_floats = data.end_floats.union(&size),
607 None => {
608 data.max_size = data
609 .max_size
610 .max(data.start_floats.union(&data.end_floats).union(&size));
611 data.start_floats = ContentSizes::zero();
612 data.end_floats = ContentSizes::zero();
613 },
614 }
615 data
616 };
617 let data = if layout_context.use_rayon {
618 boxes
619 .par_iter()
620 .filter_map(get_box_info)
621 .collect::<Vec<_>>()
622 .into_iter()
623 .fold(AccumulatedData::default(), accumulate)
624 } else {
625 boxes
626 .iter()
627 .filter_map(get_box_info)
628 .fold(AccumulatedData::default(), accumulate)
629 };
630 InlineContentSizesResult {
631 depends_on_block_constraints: data.depends_on_block_constraints,
632 sizes: data.max_size_including_uncleared_floats(),
633 }
634}
635
636impl BlockContainer {
637 fn layout(
638 &self,
639 layout_context: &LayoutContext,
640 positioning_context: &mut PositioningContext,
641 containing_block: &ContainingBlock,
642 sequential_layout_state: Option<&mut SequentialLayoutState>,
643 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
644 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
645 ) -> CacheableLayoutResult {
646 match self {
647 BlockContainer::BlockLevelBoxes(child_boxes) => layout_block_level_children(
648 layout_context,
649 positioning_context,
650 child_boxes,
651 containing_block,
652 sequential_layout_state,
653 collapsible_with_parent_start_margin,
654 ignore_block_margins_for_stretch,
655 ),
656 BlockContainer::InlineFormattingContext(ifc) => ifc.layout(
657 layout_context,
658 positioning_context,
659 containing_block,
660 sequential_layout_state,
661 collapsible_with_parent_start_margin,
662 ),
663 }
664 }
665
666 #[inline]
667 pub(crate) fn layout_style<'a>(&self, base: &'a LayoutBoxBase) -> LayoutStyle<'a> {
668 LayoutStyle::Default(&base.style)
669 }
670}
671
672impl ComputeInlineContentSizes for BlockContainer {
673 fn compute_inline_content_sizes(
674 &self,
675 layout_context: &LayoutContext,
676 constraint_space: &ConstraintSpace,
677 ) -> InlineContentSizesResult {
678 match &self {
679 Self::BlockLevelBoxes(boxes) => compute_inline_content_sizes_for_block_level_boxes(
680 boxes,
681 layout_context,
682 &constraint_space.into(),
683 ),
684 Self::InlineFormattingContext(context) => {
685 context.compute_inline_content_sizes(layout_context, constraint_space)
686 },
687 }
688 }
689}
690
691fn layout_block_level_children(
692 layout_context: &LayoutContext,
693 positioning_context: &mut PositioningContext,
694 child_boxes: &[ArcRefCell<BlockLevelBox>],
695 containing_block: &ContainingBlock,
696 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
697 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
698 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
699) -> CacheableLayoutResult {
700 let mut placement_state =
701 PlacementState::new(collapsible_with_parent_start_margin, containing_block);
702
703 let fragments = match sequential_layout_state {
704 Some(ref mut sequential_layout_state) => layout_block_level_children_sequentially(
705 layout_context,
706 positioning_context,
707 child_boxes,
708 containing_block,
709 sequential_layout_state,
710 &mut placement_state,
711 ignore_block_margins_for_stretch,
712 ),
713 None => layout_block_level_children_in_parallel(
714 layout_context,
715 positioning_context,
716 child_boxes,
717 containing_block,
718 &mut placement_state,
719 ignore_block_margins_for_stretch,
720 ),
721 };
722
723 let depends_on_block_constraints = fragments.iter().any(|fragment| {
724 fragment.base().is_some_and(|base| {
725 base.flags.contains(
726 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
727 )
728 })
729 });
730
731 let (content_block_size, collapsible_margins_in_children, baselines) = placement_state.finish();
732 CacheableLayoutResult {
733 fragments,
734 content_block_size,
735 collapsible_margins_in_children,
736 baselines,
737 depends_on_block_constraints,
738 content_inline_size_for_table: None,
739 specific_layout_info: None,
740 }
741}
742
743fn layout_block_level_children_in_parallel(
744 layout_context: &LayoutContext,
745 positioning_context: &mut PositioningContext,
746 child_boxes: &[ArcRefCell<BlockLevelBox>],
747 containing_block: &ContainingBlock,
748 placement_state: &mut PlacementState,
749 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
750) -> Vec<Fragment> {
751 let mut layout_results: Vec<(Fragment, PositioningContext)> =
752 Vec::with_capacity(child_boxes.len());
753
754 child_boxes
755 .par_iter()
756 .map(|child_box| {
757 let mut child_positioning_context = PositioningContext::default();
758 let fragment = child_box.borrow().layout(
759 layout_context,
760 &mut child_positioning_context,
761 containing_block,
762 None,
763 None,
764 ignore_block_margins_for_stretch,
765 );
766 (fragment, child_positioning_context)
767 })
768 .collect_into_vec(&mut layout_results);
769
770 layout_results
771 .into_iter()
772 .map(|(mut fragment, mut child_positioning_context)| {
773 placement_state.place_fragment_and_update_baseline(&mut fragment, None);
774 child_positioning_context.adjust_static_position_of_hoisted_fragments(
775 &fragment,
776 PositioningContextLength::zero(),
777 );
778 positioning_context.append(child_positioning_context);
779 fragment
780 })
781 .collect()
782}
783
784fn layout_block_level_children_sequentially(
785 layout_context: &LayoutContext,
786 positioning_context: &mut PositioningContext,
787 child_boxes: &[ArcRefCell<BlockLevelBox>],
788 containing_block: &ContainingBlock,
789 sequential_layout_state: &mut SequentialLayoutState,
790 placement_state: &mut PlacementState,
791 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
792) -> Vec<Fragment> {
793 child_boxes
797 .iter()
798 .map(|child_box| {
799 let positioning_context_length_before_layout = positioning_context.len();
800 let mut fragment = child_box.borrow().layout(
801 layout_context,
802 positioning_context,
803 containing_block,
804 Some(&mut *sequential_layout_state),
805 Some(CollapsibleWithParentStartMargin(
806 placement_state.next_in_flow_margin_collapses_with_parent_start_margin,
807 )),
808 ignore_block_margins_for_stretch,
809 );
810
811 placement_state
812 .place_fragment_and_update_baseline(&mut fragment, Some(sequential_layout_state));
813 positioning_context.adjust_static_position_of_hoisted_fragments(
814 &fragment,
815 positioning_context_length_before_layout,
816 );
817
818 fragment
819 })
820 .collect()
821}
822
823impl BlockLevelBox {
824 fn layout(
825 &self,
826 layout_context: &LayoutContext,
827 positioning_context: &mut PositioningContext,
828 containing_block: &ContainingBlock,
829 sequential_layout_state: Option<&mut SequentialLayoutState>,
830 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
831 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
832 ) -> Fragment {
833 let fragment = match self {
834 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => Fragment::Box(
835 ArcRefCell::new(positioning_context.layout_maybe_position_relative_fragment(
836 layout_context,
837 containing_block,
838 base,
839 |positioning_context| {
840 layout_in_flow_non_replaced_block_level_same_formatting_context(
841 layout_context,
842 positioning_context,
843 containing_block,
844 base,
845 contents,
846 sequential_layout_state,
847 collapsible_with_parent_start_margin,
848 ignore_block_margins_for_stretch,
849 )
850 },
851 )),
852 ),
853 BlockLevelBox::Independent(independent) => Fragment::Box(ArcRefCell::new(
854 positioning_context.layout_maybe_position_relative_fragment(
855 layout_context,
856 containing_block,
857 &independent.base,
858 |positioning_context| {
859 independent.layout_in_flow_block_level(
860 layout_context,
861 positioning_context,
862 containing_block,
863 sequential_layout_state,
864 ignore_block_margins_for_stretch,
865 )
866 },
867 ),
868 )),
869 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => {
870 let hoisted_box = AbsolutelyPositionedBox::to_hoisted(
874 box_.clone(),
875 PhysicalRect::zero(),
879 LogicalVec2 {
880 inline: AlignFlags::START,
881 block: AlignFlags::START,
882 },
883 containing_block.style.writing_mode,
884 );
885 let hoisted_fragment = hoisted_box.fragment.clone();
886 positioning_context.push(hoisted_box);
887 Fragment::AbsoluteOrFixedPositioned(hoisted_fragment)
888 },
889 BlockLevelBox::OutOfFlowFloatBox(float_box) => Fragment::Float(ArcRefCell::new(
890 float_box.layout(layout_context, positioning_context, containing_block),
891 )),
892 BlockLevelBox::OutsideMarker(outside_marker) => {
893 outside_marker.layout(layout_context, containing_block, positioning_context)
894 },
895 };
896
897 self.with_base(|base| base.set_fragment(fragment.clone()));
898
899 fragment
900 }
901
902 fn inline_content_sizes(
903 &self,
904 layout_context: &LayoutContext,
905 constraint_space: &ConstraintSpace,
906 ) -> InlineContentSizesResult {
907 let independent_formatting_context = match self {
908 BlockLevelBox::Independent(independent) => independent,
909 BlockLevelBox::OutOfFlowAbsolutelyPositionedBox(box_) => &box_.borrow().context,
910 BlockLevelBox::OutOfFlowFloatBox(float_box) => &float_box.contents,
911 BlockLevelBox::OutsideMarker(outside_marker) => {
912 return outside_marker.inline_content_sizes(layout_context, constraint_space);
913 },
914 BlockLevelBox::SameFormattingContextBlock { base, contents, .. } => {
915 return base.inline_content_sizes(layout_context, constraint_space, contents);
916 },
917 };
918 independent_formatting_context.inline_content_sizes(layout_context, constraint_space)
919 }
920}
921
922#[allow(clippy::too_many_arguments)]
928fn layout_in_flow_non_replaced_block_level_same_formatting_context(
929 layout_context: &LayoutContext,
930 positioning_context: &mut PositioningContext,
931 containing_block: &ContainingBlock,
932 base: &LayoutBoxBase,
933 contents: &BlockContainer,
934 mut sequential_layout_state: Option<&mut SequentialLayoutState>,
935 collapsible_with_parent_start_margin: Option<CollapsibleWithParentStartMargin>,
936 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
937) -> BoxFragment {
938 let style = &base.style;
939 let layout_style = contents.layout_style(base);
940 let containing_block_writing_mode = containing_block.style.writing_mode;
941 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
942 base.inline_content_sizes(layout_context, constraint_space, contents)
943 .sizes
944 };
945 let ContainingBlockPaddingAndBorder {
946 containing_block: containing_block_for_children,
947 pbm,
948 block_sizes,
949 depends_on_block_constraints,
950 available_block_size,
951 justify_self,
952 ..
953 } = solve_containing_block_padding_and_border_for_in_flow_box(
954 containing_block,
955 &layout_style,
956 get_inline_content_sizes,
957 ignore_block_margins_for_stretch,
958 None,
959 );
960 let ResolvedMargins {
961 margin,
962 effective_margin_inline_start,
963 } = solve_margins(
964 containing_block,
965 &pbm,
966 containing_block_for_children.size.inline,
967 justify_self,
968 );
969
970 let computed_block_size = style.content_block_size();
971 let start_margin_can_collapse_with_children =
972 pbm.padding.block_start.is_zero() && pbm.border.block_start.is_zero();
973
974 let mut clearance = None;
975 let parent_containing_block_position_info;
976 match sequential_layout_state {
977 None => parent_containing_block_position_info = None,
978 Some(ref mut sequential_layout_state) => {
979 let clear =
980 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode);
981 let mut block_start_margin = CollapsedMargin::new(margin.block_start);
982
983 let collapsible_with_parent_start_margin = collapsible_with_parent_start_margin.expect(
995 "We should know whether we are collapsing the block start margin with the parent \
996 when laying out sequentially",
997 ).0 && clear == Clear::None;
998 if !collapsible_with_parent_start_margin && start_margin_can_collapse_with_children {
999 if let BlockContainer::BlockLevelBoxes(child_boxes) = contents {
1000 BlockLevelBox::find_block_margin_collapsing_with_parent_from_slice(
1001 layout_context,
1002 child_boxes,
1003 &mut block_start_margin,
1004 &containing_block_for_children,
1005 );
1006 }
1007 }
1008
1009 clearance = sequential_layout_state.calculate_clearance(clear, &block_start_margin);
1011 if clearance.is_some() {
1012 sequential_layout_state.collapse_margins();
1013 }
1014 sequential_layout_state.adjoin_assign(&block_start_margin);
1015 if !start_margin_can_collapse_with_children {
1016 sequential_layout_state.collapse_margins();
1017 }
1018
1019 sequential_layout_state.advance_block_position(
1022 pbm.padding.block_start +
1023 pbm.border.block_start +
1024 clearance.unwrap_or_else(Au::zero),
1025 );
1026
1027 let inline_start = sequential_layout_state
1033 .floats
1034 .containing_block_info
1035 .inline_start +
1036 pbm.padding.inline_start +
1037 pbm.border.inline_start +
1038 effective_margin_inline_start;
1039 let new_cb_offsets = ContainingBlockPositionInfo {
1040 block_start: sequential_layout_state.bfc_relative_block_position,
1041 block_start_margins_not_collapsed: sequential_layout_state.current_margin,
1042 inline_start,
1043 inline_end: inline_start + containing_block_for_children.size.inline,
1044 };
1045 parent_containing_block_position_info = Some(
1046 sequential_layout_state.replace_containing_block_position_info(new_cb_offsets),
1047 );
1048 },
1049 };
1050
1051 let ignore_block_margins_for_stretch = LogicalSides1D::new(
1057 pbm.border.block_start.is_zero() && pbm.padding.block_start.is_zero(),
1058 pbm.border.block_end.is_zero() && pbm.padding.block_end.is_zero(),
1059 );
1060
1061 let flow_layout = contents.layout(
1062 layout_context,
1063 positioning_context,
1064 &containing_block_for_children,
1065 sequential_layout_state.as_deref_mut(),
1066 CollapsibleWithParentStartMargin(start_margin_can_collapse_with_children),
1067 ignore_block_margins_for_stretch,
1068 );
1069 let mut content_block_size: Au = flow_layout.content_block_size;
1070
1071 let mut block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1073 let mut collapsible_margins_in_children = flow_layout.collapsible_margins_in_children;
1074 if start_margin_can_collapse_with_children {
1075 block_margins_collapsed_with_children
1076 .start
1077 .adjoin_assign(&collapsible_margins_in_children.start);
1078 if collapsible_margins_in_children.collapsed_through {
1079 block_margins_collapsed_with_children
1080 .start
1081 .adjoin_assign(&std::mem::replace(
1082 &mut collapsible_margins_in_children.end,
1083 CollapsedMargin::zero(),
1084 ));
1085 }
1086 }
1087
1088 let collapsed_through = collapsible_margins_in_children.collapsed_through &&
1089 pbm.padding_border_sums.block.is_zero() &&
1090 block_size_is_zero_or_intrinsic(computed_block_size, containing_block) &&
1091 block_size_is_zero_or_intrinsic(style.min_block_size(), containing_block);
1092 block_margins_collapsed_with_children.collapsed_through = collapsed_through;
1093
1094 let end_margin_can_collapse_with_children =
1095 pbm.padding.block_end.is_zero() && pbm.border.block_end.is_zero();
1096 if !end_margin_can_collapse_with_children {
1097 content_block_size += collapsible_margins_in_children.end.solve();
1098 }
1099
1100 let block_size = block_sizes.resolve(
1101 Direction::Block,
1102 Size::FitContent,
1103 Au::zero,
1104 available_block_size,
1105 || content_block_size.into(),
1106 false, );
1108
1109 let end_margin_can_collapse_with_children = end_margin_can_collapse_with_children &&
1124 block_size == content_block_size &&
1125 (collapsed_through || !containing_block_for_children.size.block.is_definite());
1126 if end_margin_can_collapse_with_children {
1127 block_margins_collapsed_with_children
1128 .end
1129 .adjoin_assign(&collapsible_margins_in_children.end);
1130 }
1131
1132 if let Some(ref mut sequential_layout_state) = sequential_layout_state {
1133 sequential_layout_state
1136 .replace_containing_block_position_info(parent_containing_block_position_info.unwrap());
1137
1138 sequential_layout_state.advance_block_position(
1148 block_size - content_block_size + pbm.padding.block_end + pbm.border.block_end,
1149 );
1150
1151 if !end_margin_can_collapse_with_children {
1152 sequential_layout_state.collapse_margins();
1153 }
1154 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1155 }
1156
1157 let content_rect = LogicalRect {
1158 start_corner: LogicalVec2 {
1159 block: (pbm.padding.block_start +
1160 pbm.border.block_start +
1161 clearance.unwrap_or_else(Au::zero)),
1162 inline: pbm.padding.inline_start +
1163 pbm.border.inline_start +
1164 effective_margin_inline_start,
1165 },
1166 size: LogicalVec2 {
1167 block: block_size,
1168 inline: containing_block_for_children.size.inline,
1169 },
1170 };
1171
1172 let mut base_fragment_info = base.base_fragment_info;
1173 if depends_on_block_constraints {
1174 base_fragment_info
1175 .flags
1176 .insert(FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM);
1177 }
1178
1179 BoxFragment::new(
1180 base_fragment_info,
1181 style.clone(),
1182 flow_layout.fragments,
1183 content_rect.as_physical(Some(containing_block)),
1184 pbm.padding.to_physical(containing_block_writing_mode),
1185 pbm.border.to_physical(containing_block_writing_mode),
1186 margin.to_physical(containing_block_writing_mode),
1187 flow_layout.specific_layout_info,
1188 )
1189 .with_baselines(flow_layout.baselines)
1190 .with_block_level_layout_info(block_margins_collapsed_with_children, clearance)
1191}
1192
1193impl IndependentFormattingContext {
1194 pub(crate) fn layout_in_flow_block_level(
1202 &self,
1203 layout_context: &LayoutContext,
1204 positioning_context: &mut PositioningContext,
1205 containing_block: &ContainingBlock,
1206 sequential_layout_state: Option<&mut SequentialLayoutState>,
1207 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1208 ) -> BoxFragment {
1209 if let Some(sequential_layout_state) = sequential_layout_state {
1210 return self.layout_in_flow_block_level_sequentially(
1211 layout_context,
1212 positioning_context,
1213 containing_block,
1214 sequential_layout_state,
1215 ignore_block_margins_for_stretch,
1216 );
1217 }
1218
1219 let get_inline_content_sizes = |constraint_space: &ConstraintSpace| {
1220 self.inline_content_sizes(layout_context, constraint_space)
1221 .sizes
1222 };
1223 let layout_style = self.layout_style();
1224 let ContainingBlockPaddingAndBorder {
1225 containing_block: containing_block_for_children,
1226 pbm,
1227 block_sizes,
1228 depends_on_block_constraints,
1229 available_block_size,
1230 justify_self,
1231 preferred_aspect_ratio,
1232 } = solve_containing_block_padding_and_border_for_in_flow_box(
1233 containing_block,
1234 &layout_style,
1235 get_inline_content_sizes,
1236 ignore_block_margins_for_stretch,
1237 Some(self),
1238 );
1239
1240 let lazy_block_size = LazySize::new(
1241 &block_sizes,
1242 Direction::Block,
1243 Size::FitContent,
1244 Au::zero,
1245 available_block_size,
1246 layout_style.is_table(),
1247 );
1248
1249 let layout = self.layout(
1250 layout_context,
1251 positioning_context,
1252 &containing_block_for_children,
1253 containing_block,
1254 preferred_aspect_ratio,
1255 &lazy_block_size,
1256 );
1257
1258 let inline_size = layout
1259 .content_inline_size_for_table
1260 .unwrap_or(containing_block_for_children.size.inline);
1261 let block_size = lazy_block_size.resolve(|| layout.content_block_size);
1262
1263 let ResolvedMargins {
1264 margin,
1265 effective_margin_inline_start,
1266 } = solve_margins(containing_block, &pbm, inline_size, justify_self);
1267
1268 let content_rect = LogicalRect {
1269 start_corner: LogicalVec2 {
1270 block: pbm.padding.block_start + pbm.border.block_start,
1271 inline: pbm.padding.inline_start +
1272 pbm.border.inline_start +
1273 effective_margin_inline_start,
1274 },
1275 size: LogicalVec2 {
1276 block: block_size,
1277 inline: inline_size,
1278 },
1279 };
1280
1281 let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
1282 let containing_block_writing_mode = containing_block.style.writing_mode;
1283
1284 let mut base_fragment_info = self.base.base_fragment_info;
1285 if depends_on_block_constraints {
1286 base_fragment_info.flags.insert(
1287 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1288 );
1289 }
1290 BoxFragment::new(
1291 base_fragment_info,
1292 self.base.style.clone(),
1293 layout.fragments,
1294 content_rect.as_physical(Some(containing_block)),
1295 pbm.padding.to_physical(containing_block_writing_mode),
1296 pbm.border.to_physical(containing_block_writing_mode),
1297 margin.to_physical(containing_block_writing_mode),
1298 layout.specific_layout_info,
1299 )
1300 .with_baselines(layout.baselines)
1301 .with_block_level_layout_info(block_margins_collapsed_with_children, None)
1302 }
1303
1304 fn layout_in_flow_block_level_sequentially(
1308 &self,
1309 layout_context: &LayoutContext<'_>,
1310 positioning_context: &mut PositioningContext,
1311 containing_block: &ContainingBlock<'_>,
1312 sequential_layout_state: &mut SequentialLayoutState,
1313 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1314 ) -> BoxFragment {
1315 let style = &self.base.style;
1316 let containing_block_writing_mode = containing_block.style.writing_mode;
1317 let ContentBoxSizesAndPBM {
1318 content_box_sizes,
1319 pbm,
1320 depends_on_block_constraints,
1321 ..
1322 } = self
1323 .layout_style()
1324 .content_box_sizes_and_padding_border_margin(&containing_block.into());
1325
1326 let (margin_block_start, margin_block_end) =
1327 solve_block_margins_for_in_flow_block_level(&pbm);
1328 let collapsed_margin_block_start = CollapsedMargin::new(margin_block_start);
1329
1330 let mut content_size;
1341 let mut layout;
1342 let mut placement_rect;
1343
1344 let clear_position = sequential_layout_state.calculate_clear_position(
1348 Clear::from_style_and_container_writing_mode(style, containing_block_writing_mode),
1349 &collapsed_margin_block_start,
1350 );
1351 let ceiling = clear_position.unwrap_or_else(|| {
1352 sequential_layout_state.position_without_clearance(&collapsed_margin_block_start)
1353 });
1354
1355 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1357 let available_block_size = containing_block
1358 .size
1359 .block
1360 .to_definite()
1361 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1362 let is_table = self.is_table();
1363 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
1364 let tentative_block_content_size =
1365 self.tentative_block_content_size(preferred_aspect_ratio);
1366 let (preferred_block_size, min_block_size, max_block_size) =
1367 if let Some(block_content_size) = tentative_block_content_size {
1368 let (preferred, min, max) = content_box_sizes.block.resolve_each(
1369 Size::FitContent,
1370 Au::zero,
1371 available_block_size,
1372 || block_content_size,
1373 is_table,
1374 );
1375 (Some(preferred), min, max)
1376 } else {
1377 content_box_sizes.block.resolve_each_extrinsic(
1378 Size::FitContent,
1379 Au::zero(),
1380 available_block_size,
1381 )
1382 };
1383 let tentative_block_size =
1384 SizeConstraint::new(preferred_block_size, min_block_size, max_block_size);
1385
1386 let get_inline_content_sizes = || {
1388 let constraint_space =
1389 ConstraintSpace::new(tentative_block_size, style, preferred_aspect_ratio);
1390 self.inline_content_sizes(layout_context, &constraint_space)
1391 .sizes
1392 };
1393
1394 let justify_self = resolve_justify_self(style, containing_block.style);
1395 let automatic_inline_size =
1396 automatic_inline_size(justify_self, is_table, self.is_replaced());
1397 let compute_inline_size = |stretch_size| {
1398 content_box_sizes.inline.resolve(
1399 Direction::Inline,
1400 automatic_inline_size,
1401 Au::zero,
1402 Some(stretch_size),
1403 get_inline_content_sizes,
1404 is_table,
1405 )
1406 };
1407
1408 let get_lazy_block_size = || {
1409 LazySize::new(
1410 &content_box_sizes.block,
1411 Direction::Block,
1412 Size::FitContent,
1413 Au::zero,
1414 available_block_size,
1415 is_table,
1416 )
1417 };
1418
1419 let inline_size_with_no_available_space = compute_inline_size(Au::zero());
1428 if inline_size_with_no_available_space == compute_inline_size(MAX_AU) {
1429 let inline_size = inline_size_with_no_available_space;
1433 let lazy_block_size = get_lazy_block_size();
1434 layout = self.layout(
1435 layout_context,
1436 positioning_context,
1437 &ContainingBlock {
1438 size: ContainingBlockSize {
1439 inline: inline_size,
1440 block: tentative_block_size,
1441 },
1442 style,
1443 },
1444 containing_block,
1445 preferred_aspect_ratio,
1446 &lazy_block_size,
1447 );
1448
1449 content_size = LogicalVec2 {
1450 block: lazy_block_size.resolve(|| layout.content_block_size),
1451 inline: layout.content_inline_size_for_table.unwrap_or(inline_size),
1452 };
1453
1454 let mut placement = PlacementAmongFloats::new(
1455 &sequential_layout_state.floats,
1456 ceiling,
1457 content_size + pbm.padding_border_sums,
1458 &pbm,
1459 );
1460 placement_rect = placement.place();
1461 } else {
1462 let minimum_size_of_block = LogicalVec2 {
1468 inline: inline_size_with_no_available_space,
1472 block: match tentative_block_size {
1473 SizeConstraint::Definite(size) if max_block_size.is_some() => size,
1476 _ => min_block_size,
1479 },
1480 } + pbm.padding_border_sums;
1481 let mut placement = PlacementAmongFloats::new(
1482 &sequential_layout_state.floats,
1483 ceiling,
1484 minimum_size_of_block,
1485 &pbm,
1486 );
1487
1488 loop {
1489 placement_rect = placement.place();
1491 let available_inline_size =
1492 placement_rect.size.inline - pbm.padding_border_sums.inline;
1493 let proposed_inline_size = compute_inline_size(available_inline_size);
1494
1495 let positioning_context_length = positioning_context.len();
1499 let lazy_block_size = get_lazy_block_size();
1500 layout = self.layout(
1501 layout_context,
1502 positioning_context,
1503 &ContainingBlock {
1504 size: ContainingBlockSize {
1505 inline: proposed_inline_size,
1506 block: tentative_block_size,
1507 },
1508 style,
1509 },
1510 containing_block,
1511 preferred_aspect_ratio,
1512 &lazy_block_size,
1513 );
1514
1515 let inline_size = if let Some(inline_size) = layout.content_inline_size_for_table {
1516 debug_assert!(inline_size < proposed_inline_size);
1521 inline_size
1522 } else {
1523 proposed_inline_size
1524 };
1525 content_size = LogicalVec2 {
1526 block: lazy_block_size.resolve(|| layout.content_block_size),
1527 inline: inline_size,
1528 };
1529
1530 if placement.try_to_expand_for_auto_block_size(
1534 content_size.block + pbm.padding_border_sums.block,
1535 &placement_rect.size,
1536 ) {
1537 break;
1538 }
1539
1540 positioning_context.truncate(&positioning_context_length);
1544 }
1545 }
1546
1547 let has_clearance = clear_position.is_some() || placement_rect.start_corner.block > ceiling;
1551 let clearance = has_clearance.then(|| {
1552 placement_rect.start_corner.block -
1553 sequential_layout_state
1554 .position_with_zero_clearance(&collapsed_margin_block_start)
1555 });
1556
1557 let ((margin_inline_start, margin_inline_end), effective_margin_inline_start) =
1558 solve_inline_margins_avoiding_floats(
1559 sequential_layout_state,
1560 containing_block,
1561 &pbm,
1562 content_size.inline + pbm.padding_border_sums.inline,
1563 placement_rect,
1564 justify_self,
1565 );
1566
1567 let margin = LogicalSides {
1568 inline_start: margin_inline_start,
1569 inline_end: margin_inline_end,
1570 block_start: margin_block_start,
1571 block_end: margin_block_end,
1572 };
1573
1574 if clearance.is_some() {
1577 sequential_layout_state.collapse_margins();
1578 }
1579 sequential_layout_state.adjoin_assign(&collapsed_margin_block_start);
1580
1581 sequential_layout_state.collapse_margins();
1583 sequential_layout_state.advance_block_position(
1584 pbm.padding_border_sums.block + content_size.block + clearance.unwrap_or_else(Au::zero),
1585 );
1586 sequential_layout_state.adjoin_assign(&CollapsedMargin::new(margin.block_end));
1587
1588 let content_rect = LogicalRect {
1589 start_corner: LogicalVec2 {
1590 block: pbm.padding.block_start +
1591 pbm.border.block_start +
1592 clearance.unwrap_or_else(Au::zero),
1593 inline: pbm.padding.inline_start +
1594 pbm.border.inline_start +
1595 effective_margin_inline_start,
1596 },
1597 size: content_size,
1598 };
1599
1600 let mut base_fragment_info = self.base.base_fragment_info;
1601 if depends_on_block_constraints {
1602 base_fragment_info.flags.insert(
1603 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
1604 );
1605 }
1606
1607 BoxFragment::new(
1608 base_fragment_info,
1609 style.clone(),
1610 layout.fragments,
1611 content_rect.as_physical(Some(containing_block)),
1612 pbm.padding.to_physical(containing_block_writing_mode),
1613 pbm.border.to_physical(containing_block_writing_mode),
1614 margin.to_physical(containing_block_writing_mode),
1615 layout.specific_layout_info,
1616 )
1617 .with_baselines(layout.baselines)
1618 .with_block_level_layout_info(CollapsedBlockMargins::from_margin(&margin), clearance)
1619 }
1620}
1621
1622struct ContainingBlockPaddingAndBorder<'a> {
1623 containing_block: ContainingBlock<'a>,
1624 pbm: PaddingBorderMargin,
1625 block_sizes: Sizes,
1626 depends_on_block_constraints: bool,
1627 available_block_size: Option<Au>,
1628 justify_self: AlignFlags,
1629 preferred_aspect_ratio: Option<AspectRatio>,
1630}
1631
1632struct ResolvedMargins {
1633 pub margin: LogicalSides<Au>,
1635
1636 pub effective_margin_inline_start: Au,
1643}
1644
1645fn solve_containing_block_padding_and_border_for_in_flow_box<'a>(
1651 containing_block: &ContainingBlock<'_>,
1652 layout_style: &'a LayoutStyle,
1653 get_inline_content_sizes: impl FnOnce(&ConstraintSpace) -> ContentSizes,
1654 ignore_block_margins_for_stretch: LogicalSides1D<bool>,
1655 context: Option<&IndependentFormattingContext>,
1656) -> ContainingBlockPaddingAndBorder<'a> {
1657 let style = layout_style.style();
1658 if matches!(style.pseudo(), Some(PseudoElement::ServoAnonymousBox)) {
1659 let containing_block_for_children = ContainingBlock {
1663 size: ContainingBlockSize {
1664 inline: containing_block.size.inline,
1665 block: containing_block.size.block,
1666 },
1667 style,
1668 };
1669 return ContainingBlockPaddingAndBorder {
1672 containing_block: containing_block_for_children,
1673 pbm: PaddingBorderMargin::zero(),
1674 block_sizes: Sizes::default(),
1675 depends_on_block_constraints: false,
1676 available_block_size: None,
1679 justify_self: AlignFlags::NORMAL,
1682 preferred_aspect_ratio: None,
1683 };
1684 }
1685
1686 let ContentBoxSizesAndPBM {
1687 content_box_sizes,
1688 pbm,
1689 depends_on_block_constraints,
1690 ..
1691 } = layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
1692
1693 let pbm_sums = pbm.sums_auto_is_zero(ignore_block_margins_for_stretch);
1694 let available_inline_size = Au::zero().max(containing_block.size.inline - pbm_sums.inline);
1695 let available_block_size = containing_block
1696 .size
1697 .block
1698 .to_definite()
1699 .map(|block_size| Au::zero().max(block_size - pbm_sums.block));
1700
1701 let preferred_aspect_ratio =
1704 context.and_then(|context| context.preferred_aspect_ratio(&pbm.padding_border_sums));
1705 let is_table = layout_style.is_table();
1706
1707 let tentative_block_content_size =
1710 context.and_then(|context| context.tentative_block_content_size(preferred_aspect_ratio));
1711 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
1712 SizeConstraint::Definite(content_box_sizes.block.resolve(
1713 Direction::Block,
1714 Size::FitContent,
1715 Au::zero,
1716 available_block_size,
1717 || block_content_size,
1718 is_table,
1719 ))
1720 } else {
1721 content_box_sizes.block.resolve_extrinsic(
1722 Size::FitContent,
1723 Au::zero(),
1724 available_block_size,
1725 )
1726 };
1727
1728 let get_inline_content_sizes = || {
1731 get_inline_content_sizes(&ConstraintSpace::new(
1732 tentative_block_size,
1733 style,
1734 preferred_aspect_ratio,
1735 ))
1736 };
1737 let justify_self = resolve_justify_self(style, containing_block.style);
1738 let is_replaced = context.is_some_and(|context| context.is_replaced());
1739 let inline_size = content_box_sizes.inline.resolve(
1740 Direction::Inline,
1741 automatic_inline_size(justify_self, is_table, is_replaced),
1742 Au::zero,
1743 Some(available_inline_size),
1744 get_inline_content_sizes,
1745 is_table,
1746 );
1747
1748 let containing_block_for_children = ContainingBlock {
1749 size: ContainingBlockSize {
1750 inline: inline_size,
1751 block: tentative_block_size,
1752 },
1753 style,
1754 };
1755 assert_eq!(
1757 containing_block.style.writing_mode.is_horizontal(),
1758 containing_block_for_children
1759 .style
1760 .writing_mode
1761 .is_horizontal(),
1762 "Vertical writing modes are not supported yet"
1763 );
1764 ContainingBlockPaddingAndBorder {
1765 containing_block: containing_block_for_children,
1766 pbm,
1767 block_sizes: content_box_sizes.block,
1768 depends_on_block_constraints,
1769 available_block_size,
1770 justify_self,
1771 preferred_aspect_ratio,
1772 }
1773}
1774
1775fn solve_margins(
1780 containing_block: &ContainingBlock<'_>,
1781 pbm: &PaddingBorderMargin,
1782 inline_size: Au,
1783 justify_self: AlignFlags,
1784) -> ResolvedMargins {
1785 let (inline_margins, effective_margin_inline_start) =
1786 solve_inline_margins_for_in_flow_block_level(
1787 containing_block,
1788 pbm,
1789 inline_size,
1790 justify_self,
1791 );
1792 let block_margins = solve_block_margins_for_in_flow_block_level(pbm);
1793 ResolvedMargins {
1794 margin: LogicalSides {
1795 inline_start: inline_margins.0,
1796 inline_end: inline_margins.1,
1797 block_start: block_margins.0,
1798 block_end: block_margins.1,
1799 },
1800 effective_margin_inline_start,
1801 }
1802}
1803
1804fn solve_block_margins_for_in_flow_block_level(pbm: &PaddingBorderMargin) -> (Au, Au) {
1808 (
1809 pbm.margin.block_start.auto_is(Au::zero),
1810 pbm.margin.block_end.auto_is(Au::zero),
1811 )
1812}
1813
1814fn resolve_justify_self(style: &ComputedValues, parent_style: &ComputedValues) -> AlignFlags {
1816 let is_ltr = |style: &ComputedValues| style.writing_mode.line_left_is_inline_start();
1817 let alignment = match style.clone_justify_self().0.0 {
1818 AlignFlags::AUTO => parent_style.clone_justify_items().computed.0,
1819 alignment => alignment,
1820 };
1821 let alignment_value = match alignment.value() {
1822 AlignFlags::LEFT if is_ltr(parent_style) => AlignFlags::START,
1823 AlignFlags::LEFT => AlignFlags::END,
1824 AlignFlags::RIGHT if is_ltr(parent_style) => AlignFlags::END,
1825 AlignFlags::RIGHT => AlignFlags::START,
1826 AlignFlags::SELF_START if is_ltr(parent_style) == is_ltr(style) => AlignFlags::START,
1827 AlignFlags::SELF_START => AlignFlags::END,
1828 AlignFlags::SELF_END if is_ltr(parent_style) == is_ltr(style) => AlignFlags::END,
1829 AlignFlags::SELF_END => AlignFlags::START,
1830 alignment_value => alignment_value,
1831 };
1832 alignment.flags() | alignment_value
1833}
1834
1835#[inline]
1838fn automatic_inline_size<T>(
1839 justify_self: AlignFlags,
1840 is_table: bool,
1841 is_replaced: bool,
1842) -> Size<T> {
1843 match justify_self {
1844 AlignFlags::STRETCH => Size::Stretch,
1845 AlignFlags::NORMAL if !is_table && !is_replaced => Size::Stretch,
1846 _ => Size::FitContent,
1847 }
1848}
1849
1850fn justify_self_alignment(
1857 containing_block: &ContainingBlock,
1858 free_space: Au,
1859 justify_self: AlignFlags,
1860) -> Au {
1861 let mut alignment = justify_self.value();
1862 let is_safe = justify_self.flags() == AlignFlags::SAFE || alignment == AlignFlags::NORMAL;
1863 if is_safe && free_space <= Au::zero() {
1864 alignment = AlignFlags::START
1865 }
1866 match alignment {
1867 AlignFlags::NORMAL => {},
1868 AlignFlags::CENTER => return free_space / 2,
1869 AlignFlags::END => return free_space,
1870 _ => return Au::zero(),
1871 }
1872
1873 let style = containing_block.style;
1875 match style.clone_text_align() {
1876 TextAlignKeyword::MozCenter => free_space / 2,
1877 TextAlignKeyword::MozLeft if !style.writing_mode.line_left_is_inline_start() => free_space,
1878 TextAlignKeyword::MozRight if style.writing_mode.line_left_is_inline_start() => free_space,
1879 _ => Au::zero(),
1880 }
1881}
1882
1883fn solve_inline_margins_for_in_flow_block_level(
1896 containing_block: &ContainingBlock,
1897 pbm: &PaddingBorderMargin,
1898 inline_size: Au,
1899 justify_self: AlignFlags,
1900) -> ((Au, Au), Au) {
1901 let free_space = containing_block.size.inline - pbm.padding_border_sums.inline - inline_size;
1902 let mut justification = Au::zero();
1903 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1904 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1905 let start = Au::zero().max(free_space / 2);
1906 (start, free_space - start)
1907 },
1908 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => {
1909 (Au::zero().max(free_space - end), end)
1910 },
1911 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, free_space - start),
1912 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1913 justification =
1918 justify_self_alignment(containing_block, free_space - start - end, justify_self);
1919 (start, end)
1920 },
1921 };
1922 let effective_margin_inline_start = inline_margins.0 + justification;
1923 (inline_margins, effective_margin_inline_start)
1924}
1925
1926fn solve_inline_margins_avoiding_floats(
1936 sequential_layout_state: &SequentialLayoutState,
1937 containing_block: &ContainingBlock,
1938 pbm: &PaddingBorderMargin,
1939 inline_size: Au,
1940 placement_rect: LogicalRect<Au>,
1941 justify_self: AlignFlags,
1942) -> ((Au, Au), Au) {
1943 let free_space = Au::zero().max(placement_rect.size.inline - inline_size);
1947 let cb_info = &sequential_layout_state.floats.containing_block_info;
1948 let start_adjustment = placement_rect.start_corner.inline - cb_info.inline_start;
1949 let end_adjustment = cb_info.inline_end - placement_rect.max_inline_position();
1950 let mut justification = Au::zero();
1951 let inline_margins = match (pbm.margin.inline_start, pbm.margin.inline_end) {
1952 (AuOrAuto::Auto, AuOrAuto::Auto) => {
1953 let half = free_space / 2;
1954 (start_adjustment + half, end_adjustment + free_space - half)
1955 },
1956 (AuOrAuto::Auto, AuOrAuto::LengthPercentage(end)) => (start_adjustment + free_space, end),
1957 (AuOrAuto::LengthPercentage(start), AuOrAuto::Auto) => (start, end_adjustment + free_space),
1958 (AuOrAuto::LengthPercentage(start), AuOrAuto::LengthPercentage(end)) => {
1959 justification = justify_self_alignment(containing_block, free_space, justify_self);
1965 (start, end)
1966 },
1967 };
1968 let effective_margin_inline_start = inline_margins.0.max(start_adjustment) + justification;
1969 (inline_margins, effective_margin_inline_start)
1970}
1971
1972struct PlacementState<'container> {
1977 next_in_flow_margin_collapses_with_parent_start_margin: bool,
1978 last_in_flow_margin_collapses_with_parent_end_margin: bool,
1979 start_margin: CollapsedMargin,
1980 current_margin: CollapsedMargin,
1981 current_block_direction_position: Au,
1982 inflow_baselines: Baselines,
1983 is_inline_block_context: bool,
1984
1985 marker_block_size: Option<Au>,
1990
1991 containing_block: &'container ContainingBlock<'container>,
1994}
1995
1996impl<'container> PlacementState<'container> {
1997 fn new(
1998 collapsible_with_parent_start_margin: CollapsibleWithParentStartMargin,
1999 containing_block: &'container ContainingBlock<'container>,
2000 ) -> PlacementState<'container> {
2001 let is_inline_block_context =
2002 containing_block.style.get_box().clone_display() == Display::InlineBlock;
2003 PlacementState {
2004 next_in_flow_margin_collapses_with_parent_start_margin:
2005 collapsible_with_parent_start_margin.0,
2006 last_in_flow_margin_collapses_with_parent_end_margin: true,
2007 start_margin: CollapsedMargin::zero(),
2008 current_margin: CollapsedMargin::zero(),
2009 current_block_direction_position: Au::zero(),
2010 inflow_baselines: Baselines::default(),
2011 is_inline_block_context,
2012 marker_block_size: None,
2013 containing_block,
2014 }
2015 }
2016
2017 fn place_fragment_and_update_baseline(
2018 &mut self,
2019 fragment: &mut Fragment,
2020 sequential_layout_state: Option<&mut SequentialLayoutState>,
2021 ) {
2022 self.place_fragment(fragment, sequential_layout_state);
2023
2024 let box_fragment = match fragment {
2025 Fragment::Box(box_fragment) => box_fragment,
2026 _ => return,
2027 };
2028 let box_fragment = box_fragment.borrow();
2029
2030 if self.is_inline_block_context && box_fragment.is_table_wrapper() {
2035 return;
2036 }
2037
2038 let box_block_offset = box_fragment
2039 .content_rect
2040 .origin
2041 .to_logical(self.containing_block)
2042 .block;
2043 let box_fragment_baselines =
2044 box_fragment.baselines(self.containing_block.style.writing_mode);
2045 if let (None, Some(first)) = (self.inflow_baselines.first, box_fragment_baselines.first) {
2046 self.inflow_baselines.first = Some(first + box_block_offset);
2047 }
2048 if let Some(last) = box_fragment_baselines.last {
2049 self.inflow_baselines.last = Some(last + box_block_offset);
2050 }
2051 }
2052
2053 fn place_fragment(
2056 &mut self,
2057 fragment: &mut Fragment,
2058 sequential_layout_state: Option<&mut SequentialLayoutState>,
2059 ) {
2060 match fragment {
2061 Fragment::Box(fragment) => {
2062 let fragment = &mut *fragment.borrow_mut();
2071 let is_outside_marker = fragment
2072 .base
2073 .flags
2074 .contains(FragmentFlags::IS_OUTSIDE_LIST_ITEM_MARKER);
2075 if is_outside_marker {
2076 assert!(self.marker_block_size.is_none());
2077 self.marker_block_size = Some(
2078 fragment
2079 .content_rect
2080 .size
2081 .to_logical(self.containing_block.style.writing_mode)
2082 .block,
2083 );
2084 return;
2085 }
2086
2087 let BlockLevelLayoutInfo {
2088 clearance,
2089 block_margins_collapsed_with_children: fragment_block_margins,
2090 } = &**fragment
2091 .block_level_layout_info
2092 .as_ref()
2093 .expect("A block-level fragment should have a BlockLevelLayoutInfo.");
2094 let mut fragment_block_size = fragment
2095 .border_rect()
2096 .size
2097 .to_logical(self.containing_block.style.writing_mode)
2098 .block;
2099
2100 if let Some(clearance) = *clearance {
2106 fragment_block_size += clearance;
2107 self.current_block_direction_position += self.current_margin.solve();
2112 self.current_margin = CollapsedMargin::zero();
2113 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2114 if fragment_block_margins.collapsed_through {
2115 self.last_in_flow_margin_collapses_with_parent_end_margin = false;
2116 }
2117 } else if !fragment_block_margins.collapsed_through {
2118 self.last_in_flow_margin_collapses_with_parent_end_margin = true;
2119 }
2120
2121 if self.next_in_flow_margin_collapses_with_parent_start_margin {
2122 debug_assert!(self.current_margin.solve().is_zero());
2123 self.start_margin
2124 .adjoin_assign(&fragment_block_margins.start);
2125 if fragment_block_margins.collapsed_through {
2126 self.start_margin.adjoin_assign(&fragment_block_margins.end);
2127 return;
2128 }
2129 self.next_in_flow_margin_collapses_with_parent_start_margin = false;
2130 } else {
2131 self.current_margin
2132 .adjoin_assign(&fragment_block_margins.start);
2133 }
2134
2135 fragment.content_rect.origin += LogicalVec2 {
2136 inline: Au::zero(),
2137 block: self.current_margin.solve() + self.current_block_direction_position,
2138 }
2139 .to_physical_size(self.containing_block.style.writing_mode);
2140
2141 if fragment_block_margins.collapsed_through {
2142 self.current_block_direction_position += fragment_block_size;
2145 self.current_margin
2146 .adjoin_assign(&fragment_block_margins.end);
2147 } else {
2148 self.current_block_direction_position +=
2149 self.current_margin.solve() + fragment_block_size;
2150 self.current_margin = fragment_block_margins.end;
2151 }
2152 },
2153 Fragment::AbsoluteOrFixedPositioned(fragment) => {
2154 fragment.borrow_mut().original_static_position_rect = LogicalRect {
2157 start_corner: LogicalVec2 {
2158 block: (self.current_margin.solve() +
2159 self.current_block_direction_position),
2160 inline: Au::zero(),
2161 },
2162 size: LogicalVec2::zero(),
2163 }
2164 .as_physical(Some(self.containing_block));
2165 },
2166 Fragment::Float(box_fragment) => {
2167 let sequential_layout_state = sequential_layout_state
2168 .expect("Found float fragment without SequentialLayoutState");
2169 let block_offset_from_containing_block_top =
2170 self.current_block_direction_position + self.current_margin.solve();
2171 let box_fragment = &mut *box_fragment.borrow_mut();
2172 sequential_layout_state.place_float_fragment(
2173 box_fragment,
2174 self.containing_block,
2175 self.start_margin,
2176 block_offset_from_containing_block_top,
2177 );
2178 },
2179 Fragment::Positioning(_) => {},
2180 _ => unreachable!(),
2181 }
2182 }
2183
2184 fn finish(mut self) -> (Au, CollapsedBlockMargins, Baselines) {
2185 if !self.last_in_flow_margin_collapses_with_parent_end_margin {
2186 self.current_block_direction_position += self.current_margin.solve();
2187 self.current_margin = CollapsedMargin::zero();
2188 }
2189 let (total_block_size, collapsed_through) = match self.marker_block_size {
2190 Some(marker_block_size) => (
2191 self.current_block_direction_position.max(marker_block_size),
2192 false,
2195 ),
2196 None => (
2197 self.current_block_direction_position,
2198 self.next_in_flow_margin_collapses_with_parent_start_margin,
2199 ),
2200 };
2201
2202 (
2203 total_block_size,
2204 CollapsedBlockMargins {
2205 collapsed_through,
2206 start: self.start_margin,
2207 end: self.current_margin,
2208 },
2209 self.inflow_baselines,
2210 )
2211 }
2212}
2213
2214fn block_size_is_zero_or_intrinsic(size: &StyleSize, containing_block: &ContainingBlock) -> bool {
2215 match size {
2216 StyleSize::Auto |
2217 StyleSize::MinContent |
2218 StyleSize::MaxContent |
2219 StyleSize::FitContent |
2220 StyleSize::FitContentFunction(_) => true,
2221 StyleSize::Stretch | StyleSize::WebkitFillAvailable => {
2222 !containing_block.size.block.is_definite()
2224 },
2225 StyleSize::LengthPercentage(lp) => {
2226 lp.is_definitely_zero() ||
2228 (lp.0.has_percentage() && !containing_block.size.block.is_definite())
2229 },
2230 StyleSize::AnchorSizeFunction(_) | StyleSize::AnchorContainingCalcFunction(_) => {
2231 unreachable!("anchor-size() should be disabled")
2232 },
2233 }
2234}
2235
2236pub(crate) struct IndependentFloatOrAtomicLayoutResult {
2237 pub fragment: BoxFragment,
2238 pub baselines: Baselines,
2239 pub pbm_sums: LogicalSides<Au>,
2240}
2241
2242impl IndependentFormattingContext {
2243 pub(crate) fn layout_float_or_atomic_inline(
2244 &self,
2245 layout_context: &LayoutContext,
2246 child_positioning_context: &mut PositioningContext,
2247 containing_block: &ContainingBlock,
2248 ) -> IndependentFloatOrAtomicLayoutResult {
2249 let style = self.style();
2250 let container_writing_mode = containing_block.style.writing_mode;
2251 let layout_style = self.layout_style();
2252 let content_box_sizes_and_pbm =
2253 layout_style.content_box_sizes_and_padding_border_margin(&containing_block.into());
2254 let pbm = &content_box_sizes_and_pbm.pbm;
2255 let margin = pbm.margin.auto_is(Au::zero);
2256 let pbm_sums = pbm.padding + pbm.border + margin;
2257 let preferred_aspect_ratio = self.preferred_aspect_ratio(&pbm.padding_border_sums);
2258 let is_table = self.is_table();
2259
2260 let available_inline_size =
2261 Au::zero().max(containing_block.size.inline - pbm_sums.inline_sum());
2262 let available_block_size = containing_block
2263 .size
2264 .block
2265 .to_definite()
2266 .map(|block_size| Au::zero().max(block_size - pbm_sums.block_sum()));
2267
2268 let tentative_block_content_size =
2269 self.tentative_block_content_size(preferred_aspect_ratio);
2270 let tentative_block_size = if let Some(block_content_size) = tentative_block_content_size {
2271 SizeConstraint::Definite(content_box_sizes_and_pbm.content_box_sizes.block.resolve(
2272 Direction::Block,
2273 Size::FitContent,
2274 Au::zero,
2275 available_block_size,
2276 || block_content_size,
2277 is_table,
2278 ))
2279 } else {
2280 content_box_sizes_and_pbm
2281 .content_box_sizes
2282 .block
2283 .resolve_extrinsic(Size::FitContent, Au::zero(), available_block_size)
2284 };
2285
2286 let get_content_size = || {
2287 let constraint_space =
2288 ConstraintSpace::new(tentative_block_size, style, preferred_aspect_ratio);
2289 self.inline_content_sizes(layout_context, &constraint_space)
2290 .sizes
2291 };
2292
2293 let inline_size = content_box_sizes_and_pbm.content_box_sizes.inline.resolve(
2294 Direction::Inline,
2295 Size::FitContent,
2296 Au::zero,
2297 Some(available_inline_size),
2298 get_content_size,
2299 is_table,
2300 );
2301
2302 let containing_block_for_children = ContainingBlock {
2303 size: ContainingBlockSize {
2304 inline: inline_size,
2305 block: tentative_block_size,
2306 },
2307 style,
2308 };
2309 assert_eq!(
2310 container_writing_mode.is_horizontal(),
2311 style.writing_mode.is_horizontal(),
2312 "Mixed horizontal and vertical writing modes are not supported yet"
2313 );
2314
2315 let lazy_block_size = LazySize::new(
2316 &content_box_sizes_and_pbm.content_box_sizes.block,
2317 Direction::Block,
2318 Size::FitContent,
2319 Au::zero,
2320 available_block_size,
2321 is_table,
2322 );
2323
2324 let CacheableLayoutResult {
2325 content_inline_size_for_table,
2326 content_block_size,
2327 fragments,
2328 baselines,
2329 specific_layout_info,
2330 ..
2331 } = self.layout(
2332 layout_context,
2333 child_positioning_context,
2334 &containing_block_for_children,
2335 containing_block,
2336 preferred_aspect_ratio,
2337 &lazy_block_size,
2338 );
2339
2340 let content_size = LogicalVec2 {
2341 inline: content_inline_size_for_table.unwrap_or(inline_size),
2342 block: lazy_block_size.resolve(|| content_block_size),
2343 }
2344 .to_physical_size(container_writing_mode);
2345 let content_rect = PhysicalRect::new(PhysicalPoint::zero(), content_size);
2346
2347 let mut base_fragment_info = self.base_fragment_info();
2348 if content_box_sizes_and_pbm.depends_on_block_constraints {
2349 base_fragment_info.flags.insert(
2350 FragmentFlags::SIZE_DEPENDS_ON_BLOCK_CONSTRAINTS_AND_CAN_BE_CHILD_OF_FLEX_ITEM,
2351 );
2352 }
2353
2354 let fragment = BoxFragment::new(
2358 base_fragment_info,
2359 style.clone(),
2360 fragments,
2361 content_rect,
2362 pbm.padding.to_physical(container_writing_mode),
2363 pbm.border.to_physical(container_writing_mode),
2364 margin.to_physical(container_writing_mode),
2365 specific_layout_info,
2366 );
2367
2368 IndependentFloatOrAtomicLayoutResult {
2369 fragment,
2370 baselines,
2371 pbm_sums,
2372 }
2373 }
2374}