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)]
193#[repr(C)]
194pub struct CSSPixelLength(CSSFloat);
195
196impl ToResolvedValue for CSSPixelLength {
197 type ResolvedValue = Self;
198
199 fn to_resolved_value(self, context: &ResolvedContext) -> Self::ResolvedValue {
200 Self(context.style.effective_zoom.unzoom(self.0))
201 }
202
203 #[inline]
204 fn from_resolved_value(value: Self::ResolvedValue) -> Self {
205 value
206 }
207}
208
209impl ToAnimatedValue for CSSPixelLength {
210 type AnimatedValue = Self;
211
212 fn to_animated_value(self, context: &AnimatedContext) -> Self::AnimatedValue {
213 Self(context.style.effective_zoom.unzoom(self.0))
214 }
215
216 #[inline]
217 fn from_animated_value(value: Self::AnimatedValue) -> Self {
218 value
219 }
220}
221
222impl fmt::Debug for CSSPixelLength {
223 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
224 self.0.fmt(f)?;
225 f.write_str(" px")
226 }
227}
228
229impl CSSPixelLength {
230 #[inline]
232 pub fn new(px: CSSFloat) -> Self {
233 CSSPixelLength(px)
234 }
235
236 #[inline]
238 pub fn normalized(self) -> Self {
239 Self::new(crate::values::normalize(self.0))
240 }
241
242 #[inline]
244 pub fn finite(self) -> Self {
245 Self::new(crate::values::normalize(self.0).min(f32::MAX).max(f32::MIN))
246 }
247
248 #[inline]
250 pub fn scale_by(self, scale: CSSFloat) -> Self {
251 CSSPixelLength(self.0 * scale)
252 }
253
254 #[inline]
256 pub fn px(self) -> CSSFloat {
257 self.0
258 }
259
260 #[inline]
262 pub fn zoom(self, zoom: Zoom) -> Self {
263 Self::new(zoom.zoom(self.px()))
264 }
265
266 #[inline]
268 pub fn to_i32_au(self) -> i32 {
269 Au::from(self).0
270 }
271
272 #[inline]
274 pub fn abs(self) -> Self {
275 CSSPixelLength::new(self.0.abs())
276 }
277
278 #[inline]
280 pub fn clamp_to_non_negative(self) -> Self {
281 CSSPixelLength::new(self.0.max(0.))
282 }
283
284 #[inline]
286 pub fn min(self, other: Self) -> Self {
287 CSSPixelLength::new(self.0.min(other.0))
288 }
289
290 #[inline]
292 pub fn max(self, other: Self) -> Self {
293 CSSPixelLength::new(self.0.max(other.0))
294 }
295
296 #[inline]
298 pub fn max_assign(&mut self, other: Self) {
299 *self = self.max(other);
300 }
301
302 #[inline]
306 pub fn clamp_between_extremums(self, min_size: Self, max_size: Option<Self>) -> Self {
307 self.clamp_below_max(max_size).max(min_size)
308 }
309
310 #[inline]
314 pub fn clamp_below_max(self, max_size: Option<Self>) -> Self {
315 match max_size {
316 None => self,
317 Some(max_size) => self.min(max_size),
318 }
319 }
320}
321
322impl num_traits::Zero for CSSPixelLength {
323 fn zero() -> Self {
324 CSSPixelLength::new(0.)
325 }
326
327 fn is_zero(&self) -> bool {
328 self.px() == 0.
329 }
330}
331
332impl ToCss for CSSPixelLength {
333 #[inline]
334 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
335 where
336 W: Write,
337 {
338 self.0.to_css(dest)?;
339 dest.write_str("px")
340 }
341}
342
343impl std::iter::Sum for CSSPixelLength {
344 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
345 iter.fold(Length::zero(), Add::add)
346 }
347}
348
349impl Add for CSSPixelLength {
350 type Output = Self;
351
352 #[inline]
353 fn add(self, other: Self) -> Self {
354 Self::new(self.px() + other.px())
355 }
356}
357
358impl AddAssign for CSSPixelLength {
359 #[inline]
360 fn add_assign(&mut self, other: Self) {
361 self.0 += other.0;
362 }
363}
364
365impl Div for CSSPixelLength {
366 type Output = CSSFloat;
367
368 #[inline]
369 fn div(self, other: Self) -> CSSFloat {
370 self.px() / other.px()
371 }
372}
373
374impl Div<CSSFloat> for CSSPixelLength {
375 type Output = Self;
376
377 #[inline]
378 fn div(self, other: CSSFloat) -> Self {
379 Self::new(self.px() / other)
380 }
381}
382
383impl MulAssign<CSSFloat> for CSSPixelLength {
384 #[inline]
385 fn mul_assign(&mut self, other: CSSFloat) {
386 self.0 *= other;
387 }
388}
389
390impl Mul<CSSFloat> for CSSPixelLength {
391 type Output = Self;
392
393 #[inline]
394 fn mul(self, other: CSSFloat) -> Self {
395 Self::new(self.px() * other)
396 }
397}
398
399impl Neg for CSSPixelLength {
400 type Output = Self;
401
402 #[inline]
403 fn neg(self) -> Self {
404 CSSPixelLength::new(-self.0)
405 }
406}
407
408impl Sub for CSSPixelLength {
409 type Output = Self;
410
411 #[inline]
412 fn sub(self, other: Self) -> Self {
413 Self::new(self.px() - other.px())
414 }
415}
416
417impl SubAssign for CSSPixelLength {
418 #[inline]
419 fn sub_assign(&mut self, other: Self) {
420 self.0 -= other.0;
421 }
422}
423
424impl From<CSSPixelLength> for Au {
425 #[inline]
426 fn from(len: CSSPixelLength) -> Self {
427 Au::from_f32_px(len.0)
428 }
429}
430
431impl From<Au> for CSSPixelLength {
432 #[inline]
433 fn from(len: Au) -> Self {
434 CSSPixelLength::new(len.to_f32_px())
435 }
436}
437
438impl From<CSSPixelLength> for euclid::Length<CSSFloat, CSSPixel> {
439 #[inline]
440 fn from(length: CSSPixelLength) -> Self {
441 Self::new(length.0)
442 }
443}
444
445pub type Length = CSSPixelLength;
447
448pub type LengthOrAuto = generics::GenericLengthPercentageOrAuto<Length>;
450
451pub type NonNegativeLengthOrAuto = generics::GenericLengthPercentageOrAuto<NonNegativeLength>;
453
454pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
456
457pub type NonNegativeLength = NonNegative<Length>;
459
460impl ToAnimatedValue for NonNegativeLength {
461 type AnimatedValue = Length;
462
463 #[inline]
464 fn to_animated_value(self, context: &AnimatedContext) -> Self::AnimatedValue {
465 self.0.to_animated_value(context)
466 }
467
468 #[inline]
469 fn from_animated_value(animated: Self::AnimatedValue) -> Self {
470 NonNegativeLength::new(animated.px().max(0.))
471 }
472}
473
474impl NonNegativeLength {
475 #[inline]
477 pub fn new(px: CSSFloat) -> Self {
478 NonNegative(Length::new(px.max(0.)))
479 }
480
481 #[inline]
483 pub fn px(&self) -> CSSFloat {
484 self.0.px()
485 }
486
487 #[inline]
488 pub fn clamp(self) -> Self {
490 if (self.0).0 < 0. {
491 Self::zero()
492 } else {
493 self
494 }
495 }
496}
497
498impl From<Length> for NonNegativeLength {
499 #[inline]
500 fn from(len: Length) -> Self {
501 NonNegative(len)
502 }
503}
504
505impl From<Au> for NonNegativeLength {
506 #[inline]
507 fn from(au: Au) -> Self {
508 NonNegative(au.into())
509 }
510}
511
512impl From<NonNegativeLength> for Au {
513 #[inline]
514 fn from(non_negative_len: NonNegativeLength) -> Self {
515 Au::from(non_negative_len.0)
516 }
517}
518
519pub type NonNegativeLengthPercentageOrNormal =
521 GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
522
523pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
525
526pub type Size = GenericSize<NonNegativeLengthPercentage>;
528
529pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
531
532#[cfg(feature = "gecko")]
533use crate::{
534 gecko_bindings::structs::AnchorPosResolutionParams, logical_geometry::PhysicalAxis,
535 values::generics::length::AnchorSizeKeyword, values::DashedIdent,
536};
537
538#[cfg(feature = "gecko")]
542pub fn resolve_anchor_size(
543 anchor_name: &DashedIdent,
544 prop_axis: PhysicalAxis,
545 anchor_size_keyword: AnchorSizeKeyword,
546 params: &AnchorPosResolutionParams,
547) -> Result<Length, ()> {
548 use crate::gecko_bindings::structs::Gecko_GetAnchorPosSize;
549
550 let mut offset = Length::zero();
551 let valid = unsafe {
552 Gecko_GetAnchorPosSize(
553 params,
554 anchor_name.0.as_ptr(),
555 prop_axis as u8,
556 anchor_size_keyword as u8,
557 &mut offset,
558 )
559 };
560
561 if !valid {
562 return Err(());
563 }
564
565 Ok(offset)
566}
567
568pub type Margin = generics::GenericMargin<LengthPercentage>;