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 #[inline]
109 pub fn is_definitely_zero(&self) -> bool {
110 use crate::values::generics::length::LengthPercentageOrAuto::*;
111 match *self {
112 LengthPercentage(ref l) => l.is_definitely_zero(),
113 Auto => false,
114 }
115 }
116 };
117}
118
119pub type LengthPercentageOrAuto = generics::GenericLengthPercentageOrAuto<LengthPercentage>;
121
122impl LengthPercentageOrAuto {
123 pub fn clamp_to_non_negative(self) -> Self {
125 use crate::values::generics::length::LengthPercentageOrAuto::*;
126 match self {
127 LengthPercentage(l) => LengthPercentage(l.clamp_to_non_negative()),
128 Auto => Auto,
129 }
130 }
131
132 pub fn as_ref(&self) -> generics::GenericLengthPercentageOrAuto<&LengthPercentage> {
134 use crate::values::generics::length::LengthPercentageOrAuto::*;
135 match *self {
136 LengthPercentage(ref lp) => LengthPercentage(lp),
137 Auto => Auto,
138 }
139 }
140
141 computed_length_percentage_or_auto!(LengthPercentage);
142}
143
144impl generics::GenericLengthPercentageOrAuto<&LengthPercentage> {
145 #[inline]
147 pub fn percentage_relative_to(&self, basis: Length) -> LengthOrAuto {
148 use crate::values::generics::length::LengthPercentageOrAuto::*;
149 match self {
150 LengthPercentage(length_percentage) => {
151 LengthPercentage(length_percentage.percentage_relative_to(basis))
152 },
153 Auto => Auto,
154 }
155 }
156
157 #[inline]
159 pub fn maybe_percentage_relative_to(&self, basis: Option<Length>) -> LengthOrAuto {
160 use crate::values::generics::length::LengthPercentageOrAuto::*;
161 match self {
162 LengthPercentage(length_percentage) => length_percentage
163 .maybe_percentage_relative_to(basis)
164 .map_or(Auto, LengthPercentage),
165 Auto => Auto,
166 }
167 }
168}
169
170pub type NonNegativeLengthPercentageOrAuto =
172 generics::GenericLengthPercentageOrAuto<NonNegativeLengthPercentage>;
173
174impl NonNegativeLengthPercentageOrAuto {
175 computed_length_percentage_or_auto!(NonNegativeLengthPercentage);
176}
177
178#[derive(
180 Animate,
181 Clone,
182 ComputeSquaredDistance,
183 Copy,
184 Deserialize,
185 MallocSizeOf,
186 PartialEq,
187 PartialOrd,
188 Serialize,
189 ToAnimatedZero,
190 ToComputedValue,
191 ToShmem,
192 ToTyped,
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
533#[cfg(feature = "gecko")]
534use crate::{
535 gecko_bindings::structs::AnchorPosResolutionParams, logical_geometry::PhysicalAxis,
536 values::generics::length::AnchorSizeKeyword, values::DashedIdent,
537};
538
539#[cfg(feature = "gecko")]
543pub fn resolve_anchor_size(
544 anchor_name: &DashedIdent,
545 prop_axis: PhysicalAxis,
546 anchor_size_keyword: AnchorSizeKeyword,
547 params: &AnchorPosResolutionParams,
548) -> Result<Length, ()> {
549 use crate::gecko_bindings::structs::Gecko_GetAnchorPosSize;
550
551 let mut offset = Length::zero();
552 let valid = unsafe {
553 Gecko_GetAnchorPosSize(
554 params,
555 anchor_name.0.as_ptr(),
556 prop_axis as u8,
557 anchor_size_keyword as u8,
558 &mut offset,
559 )
560 };
561
562 if !valid {
563 return Err(());
564 }
565
566 Ok(offset)
567}
568
569pub type Margin = generics::GenericMargin<LengthPercentage>;