1use super::{AllowQuirks, Number, Percentage, ToComputedValue};
10use crate::computed_value_flags::ComputedValueFlags;
11use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
12#[cfg(feature = "gecko")]
13use crate::gecko_bindings::structs::GeckoFontMetrics;
14use crate::parser::{Parse, ParserContext};
15use crate::values::computed::{self, CSSPixelLength, Context};
16use crate::values::generics::length as generics;
17use crate::values::generics::length::{
18 GenericAnchorSizeFunction, GenericLengthOrNumber, GenericLengthPercentageOrNormal,
19 GenericMargin, GenericMaxSize, GenericSize,
20};
21use crate::values::generics::NonNegative;
22use crate::values::specified::calc::{self, AllowAnchorPositioningFunctions, CalcNode};
23use crate::values::specified::font::QueryFontMetricsFlags;
24use crate::values::specified::NonNegativeNumber;
25use crate::values::CSSFloat;
26use crate::{Zero, ZeroNoPercent};
27use app_units::AU_PER_PX;
28use cssparser::{Parser, Token};
29use std::cmp;
30use std::fmt::{self, Write};
31use style_traits::values::specified::AllowedNumericType;
32use style_traits::{CssWriter, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss};
33
34pub use super::image::Image;
35pub use super::image::{EndingShape as GradientEndingShape, Gradient};
36pub use crate::values::specified::calc::CalcLengthPercentage;
37
38pub const PX_PER_IN: CSSFloat = 96.;
40pub const PX_PER_CM: CSSFloat = PX_PER_IN / 2.54;
42pub const PX_PER_MM: CSSFloat = PX_PER_IN / 25.4;
44pub const PX_PER_Q: CSSFloat = PX_PER_MM / 4.;
46pub const PX_PER_PT: CSSFloat = PX_PER_IN / 72.;
48pub const PX_PER_PC: CSSFloat = PX_PER_PT * 12.;
50
51#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
55#[repr(u8)]
56pub enum FontRelativeLength {
57 #[css(dimension)]
59 Em(CSSFloat),
60 #[css(dimension)]
62 Ex(CSSFloat),
63 #[css(dimension)]
65 Ch(CSSFloat),
66 #[css(dimension)]
68 Cap(CSSFloat),
69 #[css(dimension)]
71 Ic(CSSFloat),
72 #[css(dimension)]
74 Rem(CSSFloat),
75 #[css(dimension)]
77 Lh(CSSFloat),
78 #[css(dimension)]
80 Rlh(CSSFloat),
81}
82
83#[derive(Clone, Copy, Debug, PartialEq)]
85pub enum FontBaseSize {
86 CurrentStyle,
88 InheritedStyle,
90}
91
92#[derive(Clone, Copy, Debug, PartialEq)]
94pub enum LineHeightBase {
95 CurrentStyle,
97 InheritedStyle,
99}
100
101impl FontBaseSize {
102 pub fn resolve(&self, context: &Context) -> computed::FontSize {
104 let style = context.style();
105 match *self {
106 Self::CurrentStyle => style.get_font().clone_font_size(),
107 Self::InheritedStyle => {
108 let zoom = style.effective_zoom_for_inheritance;
111 style.get_parent_font().clone_font_size().zoom(zoom)
112 },
113 }
114 }
115}
116
117impl FontRelativeLength {
118 pub const EM: &'static str = "em";
120 pub const EX: &'static str = "ex";
122 pub const CH: &'static str = "ch";
124 pub const CAP: &'static str = "cap";
126 pub const IC: &'static str = "ic";
128 pub const REM: &'static str = "rem";
130 pub const LH: &'static str = "lh";
132 pub const RLH: &'static str = "rlh";
134
135 fn unitless_value(&self) -> CSSFloat {
137 match *self {
138 Self::Em(v)
139 | Self::Ex(v)
140 | Self::Ch(v)
141 | Self::Cap(v)
142 | Self::Ic(v)
143 | Self::Rem(v)
144 | Self::Lh(v)
145 | Self::Rlh(v) => v,
146 }
147 }
148
149 fn unit(&self) -> &'static str {
151 match *self {
152 Self::Em(_) => Self::EM,
153 Self::Ex(_) => Self::EX,
154 Self::Ch(_) => Self::CH,
155 Self::Cap(_) => Self::CAP,
156 Self::Ic(_) => Self::IC,
157 Self::Rem(_) => Self::REM,
158 Self::Lh(_) => Self::LH,
159 Self::Rlh(_) => Self::RLH,
160 }
161 }
162
163 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
164 where
165 O: Fn(f32, f32) -> f32,
166 {
167 use self::FontRelativeLength::*;
168
169 if std::mem::discriminant(self) != std::mem::discriminant(other) {
170 return Err(());
171 }
172
173 Ok(match (self, other) {
174 (&Em(one), &Em(other)) => Em(op(one, other)),
175 (&Ex(one), &Ex(other)) => Ex(op(one, other)),
176 (&Ch(one), &Ch(other)) => Ch(op(one, other)),
177 (&Cap(one), &Cap(other)) => Cap(op(one, other)),
178 (&Ic(one), &Ic(other)) => Ic(op(one, other)),
179 (&Rem(one), &Rem(other)) => Rem(op(one, other)),
180 (&Lh(one), &Lh(other)) => Lh(op(one, other)),
181 (&Rlh(one), &Rlh(other)) => Rlh(op(one, other)),
182 _ => unsafe {
185 match *self {
186 Em(..) | Ex(..) | Ch(..) | Cap(..) | Ic(..) | Rem(..) | Lh(..) | Rlh(..) => {},
187 }
188 debug_unreachable!("Forgot to handle unit in try_op()")
189 },
190 })
191 }
192
193 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
194 match self {
195 Self::Em(x) => Self::Em(op(*x)),
196 Self::Ex(x) => Self::Ex(op(*x)),
197 Self::Ch(x) => Self::Ch(op(*x)),
198 Self::Cap(x) => Self::Cap(op(*x)),
199 Self::Ic(x) => Self::Ic(op(*x)),
200 Self::Rem(x) => Self::Rem(op(*x)),
201 Self::Lh(x) => Self::Lh(op(*x)),
202 Self::Rlh(x) => Self::Rlh(op(*x)),
203 }
204 }
205
206 pub fn to_computed_value(
208 &self,
209 context: &Context,
210 base_size: FontBaseSize,
211 line_height_base: LineHeightBase,
212 ) -> computed::Length {
213 let (reference_size, length) =
214 self.reference_font_size_and_length(context, base_size, line_height_base);
215 (reference_size * length).finite()
216 }
217
218 #[cfg(feature = "gecko")]
220 pub fn to_computed_pixel_length_with_font_metrics(
221 &self,
222 get_font_metrics: impl Fn() -> GeckoFontMetrics,
223 ) -> Result<CSSFloat, ()> {
224 let metrics = get_font_metrics();
225 Ok(match *self {
226 Self::Em(v) => v * metrics.mComputedEmSize.px(),
227 Self::Ex(v) => v * metrics.mXSize.px(),
228 Self::Ch(v) => v * metrics.mChSize.px(),
229 Self::Cap(v) => v * metrics.mCapHeight.px(),
230 Self::Ic(v) => v * metrics.mIcWidth.px(),
231 Self::Rem(_) | Self::Lh(_) | Self::Rlh(_) => return Err(()),
233 })
234 }
235
236 fn reference_font_size_and_length(
244 &self,
245 context: &Context,
246 base_size: FontBaseSize,
247 line_height_base: LineHeightBase,
248 ) -> (computed::Length, CSSFloat) {
249 fn query_font_metrics(
250 context: &Context,
251 base_size: FontBaseSize,
252 orientation: FontMetricsOrientation,
253 flags: QueryFontMetricsFlags,
254 ) -> FontMetrics {
255 context.query_font_metrics(base_size, orientation, flags)
256 }
257
258 let reference_font_size = base_size.resolve(context);
259 match *self {
260 Self::Em(length) => {
261 if context.for_non_inherited_property && base_size == FontBaseSize::CurrentStyle {
262 context
263 .rule_cache_conditions
264 .borrow_mut()
265 .set_font_size_dependency(reference_font_size.computed_size);
266 }
267
268 (reference_font_size.computed_size(), length)
269 },
270 Self::Ex(length) => {
271 let metrics = query_font_metrics(
273 context,
274 base_size,
275 FontMetricsOrientation::Horizontal,
276 QueryFontMetricsFlags::empty(),
277 );
278 let reference_size = metrics.x_height.unwrap_or_else(|| {
279 reference_font_size.used_size() * 0.5
288 });
289 (reference_size, length)
290 },
291 Self::Ch(length) => {
292 let metrics = query_font_metrics(
300 context,
301 base_size,
302 FontMetricsOrientation::MatchContextPreferHorizontal,
303 QueryFontMetricsFlags::NEEDS_CH,
304 );
305 let reference_size = metrics.zero_advance_measure.unwrap_or_else(|| {
306 let wm = context.style().writing_mode;
319 if wm.is_vertical() && wm.is_upright() {
320 reference_font_size.used_size()
321 } else {
322 reference_font_size.used_size() * 0.5
323 }
324 });
325 (reference_size, length)
326 },
327 Self::Cap(length) => {
328 let metrics = query_font_metrics(
329 context,
330 base_size,
331 FontMetricsOrientation::Horizontal,
332 QueryFontMetricsFlags::empty(),
333 );
334 let reference_size = metrics.cap_height.unwrap_or_else(|| {
335 metrics.ascent
342 });
343 (reference_size, length)
344 },
345 Self::Ic(length) => {
346 let metrics = query_font_metrics(
347 context,
348 base_size,
349 FontMetricsOrientation::MatchContextPreferVertical,
350 QueryFontMetricsFlags::NEEDS_IC,
351 );
352 let reference_size = metrics.ic_width.unwrap_or_else(|| {
353 reference_font_size.used_size()
362 });
363 (reference_size, length)
364 },
365 Self::Rem(length) => {
366 let reference_size = if context.builder.is_root_element || context.in_media_query {
373 reference_font_size.computed_size()
374 } else {
375 context
376 .device()
377 .root_font_size()
378 .zoom(context.builder.effective_zoom)
379 };
380 (reference_size, length)
381 },
382 Self::Lh(length) => {
383 let reference_size = if context.in_media_query {
389 context
390 .device()
391 .calc_line_height(
392 &context.default_style().get_font(),
393 context.style().writing_mode,
394 None,
395 )
396 .0
397 } else {
398 let line_height = context.builder.calc_line_height(
399 context.device(),
400 line_height_base,
401 context.style().writing_mode,
402 );
403 if context.for_non_inherited_property
404 && line_height_base == LineHeightBase::CurrentStyle
405 {
406 context
407 .rule_cache_conditions
408 .borrow_mut()
409 .set_line_height_dependency(line_height)
410 }
411 line_height.0
412 };
413 (reference_size, length)
414 },
415 Self::Rlh(length) => {
416 let reference_size = if context.builder.is_root_element {
422 context
423 .builder
424 .calc_line_height(
425 context.device(),
426 line_height_base,
427 context.style().writing_mode,
428 )
429 .0
430 } else if context.in_media_query {
431 context
432 .device()
433 .calc_line_height(
434 &context.default_style().get_font(),
435 context.style().writing_mode,
436 None,
437 )
438 .0
439 } else {
440 context.device().root_line_height()
441 };
442 let reference_size = reference_size.zoom(context.builder.effective_zoom);
443 (reference_size, length)
444 },
445 }
446 }
447}
448
449pub enum ViewportVariant {
451 UADefault,
453 Small,
455 Large,
457 Dynamic,
459}
460
461#[derive(PartialEq)]
463enum ViewportUnit {
464 Vw,
466 Vh,
468 Vmin,
470 Vmax,
472 Vb,
474 Vi,
476}
477
478#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
482#[repr(u8)]
483pub enum ViewportPercentageLength {
484 #[css(dimension)]
486 Vw(CSSFloat),
487 #[css(dimension)]
489 Svw(CSSFloat),
490 #[css(dimension)]
492 Lvw(CSSFloat),
493 #[css(dimension)]
495 Dvw(CSSFloat),
496 #[css(dimension)]
498 Vh(CSSFloat),
499 #[css(dimension)]
501 Svh(CSSFloat),
502 #[css(dimension)]
504 Lvh(CSSFloat),
505 #[css(dimension)]
507 Dvh(CSSFloat),
508 #[css(dimension)]
510 Vmin(CSSFloat),
511 #[css(dimension)]
513 Svmin(CSSFloat),
514 #[css(dimension)]
516 Lvmin(CSSFloat),
517 #[css(dimension)]
519 Dvmin(CSSFloat),
520 #[css(dimension)]
522 Vmax(CSSFloat),
523 #[css(dimension)]
525 Svmax(CSSFloat),
526 #[css(dimension)]
528 Lvmax(CSSFloat),
529 #[css(dimension)]
531 Dvmax(CSSFloat),
532 #[css(dimension)]
534 Vb(CSSFloat),
535 #[css(dimension)]
537 Svb(CSSFloat),
538 #[css(dimension)]
540 Lvb(CSSFloat),
541 #[css(dimension)]
543 Dvb(CSSFloat),
544 #[css(dimension)]
546 Vi(CSSFloat),
547 #[css(dimension)]
549 Svi(CSSFloat),
550 #[css(dimension)]
552 Lvi(CSSFloat),
553 #[css(dimension)]
555 Dvi(CSSFloat),
556}
557
558impl ViewportPercentageLength {
559 fn unitless_value(&self) -> CSSFloat {
561 self.unpack().2
562 }
563
564 fn unit(&self) -> &'static str {
566 match *self {
567 Self::Vw(_) => "vw",
568 Self::Lvw(_) => "lvw",
569 Self::Svw(_) => "svw",
570 Self::Dvw(_) => "dvw",
571 Self::Vh(_) => "vh",
572 Self::Svh(_) => "svh",
573 Self::Lvh(_) => "lvh",
574 Self::Dvh(_) => "dvh",
575 Self::Vmin(_) => "vmin",
576 Self::Svmin(_) => "svmin",
577 Self::Lvmin(_) => "lvmin",
578 Self::Dvmin(_) => "dvmin",
579 Self::Vmax(_) => "vmax",
580 Self::Svmax(_) => "svmax",
581 Self::Lvmax(_) => "lvmax",
582 Self::Dvmax(_) => "dvmax",
583 Self::Vb(_) => "vb",
584 Self::Svb(_) => "svb",
585 Self::Lvb(_) => "lvb",
586 Self::Dvb(_) => "dvb",
587 Self::Vi(_) => "vi",
588 Self::Svi(_) => "svi",
589 Self::Lvi(_) => "lvi",
590 Self::Dvi(_) => "dvi",
591 }
592 }
593
594 fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) {
595 match *self {
596 Self::Vw(v) => (ViewportVariant::UADefault, ViewportUnit::Vw, v),
597 Self::Svw(v) => (ViewportVariant::Small, ViewportUnit::Vw, v),
598 Self::Lvw(v) => (ViewportVariant::Large, ViewportUnit::Vw, v),
599 Self::Dvw(v) => (ViewportVariant::Dynamic, ViewportUnit::Vw, v),
600 Self::Vh(v) => (ViewportVariant::UADefault, ViewportUnit::Vh, v),
601 Self::Svh(v) => (ViewportVariant::Small, ViewportUnit::Vh, v),
602 Self::Lvh(v) => (ViewportVariant::Large, ViewportUnit::Vh, v),
603 Self::Dvh(v) => (ViewportVariant::Dynamic, ViewportUnit::Vh, v),
604 Self::Vmin(v) => (ViewportVariant::UADefault, ViewportUnit::Vmin, v),
605 Self::Svmin(v) => (ViewportVariant::Small, ViewportUnit::Vmin, v),
606 Self::Lvmin(v) => (ViewportVariant::Large, ViewportUnit::Vmin, v),
607 Self::Dvmin(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmin, v),
608 Self::Vmax(v) => (ViewportVariant::UADefault, ViewportUnit::Vmax, v),
609 Self::Svmax(v) => (ViewportVariant::Small, ViewportUnit::Vmax, v),
610 Self::Lvmax(v) => (ViewportVariant::Large, ViewportUnit::Vmax, v),
611 Self::Dvmax(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmax, v),
612 Self::Vb(v) => (ViewportVariant::UADefault, ViewportUnit::Vb, v),
613 Self::Svb(v) => (ViewportVariant::Small, ViewportUnit::Vb, v),
614 Self::Lvb(v) => (ViewportVariant::Large, ViewportUnit::Vb, v),
615 Self::Dvb(v) => (ViewportVariant::Dynamic, ViewportUnit::Vb, v),
616 Self::Vi(v) => (ViewportVariant::UADefault, ViewportUnit::Vi, v),
617 Self::Svi(v) => (ViewportVariant::Small, ViewportUnit::Vi, v),
618 Self::Lvi(v) => (ViewportVariant::Large, ViewportUnit::Vi, v),
619 Self::Dvi(v) => (ViewportVariant::Dynamic, ViewportUnit::Vi, v),
620 }
621 }
622
623 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
624 where
625 O: Fn(f32, f32) -> f32,
626 {
627 use self::ViewportPercentageLength::*;
628
629 if std::mem::discriminant(self) != std::mem::discriminant(other) {
630 return Err(());
631 }
632
633 Ok(match (self, other) {
634 (&Vw(one), &Vw(other)) => Vw(op(one, other)),
635 (&Svw(one), &Svw(other)) => Svw(op(one, other)),
636 (&Lvw(one), &Lvw(other)) => Lvw(op(one, other)),
637 (&Dvw(one), &Dvw(other)) => Dvw(op(one, other)),
638 (&Vh(one), &Vh(other)) => Vh(op(one, other)),
639 (&Svh(one), &Svh(other)) => Svh(op(one, other)),
640 (&Lvh(one), &Lvh(other)) => Lvh(op(one, other)),
641 (&Dvh(one), &Dvh(other)) => Dvh(op(one, other)),
642 (&Vmin(one), &Vmin(other)) => Vmin(op(one, other)),
643 (&Svmin(one), &Svmin(other)) => Svmin(op(one, other)),
644 (&Lvmin(one), &Lvmin(other)) => Lvmin(op(one, other)),
645 (&Dvmin(one), &Dvmin(other)) => Dvmin(op(one, other)),
646 (&Vmax(one), &Vmax(other)) => Vmax(op(one, other)),
647 (&Svmax(one), &Svmax(other)) => Svmax(op(one, other)),
648 (&Lvmax(one), &Lvmax(other)) => Lvmax(op(one, other)),
649 (&Dvmax(one), &Dvmax(other)) => Dvmax(op(one, other)),
650 (&Vb(one), &Vb(other)) => Vb(op(one, other)),
651 (&Svb(one), &Svb(other)) => Svb(op(one, other)),
652 (&Lvb(one), &Lvb(other)) => Lvb(op(one, other)),
653 (&Dvb(one), &Dvb(other)) => Dvb(op(one, other)),
654 (&Vi(one), &Vi(other)) => Vi(op(one, other)),
655 (&Svi(one), &Svi(other)) => Svi(op(one, other)),
656 (&Lvi(one), &Lvi(other)) => Lvi(op(one, other)),
657 (&Dvi(one), &Dvi(other)) => Dvi(op(one, other)),
658 _ => unsafe {
661 match *self {
662 Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) | Dvh(..)
663 | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) | Svmax(..)
664 | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) | Vi(..)
665 | Svi(..) | Lvi(..) | Dvi(..) => {},
666 }
667 debug_unreachable!("Forgot to handle unit in try_op()")
668 },
669 })
670 }
671
672 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
673 match self {
674 Self::Vw(x) => Self::Vw(op(*x)),
675 Self::Svw(x) => Self::Svw(op(*x)),
676 Self::Lvw(x) => Self::Lvw(op(*x)),
677 Self::Dvw(x) => Self::Dvw(op(*x)),
678 Self::Vh(x) => Self::Vh(op(*x)),
679 Self::Svh(x) => Self::Svh(op(*x)),
680 Self::Lvh(x) => Self::Lvh(op(*x)),
681 Self::Dvh(x) => Self::Dvh(op(*x)),
682 Self::Vmin(x) => Self::Vmin(op(*x)),
683 Self::Svmin(x) => Self::Svmin(op(*x)),
684 Self::Lvmin(x) => Self::Lvmin(op(*x)),
685 Self::Dvmin(x) => Self::Dvmin(op(*x)),
686 Self::Vmax(x) => Self::Vmax(op(*x)),
687 Self::Svmax(x) => Self::Svmax(op(*x)),
688 Self::Lvmax(x) => Self::Lvmax(op(*x)),
689 Self::Dvmax(x) => Self::Dvmax(op(*x)),
690 Self::Vb(x) => Self::Vb(op(*x)),
691 Self::Svb(x) => Self::Svb(op(*x)),
692 Self::Lvb(x) => Self::Lvb(op(*x)),
693 Self::Dvb(x) => Self::Dvb(op(*x)),
694 Self::Vi(x) => Self::Vi(op(*x)),
695 Self::Svi(x) => Self::Svi(op(*x)),
696 Self::Lvi(x) => Self::Lvi(op(*x)),
697 Self::Dvi(x) => Self::Dvi(op(*x)),
698 }
699 }
700
701 pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
703 let (variant, unit, factor) = self.unpack();
704 let size = context.viewport_size_for_viewport_unit_resolution(variant);
705 let length: app_units::Au = match unit {
706 ViewportUnit::Vw => size.width,
707 ViewportUnit::Vh => size.height,
708 ViewportUnit::Vmin => cmp::min(size.width, size.height),
709 ViewportUnit::Vmax => cmp::max(size.width, size.height),
710 ViewportUnit::Vi | ViewportUnit::Vb => {
711 context
712 .rule_cache_conditions
713 .borrow_mut()
714 .set_writing_mode_dependency(context.builder.writing_mode);
715 if (unit == ViewportUnit::Vb) == context.style().writing_mode.is_vertical() {
716 size.width
717 } else {
718 size.height
719 }
720 },
721 };
722
723 let length = context.builder.effective_zoom.zoom(length.0 as f32);
725
726 let trunc_scaled =
731 ((length as f64 * factor as f64 / 100.).trunc() / AU_PER_PX as f64) as f32;
732 CSSPixelLength::new(crate::values::normalize(trunc_scaled))
733 }
734}
735
736#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
738#[repr(C)]
739pub struct CharacterWidth(pub i32);
740
741impl CharacterWidth {
742 pub fn to_computed_value(&self, reference_font_size: computed::Length) -> computed::Length {
744 let average_advance = reference_font_size * 0.5;
749 let max_advance = reference_font_size;
750 (average_advance * (self.0 as CSSFloat - 1.0) + max_advance).finite()
751 }
752}
753
754#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
756#[repr(u8)]
757pub enum AbsoluteLength {
758 #[css(dimension)]
760 Px(CSSFloat),
761 #[css(dimension)]
763 In(CSSFloat),
764 #[css(dimension)]
766 Cm(CSSFloat),
767 #[css(dimension)]
769 Mm(CSSFloat),
770 #[css(dimension)]
772 Q(CSSFloat),
773 #[css(dimension)]
775 Pt(CSSFloat),
776 #[css(dimension)]
778 Pc(CSSFloat),
779}
780
781impl AbsoluteLength {
782 fn unitless_value(&self) -> CSSFloat {
784 match *self {
785 Self::Px(v)
786 | Self::In(v)
787 | Self::Cm(v)
788 | Self::Mm(v)
789 | Self::Q(v)
790 | Self::Pt(v)
791 | Self::Pc(v) => v,
792 }
793 }
794
795 fn unit(&self) -> &'static str {
797 match *self {
798 Self::Px(_) => "px",
799 Self::In(_) => "in",
800 Self::Cm(_) => "cm",
801 Self::Mm(_) => "mm",
802 Self::Q(_) => "q",
803 Self::Pt(_) => "pt",
804 Self::Pc(_) => "pc",
805 }
806 }
807
808 #[inline]
810 pub fn to_px(&self) -> CSSFloat {
811 match *self {
812 Self::Px(value) => value,
813 Self::In(value) => value * PX_PER_IN,
814 Self::Cm(value) => value * PX_PER_CM,
815 Self::Mm(value) => value * PX_PER_MM,
816 Self::Q(value) => value * PX_PER_Q,
817 Self::Pt(value) => value * PX_PER_PT,
818 Self::Pc(value) => value * PX_PER_PC,
819 }
820 }
821
822 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
823 where
824 O: Fn(f32, f32) -> f32,
825 {
826 Ok(Self::Px(op(self.to_px(), other.to_px())))
827 }
828
829 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
830 Self::Px(op(self.to_px()))
831 }
832}
833
834impl ToComputedValue for AbsoluteLength {
835 type ComputedValue = CSSPixelLength;
836
837 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
838 CSSPixelLength::new(self.to_px())
839 .zoom(context.builder.effective_zoom)
840 .finite()
841 }
842
843 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
844 Self::Px(computed.px())
845 }
846}
847
848impl PartialOrd for AbsoluteLength {
849 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
850 self.to_px().partial_cmp(&other.to_px())
851 }
852}
853
854#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
858#[repr(u8)]
859pub enum ContainerRelativeLength {
860 #[css(dimension)]
862 Cqw(CSSFloat),
863 #[css(dimension)]
865 Cqh(CSSFloat),
866 #[css(dimension)]
868 Cqi(CSSFloat),
869 #[css(dimension)]
871 Cqb(CSSFloat),
872 #[css(dimension)]
874 Cqmin(CSSFloat),
875 #[css(dimension)]
877 Cqmax(CSSFloat),
878}
879
880impl ContainerRelativeLength {
881 fn unitless_value(&self) -> CSSFloat {
882 match *self {
883 Self::Cqw(v)
884 | Self::Cqh(v)
885 | Self::Cqi(v)
886 | Self::Cqb(v)
887 | Self::Cqmin(v)
888 | Self::Cqmax(v) => v,
889 }
890 }
891
892 fn unit(&self) -> &'static str {
894 match *self {
895 Self::Cqw(_) => "cqw",
896 Self::Cqh(_) => "cqh",
897 Self::Cqi(_) => "cqi",
898 Self::Cqb(_) => "cqb",
899 Self::Cqmin(_) => "cqmin",
900 Self::Cqmax(_) => "cqmax",
901 }
902 }
903
904 pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
905 where
906 O: Fn(f32, f32) -> f32,
907 {
908 use self::ContainerRelativeLength::*;
909
910 if std::mem::discriminant(self) != std::mem::discriminant(other) {
911 return Err(());
912 }
913
914 Ok(match (self, other) {
915 (&Cqw(one), &Cqw(other)) => Cqw(op(one, other)),
916 (&Cqh(one), &Cqh(other)) => Cqh(op(one, other)),
917 (&Cqi(one), &Cqi(other)) => Cqi(op(one, other)),
918 (&Cqb(one), &Cqb(other)) => Cqb(op(one, other)),
919 (&Cqmin(one), &Cqmin(other)) => Cqmin(op(one, other)),
920 (&Cqmax(one), &Cqmax(other)) => Cqmax(op(one, other)),
921
922 _ => unsafe {
926 match *self {
927 Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
928 }
929 debug_unreachable!("Forgot to handle unit in try_op()")
930 },
931 })
932 }
933
934 pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
935 match self {
936 Self::Cqw(x) => Self::Cqw(op(*x)),
937 Self::Cqh(x) => Self::Cqh(op(*x)),
938 Self::Cqi(x) => Self::Cqi(op(*x)),
939 Self::Cqb(x) => Self::Cqb(op(*x)),
940 Self::Cqmin(x) => Self::Cqmin(op(*x)),
941 Self::Cqmax(x) => Self::Cqmax(op(*x)),
942 }
943 }
944
945 pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
947 if context.for_non_inherited_property {
948 context.rule_cache_conditions.borrow_mut().set_uncacheable();
949 }
950 context
951 .builder
952 .add_flags(ComputedValueFlags::USES_CONTAINER_UNITS);
953
954 let size = context.get_container_size_query();
958 let (factor, container_length) = match *self {
959 Self::Cqw(v) => (v, size.get_container_width(context)),
960 Self::Cqh(v) => (v, size.get_container_height(context)),
961 Self::Cqi(v) => (v, size.get_container_inline_size(context)),
962 Self::Cqb(v) => (v, size.get_container_block_size(context)),
963 Self::Cqmin(v) => (
964 v,
965 cmp::min(
966 size.get_container_inline_size(context),
967 size.get_container_block_size(context),
968 ),
969 ),
970 Self::Cqmax(v) => (
971 v,
972 cmp::max(
973 size.get_container_inline_size(context),
974 size.get_container_block_size(context),
975 ),
976 ),
977 };
978 CSSPixelLength::new((container_length.to_f64_px() * factor as f64 / 100.0) as f32).finite()
979 }
980}
981
982#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
986#[repr(u8)]
987pub enum NoCalcLength {
988 Absolute(AbsoluteLength),
992
993 FontRelative(FontRelativeLength),
997
998 ViewportPercentage(ViewportPercentageLength),
1002
1003 ContainerRelative(ContainerRelativeLength),
1007 ServoCharacterWidth(CharacterWidth),
1012}
1013
1014impl NoCalcLength {
1015 pub fn unitless_value(&self) -> CSSFloat {
1017 match *self {
1018 Self::Absolute(v) => v.unitless_value(),
1019 Self::FontRelative(v) => v.unitless_value(),
1020 Self::ViewportPercentage(v) => v.unitless_value(),
1021 Self::ContainerRelative(v) => v.unitless_value(),
1022 Self::ServoCharacterWidth(c) => c.0 as f32,
1023 }
1024 }
1025
1026 fn unit(&self) -> &'static str {
1028 match *self {
1029 Self::Absolute(v) => v.unit(),
1030 Self::FontRelative(v) => v.unit(),
1031 Self::ViewportPercentage(v) => v.unit(),
1032 Self::ContainerRelative(v) => v.unit(),
1033 Self::ServoCharacterWidth(_) => "",
1034 }
1035 }
1036
1037 pub fn is_negative(&self) -> bool {
1039 self.unitless_value().is_sign_negative()
1040 }
1041
1042 pub fn is_zero(&self) -> bool {
1044 self.unitless_value() == 0.0
1045 }
1046
1047 pub fn is_infinite(&self) -> bool {
1049 self.unitless_value().is_infinite()
1050 }
1051
1052 pub fn is_nan(&self) -> bool {
1054 self.unitless_value().is_nan()
1055 }
1056
1057 pub fn should_zoom_text(&self) -> bool {
1062 match *self {
1063 Self::Absolute(..) | Self::ViewportPercentage(..) | Self::ContainerRelative(..) => true,
1064 Self::ServoCharacterWidth(..) | Self::FontRelative(..) => false,
1065 }
1066 }
1067
1068 pub fn parse_dimension(
1070 context: &ParserContext,
1071 value: CSSFloat,
1072 unit: &str,
1073 ) -> Result<Self, ()> {
1074 Ok(match_ignore_ascii_case! { unit,
1075 "px" => Self::Absolute(AbsoluteLength::Px(value)),
1076 "in" => Self::Absolute(AbsoluteLength::In(value)),
1077 "cm" => Self::Absolute(AbsoluteLength::Cm(value)),
1078 "mm" => Self::Absolute(AbsoluteLength::Mm(value)),
1079 "q" => Self::Absolute(AbsoluteLength::Q(value)),
1080 "pt" => Self::Absolute(AbsoluteLength::Pt(value)),
1081 "pc" => Self::Absolute(AbsoluteLength::Pc(value)),
1082 "em" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Em(value)),
1084 "ex" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ex(value)),
1085 "ch" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ch(value)),
1086 "cap" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Cap(value)),
1087 "ic" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ic(value)),
1088 "rem" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rem(value)),
1089 "lh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Lh(value)),
1090 "rlh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rlh(value)),
1091 "vw" if !context.in_page_rule() => {
1093 Self::ViewportPercentage(ViewportPercentageLength::Vw(value))
1094 },
1095 "svw" if !context.in_page_rule() => {
1096 Self::ViewportPercentage(ViewportPercentageLength::Svw(value))
1097 },
1098 "lvw" if !context.in_page_rule() => {
1099 Self::ViewportPercentage(ViewportPercentageLength::Lvw(value))
1100 },
1101 "dvw" if !context.in_page_rule() => {
1102 Self::ViewportPercentage(ViewportPercentageLength::Dvw(value))
1103 },
1104 "vh" if !context.in_page_rule() => {
1105 Self::ViewportPercentage(ViewportPercentageLength::Vh(value))
1106 },
1107 "svh" if !context.in_page_rule() => {
1108 Self::ViewportPercentage(ViewportPercentageLength::Svh(value))
1109 },
1110 "lvh" if !context.in_page_rule() => {
1111 Self::ViewportPercentage(ViewportPercentageLength::Lvh(value))
1112 },
1113 "dvh" if !context.in_page_rule() => {
1114 Self::ViewportPercentage(ViewportPercentageLength::Dvh(value))
1115 },
1116 "vmin" if !context.in_page_rule() => {
1117 Self::ViewportPercentage(ViewportPercentageLength::Vmin(value))
1118 },
1119 "svmin" if !context.in_page_rule() => {
1120 Self::ViewportPercentage(ViewportPercentageLength::Svmin(value))
1121 },
1122 "lvmin" if !context.in_page_rule() => {
1123 Self::ViewportPercentage(ViewportPercentageLength::Lvmin(value))
1124 },
1125 "dvmin" if !context.in_page_rule() => {
1126 Self::ViewportPercentage(ViewportPercentageLength::Dvmin(value))
1127 },
1128 "vmax" if !context.in_page_rule() => {
1129 Self::ViewportPercentage(ViewportPercentageLength::Vmax(value))
1130 },
1131 "svmax" if !context.in_page_rule() => {
1132 Self::ViewportPercentage(ViewportPercentageLength::Svmax(value))
1133 },
1134 "lvmax" if !context.in_page_rule() => {
1135 Self::ViewportPercentage(ViewportPercentageLength::Lvmax(value))
1136 },
1137 "dvmax" if !context.in_page_rule() => {
1138 Self::ViewportPercentage(ViewportPercentageLength::Dvmax(value))
1139 },
1140 "vb" if !context.in_page_rule() => {
1141 Self::ViewportPercentage(ViewportPercentageLength::Vb(value))
1142 },
1143 "svb" if !context.in_page_rule() => {
1144 Self::ViewportPercentage(ViewportPercentageLength::Svb(value))
1145 },
1146 "lvb" if !context.in_page_rule() => {
1147 Self::ViewportPercentage(ViewportPercentageLength::Lvb(value))
1148 },
1149 "dvb" if !context.in_page_rule() => {
1150 Self::ViewportPercentage(ViewportPercentageLength::Dvb(value))
1151 },
1152 "vi" if !context.in_page_rule() => {
1153 Self::ViewportPercentage(ViewportPercentageLength::Vi(value))
1154 },
1155 "svi" if !context.in_page_rule() => {
1156 Self::ViewportPercentage(ViewportPercentageLength::Svi(value))
1157 },
1158 "lvi" if !context.in_page_rule() => {
1159 Self::ViewportPercentage(ViewportPercentageLength::Lvi(value))
1160 },
1161 "dvi" if !context.in_page_rule() => {
1162 Self::ViewportPercentage(ViewportPercentageLength::Dvi(value))
1163 },
1164 "cqw" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1167 Self::ContainerRelative(ContainerRelativeLength::Cqw(value))
1168 },
1169 "cqh" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1170 Self::ContainerRelative(ContainerRelativeLength::Cqh(value))
1171 },
1172 "cqi" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1173 Self::ContainerRelative(ContainerRelativeLength::Cqi(value))
1174 },
1175 "cqb" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1176 Self::ContainerRelative(ContainerRelativeLength::Cqb(value))
1177 },
1178 "cqmin" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1179 Self::ContainerRelative(ContainerRelativeLength::Cqmin(value))
1180 },
1181 "cqmax" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1182 Self::ContainerRelative(ContainerRelativeLength::Cqmax(value))
1183 },
1184 _ => return Err(()),
1185 })
1186 }
1187
1188 pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
1189 where
1190 O: Fn(f32, f32) -> f32,
1191 {
1192 use self::NoCalcLength::*;
1193
1194 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1195 return Err(());
1196 }
1197
1198 Ok(match (self, other) {
1199 (&Absolute(ref one), &Absolute(ref other)) => Absolute(one.try_op(other, op)?),
1200 (&FontRelative(ref one), &FontRelative(ref other)) => {
1201 FontRelative(one.try_op(other, op)?)
1202 },
1203 (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
1204 ViewportPercentage(one.try_op(other, op)?)
1205 },
1206 (&ContainerRelative(ref one), &ContainerRelative(ref other)) => {
1207 ContainerRelative(one.try_op(other, op)?)
1208 },
1209 (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
1210 ServoCharacterWidth(CharacterWidth(op(one.0 as f32, other.0 as f32) as i32))
1211 },
1212 _ => unsafe {
1215 match *self {
1216 Absolute(..)
1217 | FontRelative(..)
1218 | ViewportPercentage(..)
1219 | ContainerRelative(..)
1220 | ServoCharacterWidth(..) => {},
1221 }
1222 debug_unreachable!("Forgot to handle unit in try_op()")
1223 },
1224 })
1225 }
1226
1227 pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
1228 use self::NoCalcLength::*;
1229
1230 match self {
1231 Absolute(ref one) => Absolute(one.map(op)),
1232 FontRelative(ref one) => FontRelative(one.map(op)),
1233 ViewportPercentage(ref one) => ViewportPercentage(one.map(op)),
1234 ContainerRelative(ref one) => ContainerRelative(one.map(op)),
1235 ServoCharacterWidth(ref one) => {
1236 ServoCharacterWidth(CharacterWidth(op(one.0 as f32) as i32))
1237 },
1238 }
1239 }
1240
1241 #[inline]
1243 pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
1244 match *self {
1245 Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
1246 _ => Err(()),
1247 }
1248 }
1249
1250 #[cfg(feature = "gecko")]
1253 #[inline]
1254 pub fn to_computed_pixel_length_with_font_metrics(
1255 &self,
1256 get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
1257 ) -> Result<CSSFloat, ()> {
1258 match *self {
1259 Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
1260 Self::FontRelative(fr) => {
1261 if let Some(getter) = get_font_metrics {
1262 fr.to_computed_pixel_length_with_font_metrics(getter)
1263 } else {
1264 Err(())
1265 }
1266 },
1267 _ => Err(()),
1268 }
1269 }
1270
1271 #[inline]
1273 pub fn from_px(px_value: CSSFloat) -> NoCalcLength {
1274 NoCalcLength::Absolute(AbsoluteLength::Px(px_value))
1275 }
1276}
1277
1278impl ToCss for NoCalcLength {
1279 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1280 where
1281 W: Write,
1282 {
1283 crate::values::serialize_specified_dimension(
1284 self.unitless_value(),
1285 self.unit(),
1286 false,
1287 dest,
1288 )
1289 }
1290}
1291
1292impl SpecifiedValueInfo for NoCalcLength {}
1293
1294impl PartialOrd for NoCalcLength {
1295 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1296 use self::NoCalcLength::*;
1297
1298 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1299 return None;
1300 }
1301
1302 match (self, other) {
1303 (&Absolute(ref one), &Absolute(ref other)) => one.to_px().partial_cmp(&other.to_px()),
1304 (&FontRelative(ref one), &FontRelative(ref other)) => one.partial_cmp(other),
1305 (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
1306 one.partial_cmp(other)
1307 },
1308 (&ContainerRelative(ref one), &ContainerRelative(ref other)) => one.partial_cmp(other),
1309 (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
1310 one.0.partial_cmp(&other.0)
1311 },
1312 _ => unsafe {
1315 match *self {
1316 Absolute(..)
1317 | FontRelative(..)
1318 | ViewportPercentage(..)
1319 | ContainerRelative(..)
1320 | ServoCharacterWidth(..) => {},
1321 }
1322 debug_unreachable!("Forgot an arm in partial_cmp?")
1323 },
1324 }
1325 }
1326}
1327
1328impl Zero for NoCalcLength {
1329 fn zero() -> Self {
1330 NoCalcLength::Absolute(AbsoluteLength::Px(0.))
1331 }
1332
1333 fn is_zero(&self) -> bool {
1334 NoCalcLength::is_zero(self)
1335 }
1336}
1337
1338#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
1343pub enum Length {
1344 NoCalc(NoCalcLength),
1346 Calc(Box<CalcLengthPercentage>),
1350}
1351
1352impl From<NoCalcLength> for Length {
1353 #[inline]
1354 fn from(len: NoCalcLength) -> Self {
1355 Length::NoCalc(len)
1356 }
1357}
1358
1359impl PartialOrd for FontRelativeLength {
1360 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1361 use self::FontRelativeLength::*;
1362
1363 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1364 return None;
1365 }
1366
1367 match (self, other) {
1368 (&Em(ref one), &Em(ref other)) => one.partial_cmp(other),
1369 (&Ex(ref one), &Ex(ref other)) => one.partial_cmp(other),
1370 (&Ch(ref one), &Ch(ref other)) => one.partial_cmp(other),
1371 (&Cap(ref one), &Cap(ref other)) => one.partial_cmp(other),
1372 (&Ic(ref one), &Ic(ref other)) => one.partial_cmp(other),
1373 (&Rem(ref one), &Rem(ref other)) => one.partial_cmp(other),
1374 (&Lh(ref one), &Lh(ref other)) => one.partial_cmp(other),
1375 (&Rlh(ref one), &Rlh(ref other)) => one.partial_cmp(other),
1376 _ => unsafe {
1379 match *self {
1380 Em(..) | Ex(..) | Ch(..) | Cap(..) | Ic(..) | Rem(..) | Lh(..) | Rlh(..) => {},
1381 }
1382 debug_unreachable!("Forgot an arm in partial_cmp?")
1383 },
1384 }
1385 }
1386}
1387
1388impl PartialOrd for ContainerRelativeLength {
1389 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1390 use self::ContainerRelativeLength::*;
1391
1392 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1393 return None;
1394 }
1395
1396 match (self, other) {
1397 (&Cqw(ref one), &Cqw(ref other)) => one.partial_cmp(other),
1398 (&Cqh(ref one), &Cqh(ref other)) => one.partial_cmp(other),
1399 (&Cqi(ref one), &Cqi(ref other)) => one.partial_cmp(other),
1400 (&Cqb(ref one), &Cqb(ref other)) => one.partial_cmp(other),
1401 (&Cqmin(ref one), &Cqmin(ref other)) => one.partial_cmp(other),
1402 (&Cqmax(ref one), &Cqmax(ref other)) => one.partial_cmp(other),
1403
1404 _ => unsafe {
1408 match *self {
1409 Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
1410 }
1411 debug_unreachable!("Forgot to handle unit in partial_cmp()")
1412 },
1413 }
1414 }
1415}
1416
1417impl PartialOrd for ViewportPercentageLength {
1418 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1419 use self::ViewportPercentageLength::*;
1420
1421 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1422 return None;
1423 }
1424
1425 match (self, other) {
1426 (&Vw(ref one), &Vw(ref other)) => one.partial_cmp(other),
1427 (&Svw(ref one), &Svw(ref other)) => one.partial_cmp(other),
1428 (&Lvw(ref one), &Lvw(ref other)) => one.partial_cmp(other),
1429 (&Dvw(ref one), &Dvw(ref other)) => one.partial_cmp(other),
1430 (&Vh(ref one), &Vh(ref other)) => one.partial_cmp(other),
1431 (&Svh(ref one), &Svh(ref other)) => one.partial_cmp(other),
1432 (&Lvh(ref one), &Lvh(ref other)) => one.partial_cmp(other),
1433 (&Dvh(ref one), &Dvh(ref other)) => one.partial_cmp(other),
1434 (&Vmin(ref one), &Vmin(ref other)) => one.partial_cmp(other),
1435 (&Svmin(ref one), &Svmin(ref other)) => one.partial_cmp(other),
1436 (&Lvmin(ref one), &Lvmin(ref other)) => one.partial_cmp(other),
1437 (&Dvmin(ref one), &Dvmin(ref other)) => one.partial_cmp(other),
1438 (&Vmax(ref one), &Vmax(ref other)) => one.partial_cmp(other),
1439 (&Svmax(ref one), &Svmax(ref other)) => one.partial_cmp(other),
1440 (&Lvmax(ref one), &Lvmax(ref other)) => one.partial_cmp(other),
1441 (&Dvmax(ref one), &Dvmax(ref other)) => one.partial_cmp(other),
1442 (&Vb(ref one), &Vb(ref other)) => one.partial_cmp(other),
1443 (&Svb(ref one), &Svb(ref other)) => one.partial_cmp(other),
1444 (&Lvb(ref one), &Lvb(ref other)) => one.partial_cmp(other),
1445 (&Dvb(ref one), &Dvb(ref other)) => one.partial_cmp(other),
1446 (&Vi(ref one), &Vi(ref other)) => one.partial_cmp(other),
1447 (&Svi(ref one), &Svi(ref other)) => one.partial_cmp(other),
1448 (&Lvi(ref one), &Lvi(ref other)) => one.partial_cmp(other),
1449 (&Dvi(ref one), &Dvi(ref other)) => one.partial_cmp(other),
1450 _ => unsafe {
1453 match *self {
1454 Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) | Dvh(..)
1455 | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) | Svmax(..)
1456 | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) | Vi(..)
1457 | Svi(..) | Lvi(..) | Dvi(..) => {},
1458 }
1459 debug_unreachable!("Forgot an arm in partial_cmp?")
1460 },
1461 }
1462 }
1463}
1464
1465impl Length {
1466 #[inline]
1467 fn parse_internal<'i, 't>(
1468 context: &ParserContext,
1469 input: &mut Parser<'i, 't>,
1470 num_context: AllowedNumericType,
1471 allow_quirks: AllowQuirks,
1472 ) -> Result<Self, ParseError<'i>> {
1473 let location = input.current_source_location();
1474 let token = input.next()?;
1475 match *token {
1476 Token::Dimension {
1477 value, ref unit, ..
1478 } if num_context.is_ok(context.parsing_mode, value) => {
1479 NoCalcLength::parse_dimension(context, value, unit)
1480 .map(Length::NoCalc)
1481 .map_err(|()| location.new_unexpected_token_error(token.clone()))
1482 },
1483 Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
1484 if value != 0.
1485 && !context.parsing_mode.allows_unitless_lengths()
1486 && !allow_quirks.allowed(context.quirks_mode)
1487 {
1488 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
1489 }
1490 Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(
1491 value,
1492 ))))
1493 },
1494 Token::Function(ref name) => {
1495 let function = CalcNode::math_function(context, name, location)?;
1496 let calc = CalcNode::parse_length(context, input, num_context, function)?;
1497 Ok(Length::Calc(Box::new(calc)))
1498 },
1499 ref token => return Err(location.new_unexpected_token_error(token.clone())),
1500 }
1501 }
1502
1503 #[inline]
1505 pub fn parse_non_negative<'i, 't>(
1506 context: &ParserContext,
1507 input: &mut Parser<'i, 't>,
1508 ) -> Result<Self, ParseError<'i>> {
1509 Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
1510 }
1511
1512 #[inline]
1514 pub fn parse_non_negative_quirky<'i, 't>(
1515 context: &ParserContext,
1516 input: &mut Parser<'i, 't>,
1517 allow_quirks: AllowQuirks,
1518 ) -> Result<Self, ParseError<'i>> {
1519 Self::parse_internal(
1520 context,
1521 input,
1522 AllowedNumericType::NonNegative,
1523 allow_quirks,
1524 )
1525 }
1526
1527 #[inline]
1529 pub fn from_px(px_value: CSSFloat) -> Length {
1530 Length::NoCalc(NoCalcLength::from_px(px_value))
1531 }
1532
1533 pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
1535 match *self {
1536 Self::NoCalc(ref l) => l.to_computed_pixel_length_without_context(),
1537 Self::Calc(ref l) => l.to_computed_pixel_length_without_context(),
1538 }
1539 }
1540
1541 #[cfg(feature = "gecko")]
1543 pub fn to_computed_pixel_length_with_font_metrics(
1544 &self,
1545 get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
1546 ) -> Result<CSSFloat, ()> {
1547 match *self {
1548 Self::NoCalc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
1549 Self::Calc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
1550 }
1551 }
1552}
1553
1554impl Parse for Length {
1555 fn parse<'i, 't>(
1556 context: &ParserContext,
1557 input: &mut Parser<'i, 't>,
1558 ) -> Result<Self, ParseError<'i>> {
1559 Self::parse_quirky(context, input, AllowQuirks::No)
1560 }
1561}
1562
1563impl Zero for Length {
1564 fn zero() -> Self {
1565 Length::NoCalc(NoCalcLength::zero())
1566 }
1567
1568 fn is_zero(&self) -> bool {
1569 match *self {
1572 Length::NoCalc(ref l) => l.is_zero(),
1573 Length::Calc(..) => false,
1574 }
1575 }
1576}
1577
1578impl Length {
1579 pub fn parse_quirky<'i, 't>(
1581 context: &ParserContext,
1582 input: &mut Parser<'i, 't>,
1583 allow_quirks: AllowQuirks,
1584 ) -> Result<Self, ParseError<'i>> {
1585 Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
1586 }
1587}
1588
1589pub type NonNegativeLength = NonNegative<Length>;
1591
1592impl Parse for NonNegativeLength {
1593 #[inline]
1594 fn parse<'i, 't>(
1595 context: &ParserContext,
1596 input: &mut Parser<'i, 't>,
1597 ) -> Result<Self, ParseError<'i>> {
1598 Ok(NonNegative(Length::parse_non_negative(context, input)?))
1599 }
1600}
1601
1602impl From<NoCalcLength> for NonNegativeLength {
1603 #[inline]
1604 fn from(len: NoCalcLength) -> Self {
1605 NonNegative(Length::NoCalc(len))
1606 }
1607}
1608
1609impl From<Length> for NonNegativeLength {
1610 #[inline]
1611 fn from(len: Length) -> Self {
1612 NonNegative(len)
1613 }
1614}
1615
1616impl NonNegativeLength {
1617 #[inline]
1619 pub fn from_px(px_value: CSSFloat) -> Self {
1620 Length::from_px(px_value.max(0.)).into()
1621 }
1622
1623 #[inline]
1625 pub fn parse_quirky<'i, 't>(
1626 context: &ParserContext,
1627 input: &mut Parser<'i, 't>,
1628 allow_quirks: AllowQuirks,
1629 ) -> Result<Self, ParseError<'i>> {
1630 Ok(NonNegative(Length::parse_non_negative_quirky(
1631 context,
1632 input,
1633 allow_quirks,
1634 )?))
1635 }
1636}
1637
1638#[allow(missing_docs)]
1643#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
1644pub enum LengthPercentage {
1645 Length(NoCalcLength),
1646 Percentage(computed::Percentage),
1647 Calc(Box<CalcLengthPercentage>),
1648}
1649
1650impl From<Length> for LengthPercentage {
1651 fn from(len: Length) -> LengthPercentage {
1652 match len {
1653 Length::NoCalc(l) => LengthPercentage::Length(l),
1654 Length::Calc(l) => LengthPercentage::Calc(l),
1655 }
1656 }
1657}
1658
1659impl From<NoCalcLength> for LengthPercentage {
1660 #[inline]
1661 fn from(len: NoCalcLength) -> Self {
1662 LengthPercentage::Length(len)
1663 }
1664}
1665
1666impl From<Percentage> for LengthPercentage {
1667 #[inline]
1668 fn from(pc: Percentage) -> Self {
1669 if let Some(clamping_mode) = pc.calc_clamping_mode() {
1670 LengthPercentage::Calc(Box::new(CalcLengthPercentage {
1671 clamping_mode,
1672 node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())),
1673 }))
1674 } else {
1675 LengthPercentage::Percentage(computed::Percentage(pc.get()))
1676 }
1677 }
1678}
1679
1680impl From<computed::Percentage> for LengthPercentage {
1681 #[inline]
1682 fn from(pc: computed::Percentage) -> Self {
1683 LengthPercentage::Percentage(pc)
1684 }
1685}
1686
1687impl Parse for LengthPercentage {
1688 #[inline]
1689 fn parse<'i, 't>(
1690 context: &ParserContext,
1691 input: &mut Parser<'i, 't>,
1692 ) -> Result<Self, ParseError<'i>> {
1693 Self::parse_quirky(context, input, AllowQuirks::No)
1694 }
1695}
1696
1697impl LengthPercentage {
1698 #[inline]
1699 pub fn zero_percent() -> LengthPercentage {
1701 LengthPercentage::Percentage(computed::Percentage::zero())
1702 }
1703
1704 #[inline]
1705 pub fn hundred_percent() -> LengthPercentage {
1707 LengthPercentage::Percentage(computed::Percentage::hundred())
1708 }
1709
1710 fn parse_internal<'i, 't>(
1711 context: &ParserContext,
1712 input: &mut Parser<'i, 't>,
1713 num_context: AllowedNumericType,
1714 allow_quirks: AllowQuirks,
1715 allow_anchor: AllowAnchorPositioningFunctions,
1716 ) -> Result<Self, ParseError<'i>> {
1717 let location = input.current_source_location();
1718 let token = input.next()?;
1719 match *token {
1720 Token::Dimension {
1721 value, ref unit, ..
1722 } if num_context.is_ok(context.parsing_mode, value) => {
1723 return NoCalcLength::parse_dimension(context, value, unit)
1724 .map(LengthPercentage::Length)
1725 .map_err(|()| location.new_unexpected_token_error(token.clone()));
1726 },
1727 Token::Percentage { unit_value, .. }
1728 if num_context.is_ok(context.parsing_mode, unit_value) =>
1729 {
1730 return Ok(LengthPercentage::Percentage(computed::Percentage(
1731 unit_value,
1732 )));
1733 },
1734 Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
1735 if value != 0.
1736 && !context.parsing_mode.allows_unitless_lengths()
1737 && !allow_quirks.allowed(context.quirks_mode)
1738 {
1739 return Err(location.new_unexpected_token_error(token.clone()));
1740 } else {
1741 return Ok(LengthPercentage::Length(NoCalcLength::from_px(value)));
1742 }
1743 },
1744 Token::Function(ref name) => {
1745 let function = CalcNode::math_function(context, name, location)?;
1746 let calc = CalcNode::parse_length_or_percentage(
1747 context,
1748 input,
1749 num_context,
1750 function,
1751 allow_anchor,
1752 )?;
1753 Ok(LengthPercentage::Calc(Box::new(calc)))
1754 },
1755 _ => return Err(location.new_unexpected_token_error(token.clone())),
1756 }
1757 }
1758
1759 #[inline]
1762 pub fn parse_quirky<'i, 't>(
1763 context: &ParserContext,
1764 input: &mut Parser<'i, 't>,
1765 allow_quirks: AllowQuirks,
1766 ) -> Result<Self, ParseError<'i>> {
1767 Self::parse_internal(
1768 context,
1769 input,
1770 AllowedNumericType::All,
1771 allow_quirks,
1772 AllowAnchorPositioningFunctions::No,
1773 )
1774 }
1775
1776 #[inline]
1779 fn parse_quirky_with_anchor_size_function<'i, 't>(
1780 context: &ParserContext,
1781 input: &mut Parser<'i, 't>,
1782 allow_quirks: AllowQuirks,
1783 ) -> Result<Self, ParseError<'i>> {
1784 Self::parse_internal(
1785 context,
1786 input,
1787 AllowedNumericType::All,
1788 allow_quirks,
1789 AllowAnchorPositioningFunctions::AllowAnchorSize,
1790 )
1791 }
1792
1793 #[inline]
1796 pub fn parse_quirky_with_anchor_functions<'i, 't>(
1797 context: &ParserContext,
1798 input: &mut Parser<'i, 't>,
1799 allow_quirks: AllowQuirks,
1800 ) -> Result<Self, ParseError<'i>> {
1801 Self::parse_internal(
1802 context,
1803 input,
1804 AllowedNumericType::All,
1805 allow_quirks,
1806 AllowAnchorPositioningFunctions::AllowAnchorAndAnchorSize,
1807 )
1808 }
1809
1810 pub fn parse_non_negative_with_anchor_size<'i, 't>(
1813 context: &ParserContext,
1814 input: &mut Parser<'i, 't>,
1815 allow_quirks: AllowQuirks,
1816 ) -> Result<Self, ParseError<'i>> {
1817 Self::parse_internal(
1818 context,
1819 input,
1820 AllowedNumericType::NonNegative,
1821 allow_quirks,
1822 AllowAnchorPositioningFunctions::AllowAnchorSize,
1823 )
1824 }
1825
1826 #[inline]
1831 pub fn parse_non_negative<'i, 't>(
1832 context: &ParserContext,
1833 input: &mut Parser<'i, 't>,
1834 ) -> Result<Self, ParseError<'i>> {
1835 Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
1836 }
1837
1838 #[inline]
1840 pub fn parse_non_negative_quirky<'i, 't>(
1841 context: &ParserContext,
1842 input: &mut Parser<'i, 't>,
1843 allow_quirks: AllowQuirks,
1844 ) -> Result<Self, ParseError<'i>> {
1845 Self::parse_internal(
1846 context,
1847 input,
1848 AllowedNumericType::NonNegative,
1849 allow_quirks,
1850 AllowAnchorPositioningFunctions::No,
1851 )
1852 }
1853
1854 fn to_calc_node(self) -> CalcNode {
1858 match self {
1859 LengthPercentage::Length(l) => CalcNode::Leaf(calc::Leaf::Length(l)),
1860 LengthPercentage::Percentage(p) => CalcNode::Leaf(calc::Leaf::Percentage(p.0)),
1861 LengthPercentage::Calc(p) => p.node,
1862 }
1863 }
1864
1865 pub fn hundred_percent_minus(self, clamping_mode: AllowedNumericType) -> Self {
1867 let mut sum = smallvec::SmallVec::<[CalcNode; 2]>::new();
1868 sum.push(CalcNode::Leaf(calc::Leaf::Percentage(1.0)));
1869
1870 let mut node = self.to_calc_node();
1871 node.negate();
1872 sum.push(node);
1873
1874 let calc = CalcNode::Sum(sum.into_boxed_slice().into());
1875 LengthPercentage::Calc(Box::new(
1876 calc.into_length_or_percentage(clamping_mode).unwrap(),
1877 ))
1878 }
1879}
1880
1881impl Zero for LengthPercentage {
1882 fn zero() -> Self {
1883 LengthPercentage::Length(NoCalcLength::zero())
1884 }
1885
1886 fn is_zero(&self) -> bool {
1887 match *self {
1888 LengthPercentage::Length(l) => l.is_zero(),
1889 LengthPercentage::Percentage(p) => p.0 == 0.0,
1890 LengthPercentage::Calc(_) => false,
1891 }
1892 }
1893}
1894
1895impl ZeroNoPercent for LengthPercentage {
1896 fn is_zero_no_percent(&self) -> bool {
1897 match *self {
1898 LengthPercentage::Percentage(_) => false,
1899 _ => self.is_zero(),
1900 }
1901 }
1902}
1903
1904pub type LengthPercentageOrAuto = generics::LengthPercentageOrAuto<LengthPercentage>;
1906
1907impl LengthPercentageOrAuto {
1908 #[inline]
1910 pub fn zero_percent() -> Self {
1911 generics::LengthPercentageOrAuto::LengthPercentage(LengthPercentage::zero_percent())
1912 }
1913
1914 #[inline]
1917 pub fn parse_quirky<'i, 't>(
1918 context: &ParserContext,
1919 input: &mut Parser<'i, 't>,
1920 allow_quirks: AllowQuirks,
1921 ) -> Result<Self, ParseError<'i>> {
1922 Self::parse_with(context, input, |context, input| {
1923 LengthPercentage::parse_quirky(context, input, allow_quirks)
1924 })
1925 }
1926}
1927
1928pub type NonNegativeLengthPercentageOrAuto =
1930 generics::LengthPercentageOrAuto<NonNegativeLengthPercentage>;
1931
1932impl NonNegativeLengthPercentageOrAuto {
1933 #[inline]
1935 pub fn zero_percent() -> Self {
1936 generics::LengthPercentageOrAuto::LengthPercentage(
1937 NonNegativeLengthPercentage::zero_percent(),
1938 )
1939 }
1940
1941 #[inline]
1944 pub fn parse_quirky<'i, 't>(
1945 context: &ParserContext,
1946 input: &mut Parser<'i, 't>,
1947 allow_quirks: AllowQuirks,
1948 ) -> Result<Self, ParseError<'i>> {
1949 Self::parse_with(context, input, |context, input| {
1950 NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)
1951 })
1952 }
1953}
1954
1955pub type NonNegativeLengthPercentage = NonNegative<LengthPercentage>;
1957
1958pub type NonNegativeLengthPercentageOrNormal =
1960 GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
1961
1962impl From<NoCalcLength> for NonNegativeLengthPercentage {
1963 #[inline]
1964 fn from(len: NoCalcLength) -> Self {
1965 NonNegative(LengthPercentage::from(len))
1966 }
1967}
1968
1969impl Parse for NonNegativeLengthPercentage {
1970 #[inline]
1971 fn parse<'i, 't>(
1972 context: &ParserContext,
1973 input: &mut Parser<'i, 't>,
1974 ) -> Result<Self, ParseError<'i>> {
1975 Self::parse_quirky(context, input, AllowQuirks::No)
1976 }
1977}
1978
1979impl NonNegativeLengthPercentage {
1980 #[inline]
1981 pub fn zero_percent() -> Self {
1983 NonNegative(LengthPercentage::zero_percent())
1984 }
1985
1986 #[inline]
1989 pub fn parse_quirky<'i, 't>(
1990 context: &ParserContext,
1991 input: &mut Parser<'i, 't>,
1992 allow_quirks: AllowQuirks,
1993 ) -> Result<Self, ParseError<'i>> {
1994 LengthPercentage::parse_non_negative_quirky(context, input, allow_quirks).map(NonNegative)
1995 }
1996
1997 #[inline]
2000 pub fn parse_non_negative_with_anchor_size<'i, 't>(
2001 context: &ParserContext,
2002 input: &mut Parser<'i, 't>,
2003 allow_quirks: AllowQuirks,
2004 ) -> Result<Self, ParseError<'i>> {
2005 LengthPercentage::parse_non_negative_with_anchor_size(context, input, allow_quirks)
2006 .map(NonNegative)
2007 }
2008}
2009
2010pub type LengthOrAuto = generics::LengthPercentageOrAuto<Length>;
2016
2017impl LengthOrAuto {
2018 #[inline]
2021 pub fn parse_quirky<'i, 't>(
2022 context: &ParserContext,
2023 input: &mut Parser<'i, 't>,
2024 allow_quirks: AllowQuirks,
2025 ) -> Result<Self, ParseError<'i>> {
2026 Self::parse_with(context, input, |context, input| {
2027 Length::parse_quirky(context, input, allow_quirks)
2028 })
2029 }
2030}
2031
2032pub type NonNegativeLengthOrAuto = generics::LengthPercentageOrAuto<NonNegativeLength>;
2034
2035pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
2037
2038pub type Size = GenericSize<NonNegativeLengthPercentage>;
2040
2041impl Parse for Size {
2042 fn parse<'i, 't>(
2043 context: &ParserContext,
2044 input: &mut Parser<'i, 't>,
2045 ) -> Result<Self, ParseError<'i>> {
2046 Size::parse_quirky(context, input, AllowQuirks::No)
2047 }
2048}
2049
2050macro_rules! parse_size_non_length {
2051 ($size:ident, $input:expr, $auto_or_none:expr => $auto_or_none_ident:ident) => {{
2052 let size = $input.try_parse(|input| {
2053 Ok(try_match_ident_ignore_ascii_case! { input,
2054 "min-content" | "-moz-min-content" => $size::MinContent,
2055 "max-content" | "-moz-max-content" => $size::MaxContent,
2056 "fit-content" | "-moz-fit-content" => $size::FitContent,
2057 #[cfg(feature = "gecko")]
2058 "-moz-available" => $size::MozAvailable,
2059 #[cfg(feature = "gecko")]
2060 "-webkit-fill-available" if is_webkit_fill_available_keyword_enabled() => $size::WebkitFillAvailable,
2061 "stretch" if is_stretch_enabled() => $size::Stretch,
2062 $auto_or_none => $size::$auto_or_none_ident,
2063 })
2064 });
2065 if size.is_ok() {
2066 return size;
2067 }
2068 }};
2069}
2070
2071#[cfg(feature = "gecko")]
2072fn is_webkit_fill_available_keyword_enabled() -> bool {
2073 static_prefs::pref!("layout.css.webkit-fill-available.enabled")
2074}
2075fn is_stretch_enabled() -> bool {
2076 static_prefs::pref!("layout.css.stretch-size-keyword.enabled")
2077}
2078
2079fn is_fit_content_function_enabled() -> bool {
2080 static_prefs::pref!("layout.css.fit-content-function.enabled")
2081}
2082
2083macro_rules! parse_fit_content_function {
2084 ($size:ident, $input:expr, $context:expr, $allow_quirks:expr) => {
2085 if is_fit_content_function_enabled() {
2086 if let Ok(length) = $input.try_parse(|input| {
2087 input.expect_function_matching("fit-content")?;
2088 input.parse_nested_block(|i| {
2089 NonNegativeLengthPercentage::parse_quirky($context, i, $allow_quirks)
2090 })
2091 }) {
2092 return Ok($size::FitContentFunction(length));
2093 }
2094 }
2095 };
2096}
2097
2098impl Size {
2099 pub fn parse_quirky<'i, 't>(
2101 context: &ParserContext,
2102 input: &mut Parser<'i, 't>,
2103 allow_quirks: AllowQuirks,
2104 ) -> Result<Self, ParseError<'i>> {
2105 parse_size_non_length!(Size, input, "auto" => Auto);
2106 parse_fit_content_function!(Size, input, context, allow_quirks);
2107
2108 match input
2109 .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
2110 {
2111 Ok(length) => return Ok(GenericSize::LengthPercentage(length)),
2112 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2113 return Err(e.into())
2114 },
2115 Err(_) => (),
2116 };
2117 if let Ok(length) = input.try_parse(|i| {
2118 NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
2119 context,
2120 i,
2121 allow_quirks,
2122 )
2123 }) {
2124 return Ok(GenericSize::AnchorContainingCalcFunction(length));
2125 }
2126 Ok(Self::AnchorSizeFunction(Box::new(
2127 GenericAnchorSizeFunction::parse(context, input)?,
2128 )))
2129 }
2130
2131 #[inline]
2133 pub fn zero_percent() -> Self {
2134 GenericSize::LengthPercentage(NonNegativeLengthPercentage::zero_percent())
2135 }
2136}
2137
2138pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
2140
2141impl Parse for MaxSize {
2142 fn parse<'i, 't>(
2143 context: &ParserContext,
2144 input: &mut Parser<'i, 't>,
2145 ) -> Result<Self, ParseError<'i>> {
2146 MaxSize::parse_quirky(context, input, AllowQuirks::No)
2147 }
2148}
2149
2150impl MaxSize {
2151 pub fn parse_quirky<'i, 't>(
2153 context: &ParserContext,
2154 input: &mut Parser<'i, 't>,
2155 allow_quirks: AllowQuirks,
2156 ) -> Result<Self, ParseError<'i>> {
2157 parse_size_non_length!(MaxSize, input, "none" => None);
2158 parse_fit_content_function!(MaxSize, input, context, allow_quirks);
2159
2160 match input
2161 .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
2162 {
2163 Ok(length) => return Ok(GenericMaxSize::LengthPercentage(length)),
2164 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2165 return Err(e.into())
2166 },
2167 Err(_) => (),
2168 };
2169 if let Ok(length) = input.try_parse(|i| {
2170 NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
2171 context,
2172 i,
2173 allow_quirks,
2174 )
2175 }) {
2176 return Ok(GenericMaxSize::AnchorContainingCalcFunction(length));
2177 }
2178 Ok(Self::AnchorSizeFunction(Box::new(
2179 GenericAnchorSizeFunction::parse(context, input)?,
2180 )))
2181 }
2182}
2183
2184pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
2186
2187pub type Margin = GenericMargin<LengthPercentage>;
2189
2190impl Margin {
2191 #[inline]
2194 pub fn parse_quirky<'i, 't>(
2195 context: &ParserContext,
2196 input: &mut Parser<'i, 't>,
2197 allow_quirks: AllowQuirks,
2198 ) -> Result<Self, ParseError<'i>> {
2199 if let Ok(l) = input.try_parse(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
2200 {
2201 return Ok(Self::LengthPercentage(l));
2202 }
2203 match input.try_parse(|i| i.expect_ident_matching("auto")) {
2204 Ok(_) => return Ok(Self::Auto),
2205 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2206 return Err(e.into())
2207 },
2208 Err(_) => (),
2209 };
2210 if let Ok(l) = input.try_parse(|i| {
2211 LengthPercentage::parse_quirky_with_anchor_size_function(context, i, allow_quirks)
2212 }) {
2213 return Ok(Self::AnchorContainingCalcFunction(l));
2214 }
2215 let inner = GenericAnchorSizeFunction::<Margin>::parse(context, input)?;
2216 Ok(Self::AnchorSizeFunction(Box::new(inner)))
2217 }
2218}
2219
2220impl Parse for Margin {
2221 fn parse<'i, 't>(
2222 context: &ParserContext,
2223 input: &mut Parser<'i, 't>,
2224 ) -> Result<Self, ParseError<'i>> {
2225 Self::parse_quirky(context, input, AllowQuirks::No)
2226 }
2227}