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