accessibility_tree/style/values/
length.rs1use 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#[repr(transparent)]
15#[derive(Copy, Clone, SpecifiedAsComputed)]
16pub struct Percentage {
17 pub unit_value: f32,
18}
19
20#[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 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}