Skip to main content

layout/
containing_block.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 malloc_size_of_derive::MallocSizeOf;
7use num_traits::Zero;
8use servo_arc::Arc as ServoArc;
9use style::properties::ComputedValues;
10
11use crate::geom::LogicalVec2;
12use crate::sizing::SizeConstraint;
13use crate::style_ext::AspectRatio;
14
15/// Whether the block size of a containing block was affected by the percentage quirk.
16/// If true, it means the actual block size is indefinite, but it has been overriden
17/// with a definite amount, in order to resolve percentages in quirks mode.
18/// <https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk>
19#[derive(Clone, Copy, Debug, Default, MallocSizeOf, PartialEq)]
20pub(crate) struct HasQuirkyBlockSize(pub bool);
21
22/// Represents the set of constraints that we use when computing the min-content
23/// and max-content inline sizes of an element.
24pub(crate) struct ConstraintSpace<'a> {
25    pub block_size: SizeConstraint,
26    pub has_quirky_block_size: HasQuirkyBlockSize,
27    pub style: &'a ComputedValues,
28    pub preferred_aspect_ratio: Option<AspectRatio>,
29}
30
31impl<'a> ConstraintSpace<'a> {
32    pub fn new(
33        block_size: SizeConstraint,
34        has_quirky_block_size: HasQuirkyBlockSize,
35        style: &'a ComputedValues,
36        preferred_aspect_ratio: Option<AspectRatio>,
37    ) -> Self {
38        Self {
39            block_size,
40            has_quirky_block_size,
41            style,
42            preferred_aspect_ratio,
43        }
44    }
45}
46
47#[inline]
48fn inline_stretch_size(inline_size: Option<Au>, inline_pbm_sum: Au) -> Option<Au> {
49    inline_size.map(|size| Au::zero().max(size - inline_pbm_sum))
50}
51
52#[inline]
53fn block_stretch_size(
54    block_size: Option<Au>,
55    has_quirky_block_size: HasQuirkyBlockSize,
56    block_pbm_sum: Au,
57) -> Option<Au> {
58    if has_quirky_block_size.0 {
59        // The actual block size of the containing block is indefinite,
60        // but the value was overridden in order to resolve percentages.
61        // However, now we are resolving `stretch` instead of a percentage.
62        return None;
63    }
64    block_size.map(|size| Au::zero().max(size - block_pbm_sum))
65}
66
67#[derive(Default)]
68pub(crate) struct IndefiniteContainingBlockSize {
69    pub inline: Option<Au>,
70    pub block: Option<Au>,
71    pub has_quirky_block_size: HasQuirkyBlockSize,
72}
73
74impl IndefiniteContainingBlockSize {
75    #[inline]
76    pub fn as_logical_vec2(&self) -> LogicalVec2<Option<Au>> {
77        LogicalVec2 {
78            inline: self.inline,
79            block: self.block,
80        }
81    }
82}
83
84/// A variant of [`ContainingBlock`] that allows an indefinite inline size.
85/// Useful for code that is shared for both layout (where we know the inline size
86/// of the containing block) and intrinsic sizing (where we don't know it).
87pub(crate) struct IndefiniteContainingBlock<'a> {
88    pub size: IndefiniteContainingBlockSize,
89    pub style: &'a ComputedValues,
90}
91
92impl IndefiniteContainingBlock<'_> {
93    #[inline]
94    pub fn block_stretch_size(&self, block_pbm_sum: Au) -> Option<Au> {
95        block_stretch_size(
96            self.size.block,
97            self.size.has_quirky_block_size,
98            block_pbm_sum,
99        )
100    }
101
102    #[inline]
103    pub fn has_quirky_block_size(&self) -> bool {
104        self.size.has_quirky_block_size.0
105    }
106}
107
108impl From<&ContainingBlockSize> for IndefiniteContainingBlockSize {
109    fn from(size: &ContainingBlockSize) -> Self {
110        Self {
111            inline: Some(size.inline),
112            block: size.block.to_definite(),
113            has_quirky_block_size: size.has_quirky_block_size,
114        }
115    }
116}
117
118impl<'a> From<&ConstraintSpace<'a>> for IndefiniteContainingBlock<'a> {
119    fn from(constraint_space: &ConstraintSpace<'a>) -> Self {
120        Self {
121            size: IndefiniteContainingBlockSize {
122                inline: None,
123                block: constraint_space.block_size.to_definite(),
124                has_quirky_block_size: constraint_space.has_quirky_block_size,
125            },
126            style: constraint_space.style,
127        }
128    }
129}
130
131impl<'a> From<&'_ ContainingBlock<'a>> for IndefiniteContainingBlock<'a> {
132    fn from(containing_block: &ContainingBlock<'a>) -> Self {
133        Self {
134            size: (&containing_block.size).into(),
135            style: containing_block.style,
136        }
137    }
138}
139
140impl<'a> From<&'_ DefiniteContainingBlock<'a>> for IndefiniteContainingBlock<'a> {
141    fn from(containing_block: &DefiniteContainingBlock<'a>) -> Self {
142        Self {
143            size: IndefiniteContainingBlockSize {
144                inline: Some(containing_block.size.inline),
145                block: Some(containing_block.size.block),
146                has_quirky_block_size: HasQuirkyBlockSize(false),
147            },
148            style: containing_block.style,
149        }
150    }
151}
152
153#[derive(Clone, Debug, MallocSizeOf, PartialEq)]
154pub(crate) struct ContainingBlockSize {
155    pub inline: Au,
156    pub block: SizeConstraint,
157    pub has_quirky_block_size: HasQuirkyBlockSize,
158}
159
160pub(crate) struct ContainingBlock<'a> {
161    pub size: ContainingBlockSize,
162    pub style: &'a ComputedValues,
163}
164
165impl ContainingBlock<'_> {
166    #[inline]
167    pub fn inline_stretch_size(&self, inline_pbm_sum: Au) -> Option<Au> {
168        inline_stretch_size(Some(self.size.inline), inline_pbm_sum)
169    }
170
171    #[inline]
172    pub fn block_stretch_size(&self, block_pbm_sum: Au) -> Option<Au> {
173        block_stretch_size(
174            self.size.block.to_definite(),
175            self.size.has_quirky_block_size,
176            block_pbm_sum,
177        )
178    }
179
180    #[inline]
181    pub fn has_quirky_block_size(&self) -> bool {
182        self.size.has_quirky_block_size.0
183    }
184}
185
186pub(crate) struct DefiniteContainingBlock<'a> {
187    pub size: LogicalVec2<Au>,
188    pub style: &'a ServoArc<ComputedValues>,
189}
190
191impl<'a> From<&'_ DefiniteContainingBlock<'a>> for ContainingBlock<'a> {
192    fn from(definite: &DefiniteContainingBlock<'a>) -> Self {
193        ContainingBlock {
194            size: ContainingBlockSize {
195                inline: definite.size.inline,
196                block: SizeConstraint::Definite(definite.size.block),
197                has_quirky_block_size: HasQuirkyBlockSize(false),
198            },
199            style: definite.style,
200        }
201    }
202}