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