1use std::cell::{Cell, LazyCell, OnceCell};
8use std::ops::{Add, AddAssign};
9use std::sync::atomic::Ordering;
10
11use app_units::{Au, MAX_AU};
12use malloc_size_of_derive::MallocSizeOf;
13use style::Zero;
14use style::logical_geometry::LogicalAxis;
15use style::values::computed::{
16 LengthPercentage, MaxSize as StyleMaxSize, Percentage, Size as StyleSize,
17};
18
19use crate::context::LayoutContext;
20use crate::layout_box_base::LayoutBoxBase;
21use crate::style_ext::{AspectRatio, Clamp, ComputedValuesExt, ContentBoxSizesAndPBM, LayoutStyle};
22use crate::{ConstraintSpace, IndefiniteContainingBlock, LogicalVec2};
23
24#[derive(PartialEq)]
25pub(crate) enum IntrinsicSizingMode {
26 Contribution,
32 Size,
38}
39
40#[derive(Clone, Copy, Debug, Default, MallocSizeOf)]
41pub(crate) struct ContentSizes {
42 pub min_content: Au,
43 pub max_content: Au,
44}
45
46impl ContentSizes {
48 pub fn max(&self, other: Self) -> Self {
49 Self {
50 min_content: self.min_content.max(other.min_content),
51 max_content: self.max_content.max(other.max_content),
52 }
53 }
54
55 pub fn max_assign(&mut self, other: Self) {
56 *self = self.max(other);
57 }
58
59 pub fn union(&self, other: &Self) -> Self {
60 Self {
61 min_content: self.min_content.max(other.min_content),
62 max_content: self.max_content + other.max_content,
63 }
64 }
65
66 pub fn union_assign(&mut self, other: &Self) {
67 self.min_content.max_assign(other.min_content);
68 self.max_content += other.max_content;
69 }
70
71 pub fn map(&self, f: impl Fn(Au) -> Au) -> Self {
72 Self {
73 min_content: f(self.min_content),
74 max_content: f(self.max_content),
75 }
76 }
77}
78
79impl Zero for ContentSizes {
80 fn zero() -> Self {
81 Au::zero().into()
82 }
83
84 fn is_zero(&self) -> bool {
85 self.min_content.is_zero() && self.max_content.is_zero()
86 }
87}
88
89impl Add for ContentSizes {
90 type Output = Self;
91
92 fn add(self, rhs: Self) -> Self {
93 Self {
94 min_content: self.min_content + rhs.min_content,
95 max_content: self.max_content + rhs.max_content,
96 }
97 }
98}
99
100impl AddAssign for ContentSizes {
101 fn add_assign(&mut self, rhs: Self) {
102 *self = self.add(rhs)
103 }
104}
105
106impl ContentSizes {
107 pub fn shrink_to_fit(&self, available_size: Au) -> Au {
112 available_size.min(self.max_content).max(self.min_content)
116 }
117}
118
119impl From<Au> for ContentSizes {
120 fn from(size: Au) -> Self {
121 Self {
122 min_content: size,
123 max_content: size,
124 }
125 }
126}
127
128#[expect(clippy::too_many_arguments)]
129pub(crate) fn outer_inline(
130 base: &LayoutBoxBase,
131 layout_style: &LayoutStyle,
132 containing_block: &IndefiniteContainingBlock,
133 auto_minimum: &LogicalVec2<Au>,
134 auto_block_size_stretches_to_containing_block: bool,
135 is_replaced: bool,
136 establishes_containing_block: bool,
137 skippable_for_block_percentage_quirk: bool,
138 get_preferred_aspect_ratio: impl FnOnce(&LogicalVec2<Au>) -> Option<AspectRatio>,
139 get_inline_content_size: impl FnOnce(&ConstraintSpace) -> InlineContentSizesResult,
140 get_tentative_block_content_size: impl FnOnce(Option<AspectRatio>) -> Option<ContentSizes>,
141) -> InlineContentSizesResult {
142 let ContentBoxSizesAndPBM {
143 content_box_sizes,
144 pbm,
145 mut depends_on_block_constraints,
146 preferred_size_computes_to_auto,
147 } = layout_style.content_box_sizes_and_padding_border_margin(containing_block);
148 let margin = pbm.margin.map(|v| v.auto_is(Au::zero));
149 let pbm_sums = LogicalVec2 {
150 block: pbm.padding_border_sums.block + margin.block_sum(),
151 inline: pbm.padding_border_sums.inline + margin.inline_sum(),
152 };
153 let style = layout_style.style();
154 let is_table = layout_style.is_table();
155 let depends_on_contents = Cell::new(false);
158 let content_size = LazyCell::new(|| {
159 depends_on_contents.set(true);
160 let constraint_space = if establishes_containing_block {
161 let block_stretch_size = containing_block.block_stretch_size(pbm_sums.block);
162 let automatic_size = if preferred_size_computes_to_auto.block &&
163 auto_block_size_stretches_to_containing_block
164 {
165 depends_on_block_constraints = true;
166 Size::Stretch
167 } else {
168 Size::FitContent
169 };
170 let aspect_ratio = get_preferred_aspect_ratio(&pbm.padding_border_sums);
171 let mut block_size =
172 if let Some(block_content_size) = get_tentative_block_content_size(aspect_ratio) {
173 SizeConstraint::Definite(content_box_sizes.block.resolve(
174 LogicalAxis::Block,
175 automatic_size,
176 || auto_minimum.block,
177 block_stretch_size,
178 || block_content_size,
179 is_table,
180 ))
181 } else {
182 content_box_sizes.block.resolve_extrinsic(
183 automatic_size,
184 auto_minimum.block,
185 block_stretch_size,
186 )
187 };
188 if skippable_for_block_percentage_quirk {
189 block_size.replace_if_indefinite_with(containing_block.size.block.into())
190 }
191 ConstraintSpace::new(block_size, style, aspect_ratio)
192 } else {
193 depends_on_block_constraints = true;
197 ConstraintSpace::new(
201 containing_block.size.block.into(),
202 containing_block.style,
203 None,
204 )
205 };
206 get_inline_content_size(&constraint_space)
207 });
208 let resolve_non_initial = |inline_size, stretch_values| {
209 Some(match inline_size {
210 Size::Initial => return None,
211 Size::Numeric(numeric) => (numeric, numeric, false),
212 Size::MinContent => (
213 content_size.sizes.min_content,
214 content_size.sizes.min_content,
215 content_size.depends_on_block_constraints,
216 ),
217 Size::MaxContent => (
218 content_size.sizes.max_content,
219 content_size.sizes.max_content,
220 content_size.depends_on_block_constraints,
221 ),
222 Size::FitContent => (
223 content_size.sizes.min_content,
224 content_size.sizes.max_content,
225 content_size.depends_on_block_constraints,
226 ),
227 Size::FitContentFunction(size) => {
228 let size = content_size.sizes.shrink_to_fit(size);
229 (size, size, content_size.depends_on_block_constraints)
230 },
231 Size::Stretch => return stretch_values,
232 Size::QuirkyStretch => unreachable!("Quirky stretch can't be an inline size"),
233 })
234 };
235 let (mut preferred_min_content, preferred_max_content, preferred_depends_on_block_constraints) =
236 resolve_non_initial(content_box_sizes.inline.preferred, None)
237 .unwrap_or_else(|| resolve_non_initial(Size::FitContent, None).unwrap());
238 let (mut min_min_content, mut min_max_content, mut min_depends_on_block_constraints) =
239 resolve_non_initial(
240 content_box_sizes.inline.min,
241 Some((Au::zero(), Au::zero(), false)),
242 )
243 .unwrap_or((auto_minimum.inline, auto_minimum.inline, false));
244 let (mut max_min_content, max_max_content, max_depends_on_block_constraints) =
245 resolve_non_initial(content_box_sizes.inline.max, None)
246 .map(|(min_content, max_content, depends_on_block_constraints)| {
247 (
248 Some(min_content),
249 Some(max_content),
250 depends_on_block_constraints,
251 )
252 })
253 .unwrap_or_default();
254
255 if is_replaced {
263 let has_percentage = |size: Size<LengthPercentage>| {
264 matches!(size, Size::Numeric(numeric) if numeric.has_percentage())
266 };
267 let writing_mode = containing_block.style.writing_mode;
268 if content_box_sizes.inline.preferred.is_initial() &&
269 has_percentage(style.box_size(writing_mode).inline)
270 {
271 preferred_min_content = Au::zero();
272 }
273 if content_box_sizes.inline.max.is_initial() &&
274 has_percentage(style.max_box_size(writing_mode).inline)
275 {
276 max_min_content = Some(Au::zero());
277 }
278 }
279
280 if is_table {
283 min_min_content.max_assign(content_size.sizes.min_content);
284 min_max_content.max_assign(content_size.sizes.min_content);
285 min_depends_on_block_constraints |= content_size.depends_on_block_constraints;
286 }
287
288 base.outer_inline_content_sizes_depend_on_content
289 .store(depends_on_contents.get(), Ordering::Relaxed);
290 InlineContentSizesResult {
291 sizes: ContentSizes {
292 min_content: preferred_min_content
293 .clamp_between_extremums(min_min_content, max_min_content) +
294 pbm_sums.inline,
295 max_content: preferred_max_content
296 .clamp_between_extremums(min_max_content, max_max_content) +
297 pbm_sums.inline,
298 },
299 depends_on_block_constraints: depends_on_block_constraints &&
300 (preferred_depends_on_block_constraints ||
301 min_depends_on_block_constraints ||
302 max_depends_on_block_constraints),
303 }
304}
305
306#[derive(Clone, Copy, Debug, MallocSizeOf)]
307pub(crate) struct InlineContentSizesResult {
308 pub sizes: ContentSizes,
309 pub depends_on_block_constraints: bool,
310}
311
312pub(crate) trait ComputeInlineContentSizes {
313 fn compute_inline_content_sizes(
314 &self,
315 layout_context: &LayoutContext,
316 constraint_space: &ConstraintSpace,
317 ) -> InlineContentSizesResult;
318
319 fn compute_inline_content_sizes_with_fixup(
323 &self,
324 layout_context: &LayoutContext,
325 constraint_space: &ConstraintSpace,
326 ) -> InlineContentSizesResult {
327 let mut result = self.compute_inline_content_sizes(layout_context, constraint_space);
328 let sizes = &mut result.sizes;
329 sizes.max_content.max_assign(sizes.min_content);
330 result
331 }
332}
333
334#[derive(Clone, Debug, PartialEq)]
337pub(crate) enum Size<T> {
338 Initial,
343 MinContent,
345 MaxContent,
347 FitContent,
349 FitContentFunction(T),
351 Stretch,
353 QuirkyStretch,
359 Numeric(T),
362}
363
364impl<T: Copy> Copy for Size<T> {}
365
366impl<T> Default for Size<T> {
367 #[inline]
368 fn default() -> Self {
369 Self::Initial
370 }
371}
372
373impl<T> Size<T> {
374 #[inline]
375 pub(crate) fn is_initial(&self) -> bool {
376 matches!(self, Self::Initial)
377 }
378}
379
380impl<T: Clone> Size<T> {
381 #[inline]
382 pub(crate) fn to_numeric(&self) -> Option<T> {
383 match self {
384 Self::Numeric(numeric) => Some(numeric).cloned(),
385 _ => None,
386 }
387 }
388
389 #[inline]
390 pub(crate) fn map<U>(&self, f: impl FnOnce(T) -> U) -> Size<U> {
391 match self {
392 Size::Initial => Size::Initial,
393 Size::MinContent => Size::MinContent,
394 Size::MaxContent => Size::MaxContent,
395 Size::FitContent => Size::FitContent,
396 Size::FitContentFunction(size) => Size::FitContentFunction(f(size.clone())),
397 Size::Stretch => Size::Stretch,
398 Size::QuirkyStretch => Size::QuirkyStretch,
399 Size::Numeric(numeric) => Size::Numeric(f(numeric.clone())),
400 }
401 }
402}
403
404impl From<&StyleSize> for Size<LengthPercentage> {
405 fn from(size: &StyleSize) -> Self {
406 match size {
407 StyleSize::LengthPercentage(lp) => Size::Numeric(lp.0.clone()),
408 StyleSize::Auto => Size::Initial,
409 StyleSize::MinContent => Size::MinContent,
410 StyleSize::MaxContent => Size::MaxContent,
411 StyleSize::FitContent => Size::FitContent,
412 StyleSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0.clone()),
413 StyleSize::Stretch | StyleSize::WebkitFillAvailable => Size::Stretch,
414 StyleSize::AnchorSizeFunction(_) | StyleSize::AnchorContainingCalcFunction(_) => {
415 unreachable!("anchor-size() should be disabled")
416 },
417 }
418 }
419}
420
421impl From<&StyleMaxSize> for Size<LengthPercentage> {
422 fn from(max_size: &StyleMaxSize) -> Self {
423 match max_size {
424 StyleMaxSize::LengthPercentage(lp) => Size::Numeric(lp.0.clone()),
425 StyleMaxSize::None => Size::Initial,
426 StyleMaxSize::MinContent => Size::MinContent,
427 StyleMaxSize::MaxContent => Size::MaxContent,
428 StyleMaxSize::FitContent => Size::FitContent,
429 StyleMaxSize::FitContentFunction(lp) => Size::FitContentFunction(lp.0.clone()),
430 StyleMaxSize::Stretch | StyleMaxSize::WebkitFillAvailable => Size::Stretch,
431 StyleMaxSize::AnchorSizeFunction(_) | StyleMaxSize::AnchorContainingCalcFunction(_) => {
432 unreachable!("anchor-size() should be disabled")
433 },
434 }
435 }
436}
437
438impl Size<LengthPercentage> {
439 #[inline]
440 pub(crate) fn to_percentage(&self) -> Option<Percentage> {
441 self.to_numeric()
442 .and_then(|length_percentage| length_percentage.to_percentage())
443 }
444
445 #[inline]
450 pub(crate) fn resolve_percentages_for_preferred(&self, basis: Option<Au>) -> Size<Au> {
451 match self {
452 Size::Numeric(numeric) => numeric
453 .maybe_to_used_value(basis)
454 .map_or(Size::Initial, Size::Numeric),
455 Size::FitContentFunction(numeric) => {
456 numeric
458 .maybe_to_used_value(basis)
459 .map_or(Size::FitContent, Size::FitContentFunction)
460 },
461 _ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
462 }
463 }
464
465 #[inline]
470 pub(crate) fn resolve_percentages_for_max(&self, basis: Option<Au>) -> Size<Au> {
471 match self {
472 Size::Numeric(numeric) => numeric
473 .maybe_to_used_value(basis)
474 .map_or(Size::Initial, Size::Numeric),
475 Size::FitContentFunction(numeric) => {
476 numeric
478 .maybe_to_used_value(basis)
479 .map_or(Size::MaxContent, Size::FitContentFunction)
480 },
481 _ => self.map(|_| unreachable!("This shouldn't be called for keywords")),
482 }
483 }
484}
485
486impl LogicalVec2<Size<LengthPercentage>> {
487 pub(crate) fn percentages_relative_to_basis(
488 &self,
489 basis: &LogicalVec2<Au>,
490 ) -> LogicalVec2<Size<Au>> {
491 LogicalVec2 {
492 inline: self.inline.map(|value| value.to_used_value(basis.inline)),
493 block: self.block.map(|value| value.to_used_value(basis.block)),
494 }
495 }
496}
497
498impl Size<Au> {
499 #[inline]
502 pub(crate) fn resolve_for_preferred<F: FnOnce() -> ContentSizes>(
503 &self,
504 automatic_size: Size<Au>,
505 stretch_size: Option<Au>,
506 content_size: &LazyCell<ContentSizes, F>,
507 ) -> Au {
508 match self {
509 Self::Initial => {
510 assert!(!automatic_size.is_initial());
511 automatic_size.resolve_for_preferred(automatic_size, stretch_size, content_size)
512 },
513 Self::MinContent => content_size.min_content,
514 Self::MaxContent => content_size.max_content,
515 Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
516 Self::FitContent => {
517 content_size.shrink_to_fit(stretch_size.unwrap_or_else(|| content_size.max_content))
518 },
519 Self::Stretch => stretch_size.unwrap_or_else(|| content_size.max_content),
520 Self::QuirkyStretch => stretch_size
521 .unwrap_or_else(|| content_size.max_content)
522 .max(content_size.min_content),
523 Self::Numeric(numeric) => *numeric,
524 }
525 }
526
527 #[inline]
530 pub(crate) fn resolve_for_min<F: FnOnce() -> ContentSizes>(
531 &self,
532 get_automatic_minimum_size: impl FnOnce() -> Au,
533 stretch_size: Option<Au>,
534 content_size: &LazyCell<ContentSizes, F>,
535 is_table: bool,
536 ) -> Au {
537 let result = match self {
538 Self::Initial => get_automatic_minimum_size(),
539 Self::MinContent => content_size.min_content,
540 Self::MaxContent => content_size.max_content,
541 Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
542 Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or_default()),
543 Self::Stretch => stretch_size.unwrap_or_default(),
544 Self::QuirkyStretch => unreachable!("Quirky stretch can't be a min size"),
545 Self::Numeric(numeric) => *numeric,
546 };
547 if is_table {
548 result.max(content_size.min_content)
557 } else {
558 result
559 }
560 }
561
562 #[inline]
565 pub(crate) fn resolve_for_max<F: FnOnce() -> ContentSizes>(
566 &self,
567 stretch_size: Option<Au>,
568 content_size: &LazyCell<ContentSizes, F>,
569 ) -> Option<Au> {
570 Some(match self {
571 Self::Initial => return None,
572 Self::MinContent => content_size.min_content,
573 Self::MaxContent => content_size.max_content,
574 Self::FitContentFunction(size) => content_size.shrink_to_fit(*size),
575 Self::FitContent => content_size.shrink_to_fit(stretch_size.unwrap_or(MAX_AU)),
576 Self::Stretch => return stretch_size,
577 Self::QuirkyStretch => unreachable!("Quirky stretch can't be a max size"),
578 Self::Numeric(numeric) => *numeric,
579 })
580 }
581
582 #[inline]
592 pub(crate) fn maybe_resolve_extrinsic(&self, stretch_size: Option<Au>) -> Option<Au> {
593 match self {
594 Self::Initial |
595 Self::MinContent |
596 Self::MaxContent |
597 Self::FitContent |
598 Self::FitContentFunction(_) => None,
599 Self::Stretch | Self::QuirkyStretch => stretch_size,
600 Self::Numeric(numeric) => Some(*numeric),
601 }
602 }
603}
604
605#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq)]
608pub(crate) enum SizeConstraint {
609 Definite(Au),
611 MinMax(Au, Option<Au>),
614}
615
616impl Default for SizeConstraint {
617 #[inline]
618 fn default() -> Self {
619 Self::MinMax(Au::default(), None)
620 }
621}
622
623impl SizeConstraint {
624 #[inline]
625 pub(crate) fn new(preferred_size: Option<Au>, min_size: Au, max_size: Option<Au>) -> Self {
626 preferred_size.map_or_else(
627 || Self::MinMax(min_size, max_size),
628 |size| Self::Definite(size.clamp_between_extremums(min_size, max_size)),
629 )
630 }
631
632 #[inline]
633 pub(crate) fn is_definite(self) -> bool {
634 matches!(self, Self::Definite(_))
635 }
636
637 #[inline]
638 pub(crate) fn to_definite(self) -> Option<Au> {
639 match self {
640 Self::Definite(size) => Some(size),
641 _ => None,
642 }
643 }
644
645 #[inline]
646 pub(crate) fn definite_or_min(self) -> Au {
647 match self {
648 Self::Definite(size) => size,
649 Self::MinMax(min, _) => min,
650 }
651 }
652
653 #[inline]
654 pub(crate) fn replace_if_indefinite_with(&mut self, replacement: Self) {
655 if !self.is_definite() {
656 *self = replacement
657 }
658 }
659}
660
661impl From<Option<Au>> for SizeConstraint {
662 fn from(size: Option<Au>) -> Self {
663 size.map(SizeConstraint::Definite).unwrap_or_default()
664 }
665}
666
667#[derive(Clone, Debug, Default)]
668pub(crate) struct Sizes {
669 pub preferred: Size<Au>,
671 pub min: Size<Au>,
673 pub max: Size<Au>,
675}
676
677impl Sizes {
678 #[inline]
679 pub(crate) fn new(preferred: Size<Au>, min: Size<Au>, max: Size<Au>) -> Self {
680 Self {
681 preferred,
682 min,
683 max,
684 }
685 }
686
687 #[inline]
689 pub(crate) fn resolve(
690 &self,
691 axis: LogicalAxis,
692 automatic_size: Size<Au>,
693 get_automatic_minimum_size: impl FnOnce() -> Au,
694 stretch_size: Option<Au>,
695 get_content_size: impl FnOnce() -> ContentSizes,
696 is_table: bool,
697 ) -> Au {
698 if is_table && axis == LogicalAxis::Block {
699 return get_content_size().max_content;
704 }
705 let (preferred, min, max) = self.resolve_each(
706 automatic_size,
707 get_automatic_minimum_size,
708 stretch_size,
709 get_content_size,
710 is_table,
711 );
712 preferred.clamp_between_extremums(min, max)
713 }
714
715 #[inline]
720 pub(crate) fn resolve_each(
721 &self,
722 automatic_size: Size<Au>,
723 get_automatic_minimum_size: impl FnOnce() -> Au,
724 stretch_size: Option<Au>,
725 get_content_size: impl FnOnce() -> ContentSizes,
726 is_table: bool,
727 ) -> (Au, Au, Option<Au>) {
728 let content_size = LazyCell::new(get_content_size);
731 (
732 self.preferred
733 .resolve_for_preferred(automatic_size, stretch_size, &content_size),
734 self.min.resolve_for_min(
735 get_automatic_minimum_size,
736 stretch_size,
737 &content_size,
738 is_table,
739 ),
740 self.max.resolve_for_max(stretch_size, &content_size),
741 )
742 }
743
744 #[inline]
750 pub(crate) fn resolve_extrinsic(
751 &self,
752 automatic_size: Size<Au>,
753 automatic_minimum_size: Au,
754 stretch_size: Option<Au>,
755 ) -> SizeConstraint {
756 let (preferred, min, max) =
757 self.resolve_each_extrinsic(automatic_size, automatic_minimum_size, stretch_size);
758 SizeConstraint::new(preferred, min, max)
759 }
760
761 #[inline]
771 pub(crate) fn resolve_each_extrinsic(
772 &self,
773 automatic_size: Size<Au>,
774 automatic_minimum_size: Au,
775 stretch_size: Option<Au>,
776 ) -> (Option<Au>, Au, Option<Au>) {
777 (
778 if self.preferred.is_initial() {
779 automatic_size.maybe_resolve_extrinsic(stretch_size)
780 } else {
781 self.preferred.maybe_resolve_extrinsic(stretch_size)
782 },
783 self.min
784 .maybe_resolve_extrinsic(stretch_size)
785 .unwrap_or(automatic_minimum_size),
786 self.max.maybe_resolve_extrinsic(stretch_size),
787 )
788 }
789}
790
791struct LazySizeData<'a> {
792 sizes: &'a Sizes,
793 axis: LogicalAxis,
794 automatic_size: Size<Au>,
795 get_automatic_minimum_size: fn() -> Au,
796 stretch_size: Option<Au>,
797 is_table: bool,
798}
799
800pub(crate) struct LazySize<'a> {
804 result: OnceCell<Au>,
805 data: Option<LazySizeData<'a>>,
806}
807
808impl<'a> LazySize<'a> {
809 pub(crate) fn new(
810 sizes: &'a Sizes,
811 axis: LogicalAxis,
812 automatic_size: Size<Au>,
813 get_automatic_minimum_size: fn() -> Au,
814 stretch_size: Option<Au>,
815 is_table: bool,
816 ) -> Self {
817 Self {
818 result: OnceCell::new(),
819 data: Some(LazySizeData {
820 sizes,
821 axis,
822 automatic_size,
823 get_automatic_minimum_size,
824 stretch_size,
825 is_table,
826 }),
827 }
828 }
829
830 pub(crate) fn intrinsic() -> Self {
838 Self {
839 result: OnceCell::new(),
840 data: None,
841 }
842 }
843
844 pub(crate) fn resolve(&self, get_content_size: impl FnOnce() -> Au) -> Au {
849 *self.result.get_or_init(|| {
850 let Some(ref data) = self.data else {
851 return get_content_size();
852 };
853 data.sizes.resolve(
854 data.axis,
855 data.automatic_size,
856 data.get_automatic_minimum_size,
857 data.stretch_size,
858 || get_content_size().into(),
859 data.is_table,
860 )
861 })
862 }
863}
864
865impl From<Au> for LazySize<'_> {
866 fn from(value: Au) -> Self {
869 let result = OnceCell::new();
870 result.set(value).unwrap();
871 LazySize { result, data: None }
872 }
873}