1use super::{Context, Number, ToComputedValue};
8use crate::values::animated::{Context as AnimatedContext, ToAnimatedValue};
9use crate::values::computed::{NonNegativeNumber, Zoom};
10use crate::values::generics::length as generics;
11use crate::values::generics::length::{
12 GenericLengthOrNumber, GenericLengthPercentageOrNormal, GenericMaxSize, GenericSize,
13};
14use crate::values::generics::NonNegative;
15use crate::values::resolved::{Context as ResolvedContext, ToResolvedValue};
16use crate::values::specified::length::{AbsoluteLength, FontBaseSize, LineHeightBase};
17use crate::values::{specified, CSSFloat};
18use crate::Zero;
19use app_units::Au;
20use std::fmt::{self, Write};
21use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign};
22use style_traits::{CSSPixel, CssWriter, ToCss};
23
24pub use super::image::Image;
25pub use super::length_percentage::{LengthPercentage, NonNegativeLengthPercentage};
26pub use crate::values::specified::url::UrlOrNone;
27pub use crate::values::specified::{Angle, BorderStyle, Time};
28
29impl ToComputedValue for specified::NoCalcLength {
30 type ComputedValue = Length;
31
32 #[inline]
33 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
34 self.to_computed_value_with_base_size(
35 context,
36 FontBaseSize::CurrentStyle,
37 LineHeightBase::CurrentStyle,
38 )
39 }
40
41 #[inline]
42 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
43 Self::Absolute(AbsoluteLength::Px(computed.px()))
44 }
45}
46
47impl specified::NoCalcLength {
48 pub fn to_computed_value_with_base_size(
50 &self,
51 context: &Context,
52 base_size: FontBaseSize,
53 line_height_base: LineHeightBase,
54 ) -> Length {
55 match *self {
56 Self::Absolute(length) => length.to_computed_value(context),
57 Self::FontRelative(length) => {
58 length.to_computed_value(context, base_size, line_height_base)
59 },
60 Self::ViewportPercentage(length) => length.to_computed_value(context),
61 Self::ContainerRelative(length) => length.to_computed_value(context),
62 Self::ServoCharacterWidth(length) => length
63 .to_computed_value(context.style().get_font().clone_font_size().computed_size()),
64 }
65 }
66}
67
68impl ToComputedValue for specified::Length {
69 type ComputedValue = Length;
70
71 #[inline]
72 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
73 match *self {
74 Self::NoCalc(l) => l.to_computed_value(context),
75 Self::Calc(ref calc) => {
76 let result = calc.to_computed_value(context);
77 debug_assert!(
78 result.to_length().is_some(),
79 "{:?} didn't resolve to a length: {:?}",
80 calc,
81 result,
82 );
83 result.to_length().unwrap_or_else(Length::zero)
84 },
85 }
86 }
87
88 #[inline]
89 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
90 Self::NoCalc(specified::NoCalcLength::from_computed_value(computed))
91 }
92}
93
94macro_rules! computed_length_percentage_or_auto {
97 ($inner:ty) => {
98 #[inline]
100 pub fn to_used_value(&self, percentage_basis: Au) -> Option<Au> {
101 match *self {
102 Self::Auto => None,
103 Self::LengthPercentage(ref lp) => Some(lp.to_used_value(percentage_basis)),
104 }
105 }
106 };
107}
108
109pub type LengthPercentageOrAuto = generics::GenericLengthPercentageOrAuto<LengthPercentage>;
111
112impl LengthPercentageOrAuto {
113 pub fn clamp_to_non_negative(self) -> Self {
115 use crate::values::generics::length::LengthPercentageOrAuto::*;
116 match self {
117 LengthPercentage(l) => LengthPercentage(l.clamp_to_non_negative()),
118 Auto => Auto,
119 }
120 }
121
122 pub fn as_ref(&self) -> generics::GenericLengthPercentageOrAuto<&LengthPercentage> {
124 use crate::values::generics::length::LengthPercentageOrAuto::*;
125 match *self {
126 LengthPercentage(ref lp) => LengthPercentage(lp),
127 Auto => Auto,
128 }
129 }
130
131 computed_length_percentage_or_auto!(LengthPercentage);
132}
133
134impl generics::GenericLengthPercentageOrAuto<&LengthPercentage> {
135 #[inline]
137 pub fn percentage_relative_to(&self, basis: Length) -> LengthOrAuto {
138 use crate::values::generics::length::LengthPercentageOrAuto::*;
139 match self {
140 LengthPercentage(length_percentage) => {
141 LengthPercentage(length_percentage.percentage_relative_to(basis))
142 },
143 Auto => Auto,
144 }
145 }
146
147 #[inline]
149 pub fn maybe_percentage_relative_to(&self, basis: Option<Length>) -> LengthOrAuto {
150 use crate::values::generics::length::LengthPercentageOrAuto::*;
151 match self {
152 LengthPercentage(length_percentage) => length_percentage
153 .maybe_percentage_relative_to(basis)
154 .map_or(Auto, LengthPercentage),
155 Auto => Auto,
156 }
157 }
158}
159
160pub type NonNegativeLengthPercentageOrAuto =
162 generics::GenericLengthPercentageOrAuto<NonNegativeLengthPercentage>;
163
164impl NonNegativeLengthPercentageOrAuto {
165 computed_length_percentage_or_auto!(NonNegativeLengthPercentage);
166}
167
168#[derive(
170 Animate,
171 Clone,
172 ComputeSquaredDistance,
173 Copy,
174 Deserialize,
175 MallocSizeOf,
176 PartialEq,
177 PartialOrd,
178 Serialize,
179 ToAnimatedZero,
180 ToComputedValue,
181 ToShmem,
182 ToTyped,
183)]
184#[repr(C)]
185pub struct CSSPixelLength(CSSFloat);
186
187impl ToResolvedValue for CSSPixelLength {
188 type ResolvedValue = Self;
189
190 fn to_resolved_value(self, context: &ResolvedContext) -> Self::ResolvedValue {
191 Self(context.style.effective_zoom.unzoom(self.0))
192 }
193
194 #[inline]
195 fn from_resolved_value(value: Self::ResolvedValue) -> Self {
196 value
197 }
198}
199
200impl ToAnimatedValue for CSSPixelLength {
201 type AnimatedValue = Self;
202
203 fn to_animated_value(self, context: &AnimatedContext) -> Self::AnimatedValue {
204 Self(context.style.effective_zoom.unzoom(self.0))
205 }
206
207 #[inline]
208 fn from_animated_value(value: Self::AnimatedValue) -> Self {
209 value
210 }
211}
212
213impl fmt::Debug for CSSPixelLength {
214 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215 self.0.fmt(f)?;
216 f.write_str(" px")
217 }
218}
219
220impl CSSPixelLength {
221 #[inline]
223 pub fn new(px: CSSFloat) -> Self {
224 CSSPixelLength(px)
225 }
226
227 #[inline]
229 pub fn normalized(self) -> Self {
230 Self::new(crate::values::normalize(self.0))
231 }
232
233 #[inline]
235 pub fn finite(self) -> Self {
236 Self::new(crate::values::normalize(self.0).min(f32::MAX).max(f32::MIN))
237 }
238
239 #[inline]
241 pub fn scale_by(self, scale: CSSFloat) -> Self {
242 CSSPixelLength(self.0 * scale)
243 }
244
245 #[inline]
247 pub fn px(self) -> CSSFloat {
248 self.0
249 }
250
251 #[inline]
253 pub fn zoom(self, zoom: Zoom) -> Self {
254 Self::new(zoom.zoom(self.px()))
255 }
256
257 #[inline]
259 pub fn to_i32_au(self) -> i32 {
260 Au::from(self).0
261 }
262
263 #[inline]
265 pub fn abs(self) -> Self {
266 CSSPixelLength::new(self.0.abs())
267 }
268
269 #[inline]
271 pub fn clamp_to_non_negative(self) -> Self {
272 CSSPixelLength::new(self.0.max(0.))
273 }
274
275 #[inline]
277 pub fn min(self, other: Self) -> Self {
278 CSSPixelLength::new(self.0.min(other.0))
279 }
280
281 #[inline]
283 pub fn max(self, other: Self) -> Self {
284 CSSPixelLength::new(self.0.max(other.0))
285 }
286
287 #[inline]
289 pub fn max_assign(&mut self, other: Self) {
290 *self = self.max(other);
291 }
292
293 #[inline]
297 pub fn clamp_between_extremums(self, min_size: Self, max_size: Option<Self>) -> Self {
298 self.clamp_below_max(max_size).max(min_size)
299 }
300
301 #[inline]
305 pub fn clamp_below_max(self, max_size: Option<Self>) -> Self {
306 match max_size {
307 None => self,
308 Some(max_size) => self.min(max_size),
309 }
310 }
311}
312
313impl num_traits::Zero for CSSPixelLength {
314 fn zero() -> Self {
315 CSSPixelLength::new(0.)
316 }
317
318 fn is_zero(&self) -> bool {
319 self.px() == 0.
320 }
321}
322
323impl ToCss for CSSPixelLength {
324 #[inline]
325 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
326 where
327 W: Write,
328 {
329 self.0.to_css(dest)?;
330 dest.write_str("px")
331 }
332}
333
334impl std::iter::Sum for CSSPixelLength {
335 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
336 iter.fold(Length::zero(), Add::add)
337 }
338}
339
340impl Add for CSSPixelLength {
341 type Output = Self;
342
343 #[inline]
344 fn add(self, other: Self) -> Self {
345 Self::new(self.px() + other.px())
346 }
347}
348
349impl AddAssign for CSSPixelLength {
350 #[inline]
351 fn add_assign(&mut self, other: Self) {
352 self.0 += other.0;
353 }
354}
355
356impl Div for CSSPixelLength {
357 type Output = CSSFloat;
358
359 #[inline]
360 fn div(self, other: Self) -> CSSFloat {
361 self.px() / other.px()
362 }
363}
364
365impl Div<CSSFloat> for CSSPixelLength {
366 type Output = Self;
367
368 #[inline]
369 fn div(self, other: CSSFloat) -> Self {
370 Self::new(self.px() / other)
371 }
372}
373
374impl MulAssign<CSSFloat> for CSSPixelLength {
375 #[inline]
376 fn mul_assign(&mut self, other: CSSFloat) {
377 self.0 *= other;
378 }
379}
380
381impl Mul<CSSFloat> for CSSPixelLength {
382 type Output = Self;
383
384 #[inline]
385 fn mul(self, other: CSSFloat) -> Self {
386 Self::new(self.px() * other)
387 }
388}
389
390impl Neg for CSSPixelLength {
391 type Output = Self;
392
393 #[inline]
394 fn neg(self) -> Self {
395 CSSPixelLength::new(-self.0)
396 }
397}
398
399impl Sub for CSSPixelLength {
400 type Output = Self;
401
402 #[inline]
403 fn sub(self, other: Self) -> Self {
404 Self::new(self.px() - other.px())
405 }
406}
407
408impl SubAssign for CSSPixelLength {
409 #[inline]
410 fn sub_assign(&mut self, other: Self) {
411 self.0 -= other.0;
412 }
413}
414
415impl From<CSSPixelLength> for Au {
416 #[inline]
417 fn from(len: CSSPixelLength) -> Self {
418 Au::from_f32_px(len.0)
419 }
420}
421
422impl From<Au> for CSSPixelLength {
423 #[inline]
424 fn from(len: Au) -> Self {
425 CSSPixelLength::new(len.to_f32_px())
426 }
427}
428
429impl From<CSSPixelLength> for euclid::Length<CSSFloat, CSSPixel> {
430 #[inline]
431 fn from(length: CSSPixelLength) -> Self {
432 Self::new(length.0)
433 }
434}
435
436pub type Length = CSSPixelLength;
438
439pub type LengthOrAuto = generics::GenericLengthPercentageOrAuto<Length>;
441
442pub type NonNegativeLengthOrAuto = generics::GenericLengthPercentageOrAuto<NonNegativeLength>;
444
445pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
447
448pub type NonNegativeLength = NonNegative<Length>;
450
451impl ToAnimatedValue for NonNegativeLength {
452 type AnimatedValue = Length;
453
454 #[inline]
455 fn to_animated_value(self, context: &AnimatedContext) -> Self::AnimatedValue {
456 self.0.to_animated_value(context)
457 }
458
459 #[inline]
460 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
461 NonNegativeLength::new(animated.px().max(0.))
462 }
463}
464
465impl NonNegativeLength {
466 #[inline]
468 pub fn new(px: CSSFloat) -> Self {
469 NonNegative(Length::new(px.max(0.)))
470 }
471
472 #[inline]
474 pub fn px(&self) -> CSSFloat {
475 self.0.px()
476 }
477
478 #[inline]
479 pub fn clamp(self) -> Self {
481 if (self.0).0 < 0. {
482 Self::zero()
483 } else {
484 self
485 }
486 }
487}
488
489impl From<Length> for NonNegativeLength {
490 #[inline]
491 fn from(len: Length) -> Self {
492 NonNegative(len)
493 }
494}
495
496impl From<Au> for NonNegativeLength {
497 #[inline]
498 fn from(au: Au) -> Self {
499 NonNegative(au.into())
500 }
501}
502
503impl From<NonNegativeLength> for Au {
504 #[inline]
505 fn from(non_negative_len: NonNegativeLength) -> Self {
506 Au::from(non_negative_len.0)
507 }
508}
509
510pub type NonNegativeLengthPercentageOrNormal =
512 GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
513
514pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
516
517pub type Size = GenericSize<NonNegativeLengthPercentage>;
519
520pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
522
523#[cfg(feature = "gecko")]
524use crate::{
525 gecko_bindings::structs::AnchorPosResolutionParams, logical_geometry::PhysicalAxis,
526 values::generics::length::AnchorSizeKeyword, values::DashedIdent,
527};
528
529#[cfg(feature = "gecko")]
533pub fn resolve_anchor_size(
534 anchor_name: &DashedIdent,
535 prop_axis: PhysicalAxis,
536 anchor_size_keyword: AnchorSizeKeyword,
537 params: &AnchorPosResolutionParams,
538) -> Result<Length, ()> {
539 use crate::gecko_bindings::structs::Gecko_GetAnchorPosSize;
540
541 let mut offset = Length::zero();
542 let valid = unsafe {
543 Gecko_GetAnchorPosSize(
544 params,
545 anchor_name.0.as_ptr(),
546 prop_axis as u8,
547 anchor_size_keyword as u8,
548 &mut offset,
549 )
550 };
551
552 if !valid {
553 return Err(());
554 }
555
556 Ok(offset)
557}
558
559pub type Margin = generics::GenericMargin<LengthPercentage>;