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, DominantBaseline, Float, Overflow,
22    OverflowAnchor, OverscrollBehavior, PositionProperty, ScrollSnapAlign, ScrollSnapAxis,
23    ScrollSnapStop, 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: &Context) -> Self::ComputedValue {
148        let c = match *self {
149            Self::Normal => return Zoom::ONE,
150            Self::Document => return Zoom::DOCUMENT,
151            Self::Value(ref n) => n.0.to_computed_value(context),
152        };
153        let n = match c {
154            super::NumberOrPercentage::Percentage(p) => p.0,
155            super::NumberOrPercentage::Number(n) => n,
156        };
157        if n == 0.0 {
158            // For legacy reasons, zoom: 0 (and 0%) computes to 1. ¯\_(ツ)_/¯
159            return Zoom::ONE;
160        }
161        Zoom(n)
162    }
163
164    #[inline]
165    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
166        Self::new_number(computed.value())
167    }
168}
169
170impl ToCss for Zoom {
171    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
172    where
173        W: fmt::Write,
174    {
175        use std::fmt::Write;
176        if *self == Self::DOCUMENT {
177            return dest.write_str("document");
178        }
179        self.value().to_css(dest)
180    }
181}
182
183impl ToAnimatedValue for Zoom {
184    type AnimatedValue = Number;
185
186    #[inline]
187    fn to_animated_value(self, _: &crate::values::animated::Context) -> Self::AnimatedValue {
188        self.value()
189    }
190
191    #[inline]
192    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
193        Zoom(animated.max(0.0))
194    }
195}
196
197impl Zoom {
198    /// The value 1. This is by far the most common value.
199    pub const ONE: Zoom = Zoom(1.0);
200
201    /// The `document` value. This can appear in the computed zoom property value, but not in the
202    /// `effective_zoom` field.
203    pub const DOCUMENT: Zoom = Zoom(0.0);
204
205    /// Returns whether we're the number 1.
206    #[inline]
207    pub fn is_one(self) -> bool {
208        self == Self::ONE
209    }
210
211    /// Returns whether we're the `document` keyword.
212    #[inline]
213    pub fn is_document(self) -> bool {
214        self == Self::DOCUMENT
215    }
216
217    /// Returns the inverse of our value.
218    #[inline]
219    pub fn inverted(&self) -> Option<Self> {
220        if self.0 == 0.0 {
221            return None;
222        }
223        Some(Self(1. / self.0))
224    }
225
226    /// Returns the value as a float.
227    #[inline]
228    pub fn value(&self) -> f32 {
229        self.0
230    }
231
232    /// Computes the effective zoom for a given new zoom value in rhs.
233    pub fn compute_effective(self, specified: Self) -> Self {
234        if specified == Self::DOCUMENT {
235            return Self::ONE;
236        }
237        if self == Self::ONE {
238            return specified;
239        }
240        if specified == Self::ONE {
241            return self;
242        }
243        Zoom(self.0 * specified.0)
244    }
245
246    /// Returns the zoomed value.
247    #[inline]
248    pub fn zoom(self, value: f32) -> f32 {
249        if self == Self::ONE {
250            return value;
251        }
252        value * self.value()
253    }
254
255    /// Returns the un-zoomed value.
256    #[inline]
257    pub fn unzoom(self, value: f32) -> f32 {
258        // Avoid division by zero if our effective zoom computation ends up being zero.
259        if self == Self::ONE || self.0 == 0.0 {
260            return value;
261        }
262        value / self.value()
263    }
264}