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