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, Float, Overflow, OverflowAnchor,
22    OverscrollBehavior, PositionProperty, ScrollSnapAlign, ScrollSnapAxis, ScrollSnapStop,
23    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#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
69#[derive(
70    Clone, Copy, Debug, Eq, Hash, MallocSizeOf, Parse, PartialEq, ToCss, ToResolvedValue, ToTyped,
71)]
72#[repr(u8)]
73pub enum Resize {
74    None,
75    Both,
76    Horizontal,
77    Vertical,
78}
79
80impl ToComputedValue for specified::Resize {
81    type ComputedValue = Resize;
82
83    #[inline]
84    fn to_computed_value(&self, context: &Context) -> Resize {
85        let is_vertical = context.style().writing_mode.is_vertical();
86        match self {
87            specified::Resize::Inline => {
88                context
89                    .rule_cache_conditions
90                    .borrow_mut()
91                    .set_writing_mode_dependency(context.builder.writing_mode);
92                if is_vertical {
93                    Resize::Vertical
94                } else {
95                    Resize::Horizontal
96                }
97            },
98            specified::Resize::Block => {
99                context
100                    .rule_cache_conditions
101                    .borrow_mut()
102                    .set_writing_mode_dependency(context.builder.writing_mode);
103                if is_vertical {
104                    Resize::Horizontal
105                } else {
106                    Resize::Vertical
107                }
108            },
109            specified::Resize::None => Resize::None,
110            specified::Resize::Both => Resize::Both,
111            specified::Resize::Horizontal => Resize::Horizontal,
112            specified::Resize::Vertical => Resize::Vertical,
113        }
114    }
115
116    #[inline]
117    fn from_computed_value(computed: &Resize) -> specified::Resize {
118        match computed {
119            Resize::None => specified::Resize::None,
120            Resize::Both => specified::Resize::Both,
121            Resize::Horizontal => specified::Resize::Horizontal,
122            Resize::Vertical => specified::Resize::Vertical,
123        }
124    }
125}
126
127/// The computed `zoom` property value.
128#[derive(
129    Clone,
130    ComputeSquaredDistance,
131    Copy,
132    Debug,
133    MallocSizeOf,
134    PartialEq,
135    PartialOrd,
136    ToResolvedValue,
137    ToTyped,
138)]
139#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
140#[repr(C)]
141pub struct Zoom(f32);
142
143impl ToComputedValue for specified::Zoom {
144    type ComputedValue = Zoom;
145
146    #[inline]
147    fn to_computed_value(&self, _: &Context) -> Self::ComputedValue {
148        let n = match *self {
149            Self::Normal => return Zoom::ONE,
150            Self::Document => return Zoom::DOCUMENT,
151            Self::Value(ref n) => n.0.to_number().get(),
152        };
153        if n == 0.0 {
154            // For legacy reasons, zoom: 0 (and 0%) computes to 1. ¯\_(ツ)_/¯
155            return Zoom::ONE;
156        }
157        Zoom(n)
158    }
159
160    #[inline]
161    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
162        Self::new_number(computed.value())
163    }
164}
165
166impl ToCss for Zoom {
167    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
168    where
169        W: fmt::Write,
170    {
171        use std::fmt::Write;
172        if *self == Self::DOCUMENT {
173            return dest.write_str("document");
174        }
175        self.value().to_css(dest)
176    }
177}
178
179impl ToAnimatedValue for Zoom {
180    type AnimatedValue = Number;
181
182    #[inline]
183    fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
184        self.value()
185    }
186
187    #[inline]
188    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
189        Zoom(animated.max(0.0))
190    }
191}
192
193impl Zoom {
194    /// The value 1. This is by far the most common value.
195    pub const ONE: Zoom = Zoom(1.0);
196
197    /// The `document` value. This can appear in the computed zoom property value, but not in the
198    /// `effective_zoom` field.
199    pub const DOCUMENT: Zoom = Zoom(0.0);
200
201    /// Returns whether we're the number 1.
202    #[inline]
203    pub fn is_one(self) -> bool {
204        self == Self::ONE
205    }
206
207    /// Returns whether we're the `document` keyword.
208    #[inline]
209    pub fn is_document(self) -> bool {
210        self == Self::DOCUMENT
211    }
212
213    /// Returns the inverse of our value.
214    #[inline]
215    pub fn inverted(&self) -> Option<Self> {
216        if self.0 == 0.0 {
217            return None;
218        }
219        Some(Self(1. / self.0))
220    }
221
222    /// Returns the value as a float.
223    #[inline]
224    pub fn value(&self) -> f32 {
225        self.0
226    }
227
228    /// Computes the effective zoom for a given new zoom value in rhs.
229    pub fn compute_effective(self, specified: Self) -> Self {
230        if specified == Self::DOCUMENT {
231            return Self::ONE;
232        }
233        if self == Self::ONE {
234            return specified;
235        }
236        if specified == Self::ONE {
237            return self;
238        }
239        Zoom(self.0 * specified.0)
240    }
241
242    /// Returns the zoomed value.
243    #[inline]
244    pub fn zoom(self, value: f32) -> f32 {
245        if self == Self::ONE {
246            return value;
247        }
248        value * self.value()
249    }
250
251    /// Returns the un-zoomed value.
252    #[inline]
253    pub fn unzoom(self, value: f32) -> f32 {
254        // Avoid division by zero if our effective zoom computation ends up being zero.
255        if self == Self::ONE || self.0 == 0.0 {
256            return value;
257        }
258        value / self.value()
259    }
260}