accessibility_tree/style/values/
length.rs

1use crate::style::errors::{PropertyParseError, PropertyParseErrorKind};
2use crate::style::values::{CascadeContext, FromSpecified, Parse, SpecifiedValue};
3use cssparser::{Parser, Token};
4use std::fmt;
5use std::ops;
6
7#[repr(transparent)]
8#[derive(Copy, Clone, PartialEq, PartialOrd)]
9pub struct Length {
10    pub px: f32,
11}
12
13/// <https://drafts.csswg.org/css-values/#percentages>
14#[repr(transparent)]
15#[derive(Copy, Clone, SpecifiedAsComputed)]
16pub struct Percentage {
17    pub unit_value: f32,
18}
19
20/// <https://drafts.csswg.org/css-values/#lengths>
21#[derive(Clone, FromVariants)]
22pub enum SpecifiedLength {
23    Absolute(Length),
24    Em(f32),
25}
26
27#[derive(Clone, Parse, FromVariants)]
28pub enum SpecifiedLengthOrPercentage {
29    Length(SpecifiedLength),
30    Percentage(Percentage),
31}
32
33#[derive(Debug, Copy, Clone, FromSpecified, FromVariants)]
34pub enum LengthOrPercentage {
35    Length(Length),
36    Percentage(Percentage),
37}
38
39impl LengthOrPercentage {
40    /// get the px values as a float
41    pub fn inner_px(&self) -> f32 {
42        match self {
43            LengthOrPercentage::Length(l) => l.px,
44            LengthOrPercentage::Percentage(l) => l.unit_value,
45        }
46    }
47}
48
49#[derive(Clone, Parse, FromVariants)]
50pub enum SpecifiedLengthOrPercentageOrAuto {
51    Length(SpecifiedLength),
52    Percentage(Percentage),
53    Auto,
54}
55
56#[derive(Debug, Copy, Clone, FromSpecified, FromVariants)]
57pub enum LengthOrPercentageOrAuto {
58    Length(Length),
59    Percentage(Percentage),
60    Auto,
61}
62
63#[derive(Copy, Clone, Debug, FromVariants, PartialEq)]
64pub enum LengthOrAuto {
65    Length(Length),
66    Auto,
67}
68
69impl Parse for SpecifiedLength {
70    fn parse<'i, 't>(parser: &mut Parser<'i, 't>) -> Result<Self, PropertyParseError<'i>> {
71        match parser.next()? {
72            Token::Dimension { value, unit, .. } => match_ignore_ascii_case!(unit,
73                "px" => Ok(SpecifiedLength::Absolute(Length { px: *value })),
74                "em" => Ok(SpecifiedLength::Em(*value)),
75                _ => {
76                    let u = unit.clone();
77                    Err(parser.new_custom_error(PropertyParseErrorKind::UnknownUnit(u)))
78                }
79            ),
80            Token::Number { value, .. } if *value == 0. => {
81                Ok(SpecifiedLength::Absolute(Length { px: 0. }))
82            }
83            token => {
84                let t = token.clone();
85                Err(parser.new_unexpected_token_error(t))
86            }
87        }
88    }
89}
90
91impl SpecifiedValue for Length {
92    type SpecifiedValue = SpecifiedLength;
93}
94
95impl FromSpecified for Length {
96    fn from_specified(s: &SpecifiedLength, context: &CascadeContext) -> Self {
97        match s {
98            SpecifiedLength::Absolute(px) => *px,
99            SpecifiedLength::Em(value) => context.this.font_size().0 * *value,
100        }
101    }
102}
103
104impl Parse for Percentage {
105    fn parse<'i, 't>(parser: &mut Parser<'i, 't>) -> Result<Self, PropertyParseError<'i>> {
106        Ok(Percentage {
107            unit_value: parser.expect_percentage()?,
108        })
109    }
110}
111
112impl Length {
113    pub fn zero() -> Self {
114        Length { px: 0. }
115    }
116
117    pub fn max(self, other: Self) -> Self {
118        Length {
119            px: self.px.max(other.px),
120        }
121    }
122
123    pub fn min(self, other: Self) -> Self {
124        Length {
125            px: self.px.min(other.px),
126        }
127    }
128
129    pub fn max_assign(&mut self, other: Self) {
130        *self = self.max(other)
131    }
132}
133
134impl ops::Neg for Length {
135    type Output = Self;
136    fn neg(self) -> Self {
137        Length { px: -self.px }
138    }
139}
140
141impl ops::Add for Length {
142    type Output = Self;
143    fn add(self, other: Self) -> Self {
144        Length {
145            px: self.px + other.px,
146        }
147    }
148}
149
150impl ops::Sub for Length {
151    type Output = Self;
152    fn sub(self, other: Self) -> Self {
153        Length {
154            px: self.px - other.px,
155        }
156    }
157}
158
159impl ops::AddAssign for Length {
160    fn add_assign(&mut self, other: Self) {
161        self.px += other.px
162    }
163}
164
165impl ops::SubAssign for Length {
166    fn sub_assign(&mut self, other: Self) {
167        self.px -= other.px
168    }
169}
170
171impl ops::Mul<f32> for Length {
172    type Output = Self;
173
174    fn mul(self, other: f32) -> Self {
175        Length {
176            px: self.px * other,
177        }
178    }
179}
180
181impl ops::Mul<Percentage> for Length {
182    type Output = Self;
183
184    fn mul(self, other: Percentage) -> Self {
185        self * other.unit_value
186    }
187}
188
189impl ops::Div<f32> for Length {
190    type Output = Self;
191
192    fn div(self, other: f32) -> Self {
193        Length {
194            px: self.px / other,
195        }
196    }
197}
198
199impl From<Length> for euclid::Length<f32, crate::primitives::CssPx> {
200    fn from(l: Length) -> Self {
201        euclid::Length::new(l.px)
202    }
203}
204
205impl fmt::Debug for Length {
206    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207        self.px.fmt(f)?;
208        fmt::Write::write_str(f, "px")
209    }
210}
211
212impl fmt::Debug for Percentage {
213    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
214        (self.unit_value * 100.).fmt(f)?;
215        fmt::Write::write_str(f, "%")
216    }
217}
218
219impl LengthOrPercentage {
220    pub fn percentage_relative_to(&self, reference: Length) -> Length {
221        match *self {
222            LengthOrPercentage::Length(l) => l,
223            LengthOrPercentage::Percentage(p) => reference * p,
224        }
225    }
226}
227
228impl From<LengthOrPercentage> for LengthOrPercentageOrAuto {
229    fn from(value: LengthOrPercentage) -> Self {
230        match value {
231            LengthOrPercentage::Length(l) => LengthOrPercentageOrAuto::Length(l),
232            LengthOrPercentage::Percentage(p) => LengthOrPercentageOrAuto::Percentage(p),
233        }
234    }
235}
236
237impl LengthOrPercentageOrAuto {
238    pub fn inner_px(&self) -> f32 {
239        match self {
240            LengthOrPercentageOrAuto::Length(l) => l.px,
241            LengthOrPercentageOrAuto::Percentage(l) => l.unit_value,
242            LengthOrPercentageOrAuto::Auto => 0.0,
243        }
244    }
245
246    pub fn non_auto(&self) -> Option<LengthOrPercentage> {
247        match *self {
248            LengthOrPercentageOrAuto::Length(l) => Some(LengthOrPercentage::Length(l)),
249            LengthOrPercentageOrAuto::Percentage(p) => Some(LengthOrPercentage::Percentage(p)),
250            LengthOrPercentageOrAuto::Auto => None,
251        }
252    }
253
254    pub fn percentage_relative_to(&self, reference: Length) -> LengthOrAuto {
255        match *self {
256            LengthOrPercentageOrAuto::Length(l) => LengthOrAuto::Length(l),
257            LengthOrPercentageOrAuto::Percentage(p) => LengthOrAuto::Length(reference * p),
258            LengthOrPercentageOrAuto::Auto => LengthOrAuto::Auto,
259        }
260    }
261}
262
263impl LengthOrAuto {
264    pub fn auto_is(&self, auto_value: impl FnOnce() -> Length) -> Length {
265        match *self {
266            LengthOrAuto::Length(l) => l,
267            LengthOrAuto::Auto => auto_value(),
268        }
269    }
270
271    pub fn map(&self, f: impl FnOnce(Length) -> Length) -> Self {
272        match *self {
273            LengthOrAuto::Length(l) => LengthOrAuto::Length(f(l)),
274            LengthOrAuto::Auto => LengthOrAuto::Auto,
275        }
276    }
277}