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