Skip to main content

style/values/computed/
box.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
5//! Computed types for box properties.
6
7use crate::derives::*;
8use crate::values::animated::{Animate, Procedure, ToAnimatedValue};
9use crate::values::computed::length::{LengthPercentage, NonNegativeLength};
10use crate::values::computed::{Context, Integer, Number, ToComputedValue};
11use crate::values::generics::box_::{
12    GenericBaselineShift, GenericContainIntrinsicSize, GenericLineClamp, GenericOverflowClipMargin,
13    GenericPerspective,
14};
15use crate::values::specified::box_ as specified;
16use std::fmt;
17use style_traits::{CssWriter, ToCss};
18
19pub use crate::values::specified::box_::{
20    AlignmentBaseline, Appearance, BaselineSource, BreakBetween, BreakWithin, Clear, Contain,
21    ContainerName, ContainerType, ContentVisibility, Display, DominantBaseline, Float, Overflow,
22    OverflowAnchor, OverscrollBehavior, PositionProperty, ScrollSnapAlign, ScrollSnapAxis,
23    ScrollSnapStop, ScrollSnapStrictness, ScrollSnapType, ScrollbarGutter, TouchAction, WillChange,
24    WritingModeProperty,
25};
26
27/// A computed value for the `baseline-shift` property.
28pub type BaselineShift = GenericBaselineShift<LengthPercentage>;
29
30/// A computed value for the `overflow-clip-margin` property.
31pub type OverflowClipMargin = GenericOverflowClipMargin<NonNegativeLength>;
32
33/// A computed value for the `contain-intrinsic-size` property.
34pub type ContainIntrinsicSize = GenericContainIntrinsicSize<NonNegativeLength>;
35
36impl ContainIntrinsicSize {
37    /// Converts contain-intrinsic-size to auto style.
38    pub fn add_auto_if_needed(&self) -> Option<Self> {
39        Some(match *self {
40            Self::None => Self::AutoNone,
41            Self::Length(ref l) => Self::AutoLength(*l),
42            Self::AutoNone | Self::AutoLength(..) => return None,
43        })
44    }
45}
46
47/// A computed value for the `line-clamp` property.
48pub type LineClamp = GenericLineClamp<Integer>;
49
50impl Animate for LineClamp {
51    #[inline]
52    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
53        if self.is_none() != other.is_none() {
54            return Err(());
55        }
56        if self.is_none() {
57            return Ok(Self::none());
58        }
59        Ok(Self(self.0.animate(&other.0, procedure)?.max(1)))
60    }
61}
62
63/// A computed value for the `perspective` property.
64pub type Perspective = GenericPerspective<NonNegativeLength>;
65
66/// A computed value for the `resize` property.
67#[allow(missing_docs)]
68#[derive(
69    Clone,
70    Copy,
71    Debug,
72    Deserialize,
73    Eq,
74    Hash,
75    MallocSizeOf,
76    Parse,
77    PartialEq,
78    Serialize,
79    ToCss,
80    ToResolvedValue,
81    ToTyped,
82)]
83#[repr(u8)]
84pub enum Resize {
85    None,
86    Both,
87    Horizontal,
88    Vertical,
89}
90
91impl ToComputedValue for specified::Resize {
92    type ComputedValue = Resize;
93
94    #[inline]
95    fn to_computed_value(&self, context: &Context) -> Resize {
96        let is_vertical = context.style().writing_mode.is_vertical();
97        match self {
98            specified::Resize::Inline => {
99                context
100                    .rule_cache_conditions
101                    .borrow_mut()
102                    .set_writing_mode_dependency(context.builder.writing_mode);
103                if is_vertical {
104                    Resize::Vertical
105                } else {
106                    Resize::Horizontal
107                }
108            },
109            specified::Resize::Block => {
110                context
111                    .rule_cache_conditions
112                    .borrow_mut()
113                    .set_writing_mode_dependency(context.builder.writing_mode);
114                if is_vertical {
115                    Resize::Horizontal
116                } else {
117                    Resize::Vertical
118                }
119            },
120            specified::Resize::None => Resize::None,
121            specified::Resize::Both => Resize::Both,
122            specified::Resize::Horizontal => Resize::Horizontal,
123            specified::Resize::Vertical => Resize::Vertical,
124        }
125    }
126
127    #[inline]
128    fn from_computed_value(computed: &Resize) -> specified::Resize {
129        match computed {
130            Resize::None => specified::Resize::None,
131            Resize::Both => specified::Resize::Both,
132            Resize::Horizontal => specified::Resize::Horizontal,
133            Resize::Vertical => specified::Resize::Vertical,
134        }
135    }
136}
137
138/// The computed `zoom` property value.
139#[derive(
140    Clone,
141    ComputeSquaredDistance,
142    Copy,
143    Debug,
144    Deserialize,
145    MallocSizeOf,
146    PartialEq,
147    PartialOrd,
148    Serialize,
149    ToResolvedValue,
150    ToTyped,
151)]
152#[repr(C)]
153pub struct Zoom(f32);
154
155impl ToComputedValue for specified::Zoom {
156    type ComputedValue = Zoom;
157
158    #[inline]
159    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
160        let c = match *self {
161            Self::Normal => return Zoom::ONE,
162            Self::Document => return Zoom::DOCUMENT,
163            Self::Value(ref n) => n.0.to_computed_value(context),
164        };
165        let n = match c {
166            super::NumberOrPercentage::Percentage(p) => p.0,
167            super::NumberOrPercentage::Number(n) => n,
168        };
169        if n == 0.0 {
170            // For legacy reasons, zoom: 0 (and 0%) computes to 1. ¯\_(ツ)_/¯
171            return Zoom::ONE;
172        }
173        Zoom(n)
174    }
175
176    #[inline]
177    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
178        Self::new_number(computed.value())
179    }
180}
181
182impl ToCss for Zoom {
183    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
184    where
185        W: fmt::Write,
186    {
187        use std::fmt::Write;
188        if *self == Self::DOCUMENT {
189            return dest.write_str("document");
190        }
191        self.value().to_css(dest)
192    }
193}
194
195impl ToAnimatedValue for Zoom {
196    type AnimatedValue = Number;
197
198    #[inline]
199    fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
200        self.value()
201    }
202
203    #[inline]
204    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
205        Zoom(animated.max(0.0))
206    }
207}
208
209impl Zoom {
210    /// The value 1. This is by far the most common value.
211    pub const ONE: Zoom = Zoom(1.0);
212
213    /// The `document` value. This can appear in the computed zoom property value, but not in the
214    /// `effective_zoom` field.
215    pub const DOCUMENT: Zoom = Zoom(0.0);
216
217    /// Returns whether we're the number 1.
218    #[inline]
219    pub fn is_one(self) -> bool {
220        self == Self::ONE
221    }
222
223    /// Returns whether we're the `document` keyword.
224    #[inline]
225    pub fn is_document(self) -> bool {
226        self == Self::DOCUMENT
227    }
228
229    /// Returns the inverse of our value.
230    #[inline]
231    pub fn inverted(&self) -> Option<Self> {
232        if self.0 == 0.0 {
233            return None;
234        }
235        Some(Self(1. / self.0))
236    }
237
238    /// Returns the value as a float.
239    #[inline]
240    pub fn value(&self) -> f32 {
241        self.0
242    }
243
244    /// Computes the effective zoom for a given new zoom value in rhs.
245    pub fn compute_effective(self, specified: Self) -> Self {
246        if specified == Self::DOCUMENT {
247            return Self::ONE;
248        }
249        if self == Self::ONE {
250            return specified;
251        }
252        if specified == Self::ONE {
253            return self;
254        }
255        Zoom(self.0 * specified.0)
256    }
257
258    /// Returns the zoomed value.
259    #[inline]
260    pub fn zoom(self, value: f32) -> f32 {
261        if self == Self::ONE {
262            return value;
263        }
264        value * self.value()
265    }
266
267    /// Returns the un-zoomed value.
268    #[inline]
269    pub fn unzoom(self, value: f32) -> f32 {
270        // Avoid division by zero if our effective zoom computation ends up being zero.
271        if self == Self::ONE || self.0 == 0.0 {
272            return value;
273        }
274        value / self.value()
275    }
276}