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