Skip to main content

layout/
formatting_contexts.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use app_units::Au;
6use atomic_refcell::AtomicRefCell;
7use layout_api::LayoutNode;
8use malloc_size_of_derive::MallocSizeOf;
9use script::layout_dom::{ServoDangerousStyleElement, ServoLayoutNode};
10use servo_arc::Arc;
11use style::context::SharedStyleContext;
12use style::logical_geometry::LogicalAxis;
13use style::properties::ComputedValues;
14use style::selector_parser::PseudoElement;
15
16use crate::context::LayoutContext;
17use crate::dom::{LayoutBox, NodeExt, WeakLayoutBox};
18use crate::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents};
19use crate::flexbox::FlexContainer;
20use crate::flow::BlockFormattingContext;
21use crate::flow::inline::InlineFormattingContext;
22use crate::fragment_tree::{BaseFragmentInfo, FragmentFlags};
23use crate::layout_box_base::{IndependentFormattingContextLayoutResult, LayoutBoxBase};
24use crate::positioned::{LayoutRootLayoutInputs, PositioningContext};
25use crate::replaced::ReplacedContents;
26use crate::sizing::{
27    self, ComputeInlineContentSizes, ContentSizes, InlineContentSizesResult, LazySize,
28    SizeConstraint,
29};
30use crate::style_ext::{AspectRatio, Display, DisplayInside, LayoutStyle};
31use crate::table::Table;
32use crate::taffy::TaffyContainer;
33use crate::{
34    ArcRefCell, ConstraintSpace, ContainingBlock, ContainingBlockSize, IndefiniteContainingBlock,
35    LogicalVec2, PropagatedBoxTreeData,
36};
37
38/// <https://drafts.csswg.org/css-display/#independent-formatting-context>
39#[derive(Debug, MallocSizeOf)]
40pub(crate) struct IndependentFormattingContext {
41    pub base: LayoutBoxBase,
42    // Private so that code outside of this module cannot match variants.
43    // It should go through methods instead.
44    contents: IndependentFormattingContextContents,
45    /// Data that was originally propagated down to this [`IndependentFormattingContext`]
46    /// during creation. This is used during incremental layout.
47    pub propagated_data: PropagatedBoxTreeData,
48    /// If this [`IndependentFormattingContext`] was a layout root, this stores the data
49    /// necessary to lay it out again.
50    pub layout_root_layout_inputs: AtomicRefCell<Option<Box<LayoutRootLayoutInputs>>>,
51}
52
53#[derive(Debug, MallocSizeOf)]
54pub(crate) enum IndependentFormattingContextContents {
55    // Additionally to the replaced contents, replaced boxes may have an inner widget.
56    Replaced(
57        ReplacedContents,
58        Option<ArcRefCell<IndependentFormattingContext>>,
59    ),
60    Flow(BlockFormattingContext),
61    Flex(FlexContainer),
62    Grid(TaffyContainer),
63    Table(Table),
64    // Other layout modes go here
65}
66
67impl IndependentFormattingContextContents {
68    fn subtree_size(&self) -> usize {
69        match self {
70            IndependentFormattingContextContents::Replaced(_, widget) => widget
71                .as_ref()
72                .map_or(0, |widget| widget.borrow().subtree_size()),
73            IndependentFormattingContextContents::Flow(block_formatting_context) => {
74                block_formatting_context.contents.subtree_size()
75            },
76            IndependentFormattingContextContents::Flex(flex_container) => {
77                flex_container.subtree_size()
78            },
79            IndependentFormattingContextContents::Grid(taffy_container) => {
80                taffy_container.subtree_size()
81            },
82            IndependentFormattingContextContents::Table(table) => table.subtree_size(),
83        }
84    }
85}
86
87/// The baselines of a layout or a [`crate::fragment_tree::BoxFragment`]. Some layout
88/// uses the first and some layout uses the last.
89#[derive(Clone, Copy, Debug, Default, MallocSizeOf)]
90pub(crate) struct Baselines {
91    pub first: Option<Au>,
92    pub last: Option<Au>,
93}
94
95impl Baselines {
96    pub(crate) fn offset(&self, block_offset: Au) -> Baselines {
97        Self {
98            first: self.first.map(|first| first + block_offset),
99            last: self.last.map(|last| last + block_offset),
100        }
101    }
102}
103
104impl IndependentFormattingContext {
105    pub(crate) fn new(
106        base: LayoutBoxBase,
107        contents: IndependentFormattingContextContents,
108        propagated_data: PropagatedBoxTreeData,
109    ) -> Self {
110        base.set_subtree_size(contents.subtree_size() + 1);
111        Self {
112            base,
113            contents,
114            propagated_data,
115            layout_root_layout_inputs: None.into(),
116        }
117    }
118
119    pub(crate) fn rebuild(
120        &mut self,
121        layout_context: &LayoutContext,
122        node_and_style_info: &NodeAndStyleInfo,
123    ) {
124        let contents = Contents::for_element(node_and_style_info.node, layout_context);
125        let display = match Display::from(node_and_style_info.style.get_box().display) {
126            Display::None | Display::Contents => {
127                unreachable!("Should never try to rebuild IndependentFormattingContext with no box")
128            },
129            Display::GeneratingBox(display) => {
130                display.used_value_for_contents(&contents, node_and_style_info)
131            },
132        };
133
134        // This ensures that the `FragmentFlags` of this `BaseFragmentInfo` reflect the
135        // current layout and not the set that was calculated during previous layouts.
136        self.base.base_fragment_info = node_and_style_info.into();
137
138        self.contents = Self::construct_contents(
139            layout_context,
140            node_and_style_info,
141            &mut self.base.base_fragment_info,
142            display.display_inside(),
143            contents,
144            self.propagated_data,
145        );
146
147        self.base.clear_fragments_and_dirty_fragment_cache();
148        *self.base.cached_inline_content_size.borrow_mut() = None;
149        self.base.repair_style(&node_and_style_info.style);
150    }
151
152    pub(crate) fn construct(
153        context: &LayoutContext,
154        node_and_style_info: &NodeAndStyleInfo,
155        display_inside: DisplayInside,
156        contents: Contents,
157        propagated_data: PropagatedBoxTreeData,
158    ) -> Self {
159        let mut base_fragment_info: BaseFragmentInfo = node_and_style_info.into();
160        let contents = Self::construct_contents(
161            context,
162            node_and_style_info,
163            &mut base_fragment_info,
164            display_inside,
165            contents,
166            propagated_data,
167        );
168
169        let base = LayoutBoxBase::new(base_fragment_info, node_and_style_info.style.clone());
170        base.set_subtree_size(contents.subtree_size() + 1);
171
172        Self {
173            base,
174            contents,
175            propagated_data,
176            layout_root_layout_inputs: None.into(),
177        }
178    }
179
180    fn construct_contents(
181        context: &LayoutContext,
182        node_and_style_info: &NodeAndStyleInfo,
183        base_fragment_info: &mut BaseFragmentInfo,
184        display_inside: DisplayInside,
185        contents: Contents,
186        propagated_data: PropagatedBoxTreeData,
187    ) -> IndependentFormattingContextContents {
188        let non_replaced_contents = match contents {
189            Contents::Replaced(contents) => {
190                base_fragment_info.flags.insert(FragmentFlags::IS_REPLACED);
191
192                // Some replaced elements can have inner widgets, e.g. `<video controls>`.
193                let node = node_and_style_info.node;
194                let should_make_widget = node.pseudo_element_chain().is_empty() &&
195                    node.is_root_of_user_agent_widget() &&
196                    !contents.is_content_replacement;
197                let widget = should_make_widget.then(|| {
198                    Self::construct_for_widget(context, node_and_style_info, propagated_data)
199                });
200
201                return IndependentFormattingContextContents::Replaced(contents, widget);
202            },
203            Contents::Widget(non_replaced_contents) => {
204                base_fragment_info.flags.insert(FragmentFlags::IS_WIDGET);
205                non_replaced_contents
206            },
207            Contents::NonReplaced(non_replaced_contents) => non_replaced_contents,
208        };
209
210        match display_inside {
211            DisplayInside::Flow { is_list_item } | DisplayInside::FlowRoot { is_list_item } => {
212                IndependentFormattingContextContents::Flow(BlockFormattingContext::construct(
213                    context,
214                    node_and_style_info,
215                    non_replaced_contents,
216                    propagated_data,
217                    is_list_item,
218                ))
219            },
220            DisplayInside::Grid => {
221                IndependentFormattingContextContents::Grid(TaffyContainer::construct(
222                    context,
223                    node_and_style_info,
224                    non_replaced_contents,
225                    propagated_data,
226                    base_fragment_info.flags,
227                ))
228            },
229            DisplayInside::Flex => {
230                IndependentFormattingContextContents::Flex(FlexContainer::construct(
231                    context,
232                    node_and_style_info,
233                    non_replaced_contents,
234                    propagated_data,
235                ))
236            },
237            DisplayInside::Table => {
238                let table_grid_style = context
239                    .style_context
240                    .stylist
241                    .style_for_anonymous::<ServoDangerousStyleElement>(
242                        &context.style_context.guards,
243                        &PseudoElement::ServoTableGrid,
244                        &node_and_style_info.style,
245                    );
246                base_fragment_info.flags.insert(FragmentFlags::DO_NOT_PAINT);
247                IndependentFormattingContextContents::Table(Table::construct(
248                    context,
249                    node_and_style_info,
250                    table_grid_style,
251                    non_replaced_contents,
252                    propagated_data,
253                ))
254            },
255        }
256    }
257
258    fn construct_for_widget(
259        context: &LayoutContext,
260        node_and_style_info: &NodeAndStyleInfo,
261        propagated_data: PropagatedBoxTreeData,
262    ) -> ArcRefCell<IndependentFormattingContext> {
263        let widget_info = node_and_style_info
264            .with_pseudo_element(context, PseudoElement::ServoAnonymousBox)
265            .expect("Should always be able to construct info for anonymous boxes.");
266        // Use a block formatting context for the widget, since the display inside is always flow.
267        let widget_contents =
268            IndependentFormattingContextContents::Flow(BlockFormattingContext::construct(
269                context,
270                &widget_info,
271                NonReplacedContents::OfElement,
272                propagated_data,
273                false, /* is_list_item */
274            ));
275
276        let box_slot = widget_info.node.box_slot();
277        let widget_base = LayoutBoxBase::new((&widget_info).into(), widget_info.style);
278        let widget = ArcRefCell::new(Self::new(widget_base, widget_contents, propagated_data));
279        box_slot.set(LayoutBox::Widget(widget.clone()));
280        widget
281    }
282
283    #[inline]
284    pub fn style(&self) -> &Arc<ComputedValues> {
285        &self.base.style
286    }
287
288    #[inline]
289    pub fn base_fragment_info(&self) -> BaseFragmentInfo {
290        self.base.base_fragment_info
291    }
292
293    pub(crate) fn inline_content_sizes(
294        &self,
295        layout_context: &LayoutContext,
296        constraint_space: &ConstraintSpace,
297    ) -> InlineContentSizesResult {
298        self.base
299            .inline_content_sizes(layout_context, constraint_space, &self.contents)
300    }
301
302    /// Computes the tentative intrinsic block sizes that may be needed while computing
303    /// the intrinsic inline sizes. Therefore, this ignores the values of the sizing
304    /// properties in both axes.
305    /// A return value of `None` indicates that there is no suitable tentative intrinsic
306    /// block size, so intrinsic keywords in the block sizing properties will be ignored,
307    /// possibly resulting in an indefinite [`SizeConstraint`] for computing the intrinsic
308    /// inline sizes and laying out the contents.
309    /// A return value of `Some` indicates that intrinsic keywords in the block sizing
310    /// properties will be resolved as the contained value, guaranteeing a definite amount
311    /// for computing the intrinsic inline sizes and laying out the contents.
312    pub(crate) fn tentative_block_content_size(
313        &self,
314        preferred_aspect_ratio: Option<AspectRatio>,
315        inline_stretch_size: Option<Au>,
316    ) -> Option<ContentSizes> {
317        let result = self.tentative_block_content_size_with_dependency(
318            preferred_aspect_ratio,
319            inline_stretch_size,
320        );
321        Some(result?.0)
322    }
323
324    /// Same as [`Self::tentative_block_content_size()`], but if there is a tentative intrinsic
325    /// block size, it also includes a bool which will be true if the former depends on
326    /// the provided `inline_stretch_size`.
327    pub(crate) fn tentative_block_content_size_with_dependency(
328        &self,
329        preferred_aspect_ratio: Option<AspectRatio>,
330        inline_stretch_size: Option<Au>,
331    ) -> Option<(ContentSizes, bool)> {
332        // See <https://github.com/w3c/csswg-drafts/issues/12333> regarding the difference
333        // in behavior for the replaced and non-replaced cases.
334        match &self.contents {
335            IndependentFormattingContextContents::Replaced(contents, _) => {
336                // For replaced elements with no ratio, the returned value doesn't matter.
337                let ratio = preferred_aspect_ratio?;
338                let writing_mode = self.style().writing_mode;
339                let natural_sizes = contents.logical_natural_sizes(writing_mode);
340                let (block_size, depends_on_inline_stretch_size) =
341                    match (natural_sizes.block, natural_sizes.inline) {
342                        (Some(block_size), None) => (block_size, false),
343                        (_, Some(inline_size)) => (
344                            ratio.compute_dependent_size(LogicalAxis::Block, inline_size),
345                            false,
346                        ),
347                        (None, None) => (
348                            ratio.compute_dependent_size(
349                                LogicalAxis::Block,
350                                inline_stretch_size.unwrap_or_default(),
351                            ),
352                            true,
353                        ),
354                    };
355                Some((block_size.into(), depends_on_inline_stretch_size))
356            },
357            _ => None,
358        }
359    }
360
361    pub(crate) fn outer_inline_content_sizes(
362        &self,
363        layout_context: &LayoutContext,
364        containing_block: &IndefiniteContainingBlock,
365        auto_minimum: &LogicalVec2<Au>,
366        auto_block_size_stretches_to_containing_block: bool,
367        skippable_for_block_percentage_quirk: bool,
368    ) -> InlineContentSizesResult {
369        sizing::outer_inline(
370            &self.base,
371            &self.layout_style(),
372            containing_block,
373            auto_minimum,
374            auto_block_size_stretches_to_containing_block,
375            self.is_replaced(),
376            true, /* establishes_containing_block */
377            skippable_for_block_percentage_quirk,
378            |padding_border_sums| self.preferred_aspect_ratio(padding_border_sums),
379            |constraint_space| self.inline_content_sizes(layout_context, constraint_space),
380            |preferred_aspect_ratio| {
381                self.tentative_block_content_size(preferred_aspect_ratio, None)
382            },
383        )
384    }
385
386    pub(crate) fn repair_style(
387        &mut self,
388        context: &SharedStyleContext,
389        node: &ServoLayoutNode,
390        new_style: &Arc<ComputedValues>,
391    ) {
392        self.base.repair_style(new_style);
393        match &mut self.contents {
394            IndependentFormattingContextContents::Replaced(replaced, ..) => {
395                *replaced.selected_style.borrow_mut() = node.selected_style(context);
396            },
397            IndependentFormattingContextContents::Flow(block_formatting_context) => {
398                block_formatting_context.repair_style(context, node, new_style);
399            },
400            IndependentFormattingContextContents::Flex(flex_container) => {
401                flex_container.repair_style(new_style)
402            },
403            IndependentFormattingContextContents::Grid(taffy_container) => {
404                taffy_container.repair_style(new_style)
405            },
406            IndependentFormattingContextContents::Table(table) => {
407                table.repair_style(context, new_style, &self.base)
408            },
409        }
410    }
411
412    #[inline]
413    pub(crate) fn is_block_container(&self) -> bool {
414        matches!(self.contents, IndependentFormattingContextContents::Flow(_))
415    }
416
417    #[inline]
418    pub(crate) fn is_replaced(&self) -> bool {
419        matches!(
420            self.contents,
421            IndependentFormattingContextContents::Replaced(_, _)
422        )
423    }
424
425    #[inline]
426    pub(crate) fn is_table(&self) -> bool {
427        matches!(
428            &self.contents,
429            IndependentFormattingContextContents::Table(_)
430        )
431    }
432
433    #[inline]
434    pub(crate) fn is_grid(&self) -> bool {
435        matches!(
436            &self.contents,
437            IndependentFormattingContextContents::Grid(_)
438        )
439    }
440
441    #[servo_tracing::instrument(
442        name = "IndependentFormattingContext::layout_without_caching",
443        skip_all
444    )]
445    fn layout_without_caching(
446        &self,
447        layout_context: &LayoutContext,
448        positioning_context: &mut PositioningContext,
449        containing_block_for_children: &ContainingBlock,
450        containing_block: &ContainingBlock,
451        preferred_aspect_ratio: Option<AspectRatio>,
452        lazy_block_size: &LazySize,
453    ) -> IndependentFormattingContextLayoutResult {
454        match &self.contents {
455            IndependentFormattingContextContents::Replaced(replaced, widget) => {
456                let mut replaced_layout = replaced.layout(
457                    layout_context,
458                    containing_block_for_children,
459                    preferred_aspect_ratio,
460                    &self.base,
461                    lazy_block_size,
462                );
463                // Widget should know the size of the replaced contents.
464                let resolved_block_size =
465                    lazy_block_size.resolve(|| replaced_layout.content_block_size);
466                let widget_cb = ContainingBlock {
467                    size: ContainingBlockSize {
468                        inline: containing_block_for_children.size.inline,
469                        block: SizeConstraint::Definite(resolved_block_size),
470                    },
471                    style: &self.base.style,
472                };
473                if let Some(widget) = widget {
474                    let mut widget_layout = widget.borrow().layout(
475                        layout_context,
476                        positioning_context,
477                        &widget_cb,
478                        &widget_cb,
479                        None,
480                        &LazySize::intrinsic(),
481                    );
482                    replaced_layout
483                        .fragments
484                        .append(&mut widget_layout.fragments);
485                }
486                replaced_layout
487            },
488            IndependentFormattingContextContents::Flow(bfc) => bfc.layout(
489                layout_context,
490                positioning_context,
491                containing_block_for_children,
492                lazy_block_size,
493                Some(&self.base),
494            ),
495            IndependentFormattingContextContents::Flex(fc) => fc.layout(
496                layout_context,
497                positioning_context,
498                containing_block_for_children,
499                lazy_block_size,
500            ),
501            IndependentFormattingContextContents::Grid(fc) => fc.layout(
502                layout_context,
503                positioning_context,
504                containing_block_for_children,
505                containing_block,
506            ),
507            IndependentFormattingContextContents::Table(table) => table.layout(
508                layout_context,
509                positioning_context,
510                containing_block_for_children,
511                containing_block,
512            ),
513        }
514    }
515
516    pub(crate) fn layout_and_is_cached(
517        &self,
518        layout_context: &LayoutContext,
519        positioning_context: &mut PositioningContext,
520        containing_block_for_children: &ContainingBlock,
521        containing_block: &ContainingBlock,
522        preferred_aspect_ratio: Option<AspectRatio>,
523        lazy_block_size: &LazySize,
524    ) -> (IndependentFormattingContextLayoutResult, bool) {
525        let content_block_size_under_default_constraint = match self
526            .base
527            .cached_independent_formatting_context_layout_if_applicable(
528                positioning_context,
529                containing_block_for_children,
530            ) {
531            Ok(cached_layout_result) => return (cached_layout_result, true),
532            Err(v) => v,
533        };
534
535        #[cfg(feature = "tracing")]
536        tracing::debug!(
537            name: "IndependentFormattingContext::layout cache miss",
538            required = ?containing_block_for_children.size,
539        );
540        let mut child_positioning_context = PositioningContext::default();
541        let result = self.layout_without_caching(
542            layout_context,
543            &mut child_positioning_context,
544            containing_block_for_children,
545            containing_block,
546            preferred_aspect_ratio,
547            lazy_block_size,
548        );
549        self.base.cache_independent_formatting_context_layout(
550            containing_block_for_children,
551            &child_positioning_context,
552            content_block_size_under_default_constraint,
553            &result,
554        );
555        positioning_context.append(child_positioning_context);
556        (result, false)
557    }
558
559    pub(crate) fn layout(
560        &self,
561        layout_context: &LayoutContext,
562        positioning_context: &mut PositioningContext,
563        containing_block_for_children: &ContainingBlock,
564        containing_block: &ContainingBlock,
565        preferred_aspect_ratio: Option<AspectRatio>,
566        lazy_block_size: &LazySize,
567    ) -> IndependentFormattingContextLayoutResult {
568        self.layout_and_is_cached(
569            layout_context,
570            positioning_context,
571            containing_block_for_children,
572            containing_block,
573            preferred_aspect_ratio,
574            lazy_block_size,
575        )
576        .0
577    }
578
579    pub(crate) fn content_block_size_under_default_constraint(
580        &self,
581        layout_context: &LayoutContext,
582        positioning_context: &mut PositioningContext,
583        inline_size: Au,
584        containing_block: &ContainingBlock,
585        preferred_aspect_ratio: Option<AspectRatio>,
586        lazy_block_size: &LazySize,
587    ) -> Au {
588        if let Some(content_block_size) = self
589            .base
590            .cached_content_block_size_under_default_constraint_if_applicable(inline_size)
591        {
592            return content_block_size;
593        }
594        self.layout(
595            layout_context,
596            positioning_context,
597            &ContainingBlock {
598                size: ContainingBlockSize {
599                    inline: inline_size,
600                    block: SizeConstraint::default(),
601                },
602                style: self.style(),
603            },
604            containing_block,
605            preferred_aspect_ratio,
606            lazy_block_size,
607        )
608        .content_block_size
609    }
610
611    #[inline]
612    pub(crate) fn layout_style(&self) -> LayoutStyle<'_> {
613        match &self.contents {
614            IndependentFormattingContextContents::Replaced(replaced, _) => {
615                replaced.layout_style(&self.base)
616            },
617            IndependentFormattingContextContents::Flow(fc) => fc.layout_style(&self.base),
618            IndependentFormattingContextContents::Flex(fc) => fc.layout_style(),
619            IndependentFormattingContextContents::Grid(fc) => fc.layout_style(),
620            IndependentFormattingContextContents::Table(fc) => fc.layout_style(None),
621        }
622    }
623
624    #[inline]
625    pub(crate) fn preferred_aspect_ratio(
626        &self,
627        padding_border_sums: &LogicalVec2<Au>,
628    ) -> Option<AspectRatio> {
629        match &self.contents {
630            IndependentFormattingContextContents::Replaced(replaced, _) => {
631                replaced.preferred_aspect_ratio(self.style(), padding_border_sums)
632            },
633            // TODO: support preferred aspect ratios on non-replaced boxes.
634            _ => None,
635        }
636    }
637
638    pub(crate) fn attached_to_tree(&self, layout_box: WeakLayoutBox) {
639        match &self.contents {
640            IndependentFormattingContextContents::Replaced(_, widget) => {
641                if let Some(widget) = widget {
642                    widget.borrow_mut().base.parent_box.replace(layout_box);
643                }
644            },
645            IndependentFormattingContextContents::Flow(contents) => {
646                contents.attached_to_tree(layout_box)
647            },
648            IndependentFormattingContextContents::Flex(contents) => {
649                contents.attached_to_tree(layout_box)
650            },
651            IndependentFormattingContextContents::Grid(contents) => {
652                contents.attached_to_tree(layout_box)
653            },
654            IndependentFormattingContextContents::Table(contents) => {
655                contents.attached_to_tree(layout_box)
656            },
657        }
658    }
659
660    pub(crate) fn subtree_size(&self) -> usize {
661        self.base.subtree_size()
662    }
663
664    /// Set whether this [`IndependentFormattingContext`] is selected. Returns `true` if
665    /// anything changed.
666    pub(crate) fn set_selection(&self, selected: bool) -> bool {
667        match &self.contents {
668            IndependentFormattingContextContents::Replaced(replaced_contents, ..) => {
669                replaced_contents.set_selection(selected)
670            },
671            _ => false,
672        }
673    }
674
675    pub(crate) fn inline_formatting_context(&self) -> Option<&InlineFormattingContext> {
676        match &self.contents {
677            IndependentFormattingContextContents::Flow(block_formatting_context) => {
678                block_formatting_context.inline_formatting_context()
679            },
680            _ => None,
681        }
682    }
683}
684
685impl ComputeInlineContentSizes for IndependentFormattingContextContents {
686    fn compute_inline_content_sizes(
687        &self,
688        layout_context: &LayoutContext,
689        constraint_space: &ConstraintSpace,
690    ) -> InlineContentSizesResult {
691        match self {
692            Self::Replaced(inner, _) => {
693                inner.compute_inline_content_sizes(layout_context, constraint_space)
694            },
695            Self::Flow(inner) => inner
696                .contents
697                .compute_inline_content_sizes(layout_context, constraint_space),
698            Self::Flex(inner) => {
699                inner.compute_inline_content_sizes(layout_context, constraint_space)
700            },
701            Self::Grid(inner) => {
702                inner.compute_inline_content_sizes(layout_context, constraint_space)
703            },
704            Self::Table(inner) => {
705                inner.compute_inline_content_sizes(layout_context, constraint_space)
706            },
707        }
708    }
709}