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(
256 base_size,
257 orientation,
258 flags,
259 )
260 }
261
262 let reference_font_size = base_size.resolve(context);
263 match *self {
264 Self::Em(length) => {
265 if context.for_non_inherited_property && base_size == FontBaseSize::CurrentStyle {
266 context
267 .rule_cache_conditions
268 .borrow_mut()
269 .set_font_size_dependency(reference_font_size.computed_size);
270 }
271
272 (reference_font_size.computed_size(), length)
273 },
274 Self::Ex(length) => {
275 let metrics = query_font_metrics(
277 context,
278 base_size,
279 FontMetricsOrientation::Horizontal,
280 QueryFontMetricsFlags::empty(),
281 );
282 let reference_size = metrics.x_height.unwrap_or_else(|| {
283 reference_font_size.used_size() * 0.5
292 });
293 (reference_size, length)
294 },
295 Self::Ch(length) => {
296 let metrics = query_font_metrics(
304 context,
305 base_size,
306 FontMetricsOrientation::MatchContextPreferHorizontal,
307 QueryFontMetricsFlags::NEEDS_CH,
308 );
309 let reference_size = metrics.zero_advance_measure.unwrap_or_else(|| {
310 let wm = context.style().writing_mode;
323 if wm.is_vertical() && wm.is_upright() {
324 reference_font_size.used_size()
325 } else {
326 reference_font_size.used_size() * 0.5
327 }
328 });
329 (reference_size, length)
330 },
331 Self::Cap(length) => {
332 let metrics = query_font_metrics(
333 context,
334 base_size,
335 FontMetricsOrientation::Horizontal,
336 QueryFontMetricsFlags::empty(),
337 );
338 let reference_size = metrics.cap_height.unwrap_or_else(|| {
339 metrics.ascent
346 });
347 (reference_size, length)
348 },
349 Self::Ic(length) => {
350 let metrics = query_font_metrics(
351 context,
352 base_size,
353 FontMetricsOrientation::MatchContextPreferVertical,
354 QueryFontMetricsFlags::NEEDS_IC,
355 );
356 let reference_size = metrics.ic_width.unwrap_or_else(|| {
357 reference_font_size.used_size()
366 });
367 (reference_size, length)
368 },
369 Self::Rem(length) => {
370 let reference_size = if context.builder.is_root_element || context.in_media_query {
377 reference_font_size.computed_size()
378 } else {
379 context
380 .device()
381 .root_font_size()
382 .zoom(context.builder.effective_zoom)
383 };
384 (reference_size, length)
385 },
386 Self::Lh(length) => {
387 let reference_size = if context.in_media_query {
393 context
394 .device()
395 .calc_line_height(
396 &context.default_style().get_font(),
397 context.style().writing_mode,
398 None,
399 )
400 .0
401 } else {
402 let line_height = context.builder.calc_line_height(
403 context.device(),
404 line_height_base,
405 context.style().writing_mode,
406 );
407 if context.for_non_inherited_property &&
408 line_height_base == LineHeightBase::CurrentStyle
409 {
410 context
411 .rule_cache_conditions
412 .borrow_mut()
413 .set_line_height_dependency(line_height)
414 }
415 line_height.0
416 };
417 (reference_size, length)
418 },
419 Self::Rlh(length) => {
420 let reference_size = if context.builder.is_root_element {
426 context.builder
427 .calc_line_height(
428 context.device(),
429 line_height_base,
430 context.style().writing_mode,
431 )
432 .0
433 } else if context.in_media_query {
434 context
435 .device()
436 .calc_line_height(
437 &context.default_style().get_font(),
438 context.style().writing_mode,
439 None,
440 )
441 .0
442 } else {
443 context.device().root_line_height()
444 };
445 let reference_size = reference_size.zoom(context.builder.effective_zoom);
446 (reference_size, length)
447 },
448 }
449 }
450}
451
452pub enum ViewportVariant {
454 UADefault,
456 Small,
458 Large,
460 Dynamic,
462}
463
464#[derive(PartialEq)]
466enum ViewportUnit {
467 Vw,
469 Vh,
471 Vmin,
473 Vmax,
475 Vb,
477 Vi,
479}
480
481#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
485#[repr(u8)]
486pub enum ViewportPercentageLength {
487 #[css(dimension)]
489 Vw(CSSFloat),
490 #[css(dimension)]
492 Svw(CSSFloat),
493 #[css(dimension)]
495 Lvw(CSSFloat),
496 #[css(dimension)]
498 Dvw(CSSFloat),
499 #[css(dimension)]
501 Vh(CSSFloat),
502 #[css(dimension)]
504 Svh(CSSFloat),
505 #[css(dimension)]
507 Lvh(CSSFloat),
508 #[css(dimension)]
510 Dvh(CSSFloat),
511 #[css(dimension)]
513 Vmin(CSSFloat),
514 #[css(dimension)]
516 Svmin(CSSFloat),
517 #[css(dimension)]
519 Lvmin(CSSFloat),
520 #[css(dimension)]
522 Dvmin(CSSFloat),
523 #[css(dimension)]
525 Vmax(CSSFloat),
526 #[css(dimension)]
528 Svmax(CSSFloat),
529 #[css(dimension)]
531 Lvmax(CSSFloat),
532 #[css(dimension)]
534 Dvmax(CSSFloat),
535 #[css(dimension)]
537 Vb(CSSFloat),
538 #[css(dimension)]
540 Svb(CSSFloat),
541 #[css(dimension)]
543 Lvb(CSSFloat),
544 #[css(dimension)]
546 Dvb(CSSFloat),
547 #[css(dimension)]
549 Vi(CSSFloat),
550 #[css(dimension)]
552 Svi(CSSFloat),
553 #[css(dimension)]
555 Lvi(CSSFloat),
556 #[css(dimension)]
558 Dvi(CSSFloat),
559}
560
561impl ViewportPercentageLength {
562 fn unitless_value(&self) -> CSSFloat {
564 self.unpack().2
565 }
566
567 fn unit(&self) -> &'static str {
569 match *self {
570 Self::Vw(_) => "vw",
571 Self::Lvw(_) => "lvw",
572 Self::Svw(_) => "svw",
573 Self::Dvw(_) => "dvw",
574 Self::Vh(_) => "vh",
575 Self::Svh(_) => "svh",
576 Self::Lvh(_) => "lvh",
577 Self::Dvh(_) => "dvh",
578 Self::Vmin(_) => "vmin",
579 Self::Svmin(_) => "svmin",
580 Self::Lvmin(_) => "lvmin",
581 Self::Dvmin(_) => "dvmin",
582 Self::Vmax(_) => "vmax",
583 Self::Svmax(_) => "svmax",
584 Self::Lvmax(_) => "lvmax",
585 Self::Dvmax(_) => "dvmax",
586 Self::Vb(_) => "vb",
587 Self::Svb(_) => "svb",
588 Self::Lvb(_) => "lvb",
589 Self::Dvb(_) => "dvb",
590 Self::Vi(_) => "vi",
591 Self::Svi(_) => "svi",
592 Self::Lvi(_) => "lvi",
593 Self::Dvi(_) => "dvi",
594 }
595 }
596
597 fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) {
598 match *self {
599 Self::Vw(v) => (ViewportVariant::UADefault, ViewportUnit::Vw, v),
600 Self::Svw(v) => (ViewportVariant::Small, ViewportUnit::Vw, v),
601 Self::Lvw(v) => (ViewportVariant::Large, ViewportUnit::Vw, v),
602 Self::Dvw(v) => (ViewportVariant::Dynamic, ViewportUnit::Vw, v),
603 Self::Vh(v) => (ViewportVariant::UADefault, ViewportUnit::Vh, v),
604 Self::Svh(v) => (ViewportVariant::Small, ViewportUnit::Vh, v),
605 Self::Lvh(v) => (ViewportVariant::Large, ViewportUnit::Vh, v),
606 Self::Dvh(v) => (ViewportVariant::Dynamic, ViewportUnit::Vh, v),
607 Self::Vmin(v) => (ViewportVariant::UADefault, ViewportUnit::Vmin, v),
608 Self::Svmin(v) => (ViewportVariant::Small, ViewportUnit::Vmin, v),
609 Self::Lvmin(v) => (ViewportVariant::Large, ViewportUnit::Vmin, v),
610 Self::Dvmin(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmin, v),
611 Self::Vmax(v) => (ViewportVariant::UADefault, ViewportUnit::Vmax, v),
612 Self::Svmax(v) => (ViewportVariant::Small, ViewportUnit::Vmax, v),
613 Self::Lvmax(v) => (ViewportVariant::Large, ViewportUnit::Vmax, v),
614 Self::Dvmax(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmax, v),
615 Self::Vb(v) => (ViewportVariant::UADefault, ViewportUnit::Vb, v),
616 Self::Svb(v) => (ViewportVariant::Small, ViewportUnit::Vb, v),
617 Self::Lvb(v) => (ViewportVariant::Large, ViewportUnit::Vb, v),
618 Self::Dvb(v) => (ViewportVariant::Dynamic, ViewportUnit::Vb, v),
619 Self::Vi(v) => (ViewportVariant::UADefault, ViewportUnit::Vi, v),
620 Self::Svi(v) => (ViewportVariant::Small, ViewportUnit::Vi, v),
621 Self::Lvi(v) => (ViewportVariant::Large, ViewportUnit::Vi, v),
622 Self::Dvi(v) => (ViewportVariant::Dynamic, ViewportUnit::Vi, v),
623 }
624 }
625
626 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
627 where
628 O: Fn(f32, f32) -> f32,
629 {
630 use self::ViewportPercentageLength::*;
631
632 if std::mem::discriminant(self) != std::mem::discriminant(other) {
633 return Err(());
634 }
635
636 Ok(match (self, other) {
637 (&Vw(one), &Vw(other)) => Vw(op(one, other)),
638 (&Svw(one), &Svw(other)) => Svw(op(one, other)),
639 (&Lvw(one), &Lvw(other)) => Lvw(op(one, other)),
640 (&Dvw(one), &Dvw(other)) => Dvw(op(one, other)),
641 (&Vh(one), &Vh(other)) => Vh(op(one, other)),
642 (&Svh(one), &Svh(other)) => Svh(op(one, other)),
643 (&Lvh(one), &Lvh(other)) => Lvh(op(one, other)),
644 (&Dvh(one), &Dvh(other)) => Dvh(op(one, other)),
645 (&Vmin(one), &Vmin(other)) => Vmin(op(one, other)),
646 (&Svmin(one), &Svmin(other)) => Svmin(op(one, other)),
647 (&Lvmin(one), &Lvmin(other)) => Lvmin(op(one, other)),
648 (&Dvmin(one), &Dvmin(other)) => Dvmin(op(one, other)),
649 (&Vmax(one), &Vmax(other)) => Vmax(op(one, other)),
650 (&Svmax(one), &Svmax(other)) => Svmax(op(one, other)),
651 (&Lvmax(one), &Lvmax(other)) => Lvmax(op(one, other)),
652 (&Dvmax(one), &Dvmax(other)) => Dvmax(op(one, other)),
653 (&Vb(one), &Vb(other)) => Vb(op(one, other)),
654 (&Svb(one), &Svb(other)) => Svb(op(one, other)),
655 (&Lvb(one), &Lvb(other)) => Lvb(op(one, other)),
656 (&Dvb(one), &Dvb(other)) => Dvb(op(one, other)),
657 (&Vi(one), &Vi(other)) => Vi(op(one, other)),
658 (&Svi(one), &Svi(other)) => Svi(op(one, other)),
659 (&Lvi(one), &Lvi(other)) => Lvi(op(one, other)),
660 (&Dvi(one), &Dvi(other)) => Dvi(op(one, other)),
661 _ => unsafe {
664 match *self {
665 Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) |
666 Dvh(..) | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) |
667 Svmax(..) | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) |
668 Vi(..) | Svi(..) | Lvi(..) | Dvi(..) => {},
669 }
670 debug_unreachable!("Forgot to handle unit in try_op()")
671 },
672 })
673 }
674
675 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
676 match self {
677 Self::Vw(x) => Self::Vw(op(*x)),
678 Self::Svw(x) => Self::Svw(op(*x)),
679 Self::Lvw(x) => Self::Lvw(op(*x)),
680 Self::Dvw(x) => Self::Dvw(op(*x)),
681 Self::Vh(x) => Self::Vh(op(*x)),
682 Self::Svh(x) => Self::Svh(op(*x)),
683 Self::Lvh(x) => Self::Lvh(op(*x)),
684 Self::Dvh(x) => Self::Dvh(op(*x)),
685 Self::Vmin(x) => Self::Vmin(op(*x)),
686 Self::Svmin(x) => Self::Svmin(op(*x)),
687 Self::Lvmin(x) => Self::Lvmin(op(*x)),
688 Self::Dvmin(x) => Self::Dvmin(op(*x)),
689 Self::Vmax(x) => Self::Vmax(op(*x)),
690 Self::Svmax(x) => Self::Svmax(op(*x)),
691 Self::Lvmax(x) => Self::Lvmax(op(*x)),
692 Self::Dvmax(x) => Self::Dvmax(op(*x)),
693 Self::Vb(x) => Self::Vb(op(*x)),
694 Self::Svb(x) => Self::Svb(op(*x)),
695 Self::Lvb(x) => Self::Lvb(op(*x)),
696 Self::Dvb(x) => Self::Dvb(op(*x)),
697 Self::Vi(x) => Self::Vi(op(*x)),
698 Self::Svi(x) => Self::Svi(op(*x)),
699 Self::Lvi(x) => Self::Lvi(op(*x)),
700 Self::Dvi(x) => Self::Dvi(op(*x)),
701 }
702 }
703
704 pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
706 let (variant, unit, factor) = self.unpack();
707 let size = context.viewport_size_for_viewport_unit_resolution(variant);
708 let length: app_units::Au = match unit {
709 ViewportUnit::Vw => size.width,
710 ViewportUnit::Vh => size.height,
711 ViewportUnit::Vmin => cmp::min(size.width, size.height),
712 ViewportUnit::Vmax => cmp::max(size.width, size.height),
713 ViewportUnit::Vi | ViewportUnit::Vb => {
714 context
715 .rule_cache_conditions
716 .borrow_mut()
717 .set_writing_mode_dependency(context.builder.writing_mode);
718 if (unit == ViewportUnit::Vb) == context.style().writing_mode.is_vertical() {
719 size.width
720 } else {
721 size.height
722 }
723 },
724 };
725
726 let length = context.builder.effective_zoom.zoom(length.0 as f32);
728
729 let trunc_scaled =
734 ((length as f64 * factor as f64 / 100.).trunc() / AU_PER_PX as f64) as f32;
735 CSSPixelLength::new(crate::values::normalize(trunc_scaled))
736 }
737}
738
739#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
741#[repr(C)]
742pub struct CharacterWidth(pub i32);
743
744impl CharacterWidth {
745 pub fn to_computed_value(&self, reference_font_size: computed::Length) -> computed::Length {
747 let average_advance = reference_font_size * 0.5;
752 let max_advance = reference_font_size;
753 (average_advance * (self.0 as CSSFloat - 1.0) + max_advance).finite()
754 }
755}
756
757#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
759#[repr(u8)]
760pub enum AbsoluteLength {
761 #[css(dimension)]
763 Px(CSSFloat),
764 #[css(dimension)]
766 In(CSSFloat),
767 #[css(dimension)]
769 Cm(CSSFloat),
770 #[css(dimension)]
772 Mm(CSSFloat),
773 #[css(dimension)]
775 Q(CSSFloat),
776 #[css(dimension)]
778 Pt(CSSFloat),
779 #[css(dimension)]
781 Pc(CSSFloat),
782}
783
784impl AbsoluteLength {
785 fn unitless_value(&self) -> CSSFloat {
787 match *self {
788 Self::Px(v) |
789 Self::In(v) |
790 Self::Cm(v) |
791 Self::Mm(v) |
792 Self::Q(v) |
793 Self::Pt(v) |
794 Self::Pc(v) => v,
795 }
796 }
797
798 fn unit(&self) -> &'static str {
800 match *self {
801 Self::Px(_) => "px",
802 Self::In(_) => "in",
803 Self::Cm(_) => "cm",
804 Self::Mm(_) => "mm",
805 Self::Q(_) => "q",
806 Self::Pt(_) => "pt",
807 Self::Pc(_) => "pc",
808 }
809 }
810
811 #[inline]
813 pub fn to_px(&self) -> CSSFloat {
814 match *self {
815 Self::Px(value) => value,
816 Self::In(value) => value * PX_PER_IN,
817 Self::Cm(value) => value * PX_PER_CM,
818 Self::Mm(value) => value * PX_PER_MM,
819 Self::Q(value) => value * PX_PER_Q,
820 Self::Pt(value) => value * PX_PER_PT,
821 Self::Pc(value) => value * PX_PER_PC,
822 }
823 }
824
825 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
826 where
827 O: Fn(f32, f32) -> f32,
828 {
829 Ok(Self::Px(op(self.to_px(), other.to_px())))
830 }
831
832 fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
833 Self::Px(op(self.to_px()))
834 }
835}
836
837impl ToComputedValue for AbsoluteLength {
838 type ComputedValue = CSSPixelLength;
839
840 fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
841 CSSPixelLength::new(self.to_px())
842 .zoom(context.builder.effective_zoom)
843 .finite()
844 }
845
846 fn from_computed_value(computed: &Self::ComputedValue) -> Self {
847 Self::Px(computed.px())
848 }
849}
850
851impl PartialOrd for AbsoluteLength {
852 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
853 self.to_px().partial_cmp(&other.to_px())
854 }
855}
856
857#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
861#[repr(u8)]
862pub enum ContainerRelativeLength {
863 #[css(dimension)]
865 Cqw(CSSFloat),
866 #[css(dimension)]
868 Cqh(CSSFloat),
869 #[css(dimension)]
871 Cqi(CSSFloat),
872 #[css(dimension)]
874 Cqb(CSSFloat),
875 #[css(dimension)]
877 Cqmin(CSSFloat),
878 #[css(dimension)]
880 Cqmax(CSSFloat),
881}
882
883impl ContainerRelativeLength {
884 fn unitless_value(&self) -> CSSFloat {
885 match *self {
886 Self::Cqw(v) |
887 Self::Cqh(v) |
888 Self::Cqi(v) |
889 Self::Cqb(v) |
890 Self::Cqmin(v) |
891 Self::Cqmax(v) => v,
892 }
893 }
894
895 fn unit(&self) -> &'static str {
897 match *self {
898 Self::Cqw(_) => "cqw",
899 Self::Cqh(_) => "cqh",
900 Self::Cqi(_) => "cqi",
901 Self::Cqb(_) => "cqb",
902 Self::Cqmin(_) => "cqmin",
903 Self::Cqmax(_) => "cqmax",
904 }
905 }
906
907 pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
908 where
909 O: Fn(f32, f32) -> f32,
910 {
911 use self::ContainerRelativeLength::*;
912
913 if std::mem::discriminant(self) != std::mem::discriminant(other) {
914 return Err(());
915 }
916
917 Ok(match (self, other) {
918 (&Cqw(one), &Cqw(other)) => Cqw(op(one, other)),
919 (&Cqh(one), &Cqh(other)) => Cqh(op(one, other)),
920 (&Cqi(one), &Cqi(other)) => Cqi(op(one, other)),
921 (&Cqb(one), &Cqb(other)) => Cqb(op(one, other)),
922 (&Cqmin(one), &Cqmin(other)) => Cqmin(op(one, other)),
923 (&Cqmax(one), &Cqmax(other)) => Cqmax(op(one, other)),
924
925 _ => unsafe {
929 match *self {
930 Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
931 }
932 debug_unreachable!("Forgot to handle unit in try_op()")
933 },
934 })
935 }
936
937 pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
938 match self {
939 Self::Cqw(x) => Self::Cqw(op(*x)),
940 Self::Cqh(x) => Self::Cqh(op(*x)),
941 Self::Cqi(x) => Self::Cqi(op(*x)),
942 Self::Cqb(x) => Self::Cqb(op(*x)),
943 Self::Cqmin(x) => Self::Cqmin(op(*x)),
944 Self::Cqmax(x) => Self::Cqmax(op(*x)),
945 }
946 }
947
948 pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
950 if context.for_non_inherited_property {
951 context.rule_cache_conditions.borrow_mut().set_uncacheable();
952 }
953 context
954 .builder
955 .add_flags(ComputedValueFlags::USES_CONTAINER_UNITS);
956
957 let size = context.get_container_size_query();
961 let (factor, container_length) = match *self {
962 Self::Cqw(v) => (v, size.get_container_width(context)),
963 Self::Cqh(v) => (v, size.get_container_height(context)),
964 Self::Cqi(v) => (v, size.get_container_inline_size(context)),
965 Self::Cqb(v) => (v, size.get_container_block_size(context)),
966 Self::Cqmin(v) => (
967 v,
968 cmp::min(
969 size.get_container_inline_size(context),
970 size.get_container_block_size(context),
971 ),
972 ),
973 Self::Cqmax(v) => (
974 v,
975 cmp::max(
976 size.get_container_inline_size(context),
977 size.get_container_block_size(context),
978 ),
979 ),
980 };
981 CSSPixelLength::new((container_length.to_f64_px() * factor as f64 / 100.0) as f32).finite()
982 }
983}
984
985#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
989#[repr(u8)]
990pub enum NoCalcLength {
991 Absolute(AbsoluteLength),
995
996 FontRelative(FontRelativeLength),
1000
1001 ViewportPercentage(ViewportPercentageLength),
1005
1006 ContainerRelative(ContainerRelativeLength),
1010 ServoCharacterWidth(CharacterWidth),
1015}
1016
1017impl NoCalcLength {
1018 pub fn unitless_value(&self) -> CSSFloat {
1020 match *self {
1021 Self::Absolute(v) => v.unitless_value(),
1022 Self::FontRelative(v) => v.unitless_value(),
1023 Self::ViewportPercentage(v) => v.unitless_value(),
1024 Self::ContainerRelative(v) => v.unitless_value(),
1025 Self::ServoCharacterWidth(c) => c.0 as f32,
1026 }
1027 }
1028
1029 fn unit(&self) -> &'static str {
1031 match *self {
1032 Self::Absolute(v) => v.unit(),
1033 Self::FontRelative(v) => v.unit(),
1034 Self::ViewportPercentage(v) => v.unit(),
1035 Self::ContainerRelative(v) => v.unit(),
1036 Self::ServoCharacterWidth(_) => "",
1037 }
1038 }
1039
1040 pub fn is_negative(&self) -> bool {
1042 self.unitless_value().is_sign_negative()
1043 }
1044
1045 pub fn is_zero(&self) -> bool {
1047 self.unitless_value() == 0.0
1048 }
1049
1050 pub fn is_infinite(&self) -> bool {
1052 self.unitless_value().is_infinite()
1053 }
1054
1055 pub fn is_nan(&self) -> bool {
1057 self.unitless_value().is_nan()
1058 }
1059
1060 pub fn should_zoom_text(&self) -> bool {
1065 match *self {
1066 Self::Absolute(..) | Self::ViewportPercentage(..) | Self::ContainerRelative(..) => true,
1067 Self::ServoCharacterWidth(..) | Self::FontRelative(..) => false,
1068 }
1069 }
1070
1071 pub fn parse_dimension(
1073 context: &ParserContext,
1074 value: CSSFloat,
1075 unit: &str,
1076 ) -> Result<Self, ()> {
1077 Ok(match_ignore_ascii_case! { unit,
1078 "px" => Self::Absolute(AbsoluteLength::Px(value)),
1079 "in" => Self::Absolute(AbsoluteLength::In(value)),
1080 "cm" => Self::Absolute(AbsoluteLength::Cm(value)),
1081 "mm" => Self::Absolute(AbsoluteLength::Mm(value)),
1082 "q" => Self::Absolute(AbsoluteLength::Q(value)),
1083 "pt" => Self::Absolute(AbsoluteLength::Pt(value)),
1084 "pc" => Self::Absolute(AbsoluteLength::Pc(value)),
1085 "em" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Em(value)),
1087 "ex" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ex(value)),
1088 "ch" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ch(value)),
1089 "cap" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Cap(value)),
1090 "ic" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ic(value)),
1091 "rem" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rem(value)),
1092 "lh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Lh(value)),
1093 "rlh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rlh(value)),
1094 "vw" if !context.in_page_rule() => {
1096 Self::ViewportPercentage(ViewportPercentageLength::Vw(value))
1097 },
1098 "svw" if !context.in_page_rule() => {
1099 Self::ViewportPercentage(ViewportPercentageLength::Svw(value))
1100 },
1101 "lvw" if !context.in_page_rule() => {
1102 Self::ViewportPercentage(ViewportPercentageLength::Lvw(value))
1103 },
1104 "dvw" if !context.in_page_rule() => {
1105 Self::ViewportPercentage(ViewportPercentageLength::Dvw(value))
1106 },
1107 "vh" if !context.in_page_rule() => {
1108 Self::ViewportPercentage(ViewportPercentageLength::Vh(value))
1109 },
1110 "svh" if !context.in_page_rule() => {
1111 Self::ViewportPercentage(ViewportPercentageLength::Svh(value))
1112 },
1113 "lvh" if !context.in_page_rule() => {
1114 Self::ViewportPercentage(ViewportPercentageLength::Lvh(value))
1115 },
1116 "dvh" if !context.in_page_rule() => {
1117 Self::ViewportPercentage(ViewportPercentageLength::Dvh(value))
1118 },
1119 "vmin" if !context.in_page_rule() => {
1120 Self::ViewportPercentage(ViewportPercentageLength::Vmin(value))
1121 },
1122 "svmin" if !context.in_page_rule() => {
1123 Self::ViewportPercentage(ViewportPercentageLength::Svmin(value))
1124 },
1125 "lvmin" if !context.in_page_rule() => {
1126 Self::ViewportPercentage(ViewportPercentageLength::Lvmin(value))
1127 },
1128 "dvmin" if !context.in_page_rule() => {
1129 Self::ViewportPercentage(ViewportPercentageLength::Dvmin(value))
1130 },
1131 "vmax" if !context.in_page_rule() => {
1132 Self::ViewportPercentage(ViewportPercentageLength::Vmax(value))
1133 },
1134 "svmax" if !context.in_page_rule() => {
1135 Self::ViewportPercentage(ViewportPercentageLength::Svmax(value))
1136 },
1137 "lvmax" if !context.in_page_rule() => {
1138 Self::ViewportPercentage(ViewportPercentageLength::Lvmax(value))
1139 },
1140 "dvmax" if !context.in_page_rule() => {
1141 Self::ViewportPercentage(ViewportPercentageLength::Dvmax(value))
1142 },
1143 "vb" if !context.in_page_rule() => {
1144 Self::ViewportPercentage(ViewportPercentageLength::Vb(value))
1145 },
1146 "svb" if !context.in_page_rule() => {
1147 Self::ViewportPercentage(ViewportPercentageLength::Svb(value))
1148 },
1149 "lvb" if !context.in_page_rule() => {
1150 Self::ViewportPercentage(ViewportPercentageLength::Lvb(value))
1151 },
1152 "dvb" if !context.in_page_rule() => {
1153 Self::ViewportPercentage(ViewportPercentageLength::Dvb(value))
1154 },
1155 "vi" if !context.in_page_rule() => {
1156 Self::ViewportPercentage(ViewportPercentageLength::Vi(value))
1157 },
1158 "svi" if !context.in_page_rule() => {
1159 Self::ViewportPercentage(ViewportPercentageLength::Svi(value))
1160 },
1161 "lvi" if !context.in_page_rule() => {
1162 Self::ViewportPercentage(ViewportPercentageLength::Lvi(value))
1163 },
1164 "dvi" if !context.in_page_rule() => {
1165 Self::ViewportPercentage(ViewportPercentageLength::Dvi(value))
1166 },
1167 "cqw" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1170 Self::ContainerRelative(ContainerRelativeLength::Cqw(value))
1171 },
1172 "cqh" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1173 Self::ContainerRelative(ContainerRelativeLength::Cqh(value))
1174 },
1175 "cqi" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1176 Self::ContainerRelative(ContainerRelativeLength::Cqi(value))
1177 },
1178 "cqb" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1179 Self::ContainerRelative(ContainerRelativeLength::Cqb(value))
1180 },
1181 "cqmin" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1182 Self::ContainerRelative(ContainerRelativeLength::Cqmin(value))
1183 },
1184 "cqmax" if !context.in_page_rule() && cfg!(feature = "gecko") => {
1185 Self::ContainerRelative(ContainerRelativeLength::Cqmax(value))
1186 },
1187 _ => return Err(()),
1188 })
1189 }
1190
1191 pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
1192 where
1193 O: Fn(f32, f32) -> f32,
1194 {
1195 use self::NoCalcLength::*;
1196
1197 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1198 return Err(());
1199 }
1200
1201 Ok(match (self, other) {
1202 (&Absolute(ref one), &Absolute(ref other)) => Absolute(one.try_op(other, op)?),
1203 (&FontRelative(ref one), &FontRelative(ref other)) => {
1204 FontRelative(one.try_op(other, op)?)
1205 },
1206 (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
1207 ViewportPercentage(one.try_op(other, op)?)
1208 },
1209 (&ContainerRelative(ref one), &ContainerRelative(ref other)) => {
1210 ContainerRelative(one.try_op(other, op)?)
1211 },
1212 (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
1213 ServoCharacterWidth(CharacterWidth(op(one.0 as f32, other.0 as f32) as i32))
1214 },
1215 _ => unsafe {
1218 match *self {
1219 Absolute(..) |
1220 FontRelative(..) |
1221 ViewportPercentage(..) |
1222 ContainerRelative(..) |
1223 ServoCharacterWidth(..) => {},
1224 }
1225 debug_unreachable!("Forgot to handle unit in try_op()")
1226 },
1227 })
1228 }
1229
1230 pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
1231 use self::NoCalcLength::*;
1232
1233 match self {
1234 Absolute(ref one) => Absolute(one.map(op)),
1235 FontRelative(ref one) => FontRelative(one.map(op)),
1236 ViewportPercentage(ref one) => ViewportPercentage(one.map(op)),
1237 ContainerRelative(ref one) => ContainerRelative(one.map(op)),
1238 ServoCharacterWidth(ref one) => {
1239 ServoCharacterWidth(CharacterWidth(op(one.0 as f32) as i32))
1240 },
1241 }
1242 }
1243
1244 #[inline]
1246 pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
1247 match *self {
1248 Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
1249 _ => Err(()),
1250 }
1251 }
1252
1253 #[cfg(feature = "gecko")]
1256 #[inline]
1257 pub fn to_computed_pixel_length_with_font_metrics(
1258 &self,
1259 get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
1260 ) -> Result<CSSFloat, ()> {
1261 match *self {
1262 Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
1263 Self::FontRelative(fr) => {
1264 if let Some(getter) = get_font_metrics {
1265 fr.to_computed_pixel_length_with_font_metrics(getter)
1266 } else {
1267 Err(())
1268 }
1269 },
1270 _ => Err(()),
1271 }
1272 }
1273
1274 #[inline]
1276 pub fn from_px(px_value: CSSFloat) -> NoCalcLength {
1277 NoCalcLength::Absolute(AbsoluteLength::Px(px_value))
1278 }
1279}
1280
1281impl ToCss for NoCalcLength {
1282 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1283 where
1284 W: Write,
1285 {
1286 crate::values::serialize_specified_dimension(
1287 self.unitless_value(),
1288 self.unit(),
1289 false,
1290 dest,
1291 )
1292 }
1293}
1294
1295impl SpecifiedValueInfo for NoCalcLength {}
1296
1297impl PartialOrd for NoCalcLength {
1298 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1299 use self::NoCalcLength::*;
1300
1301 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1302 return None;
1303 }
1304
1305 match (self, other) {
1306 (&Absolute(ref one), &Absolute(ref other)) => one.to_px().partial_cmp(&other.to_px()),
1307 (&FontRelative(ref one), &FontRelative(ref other)) => one.partial_cmp(other),
1308 (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
1309 one.partial_cmp(other)
1310 },
1311 (&ContainerRelative(ref one), &ContainerRelative(ref other)) => one.partial_cmp(other),
1312 (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
1313 one.0.partial_cmp(&other.0)
1314 },
1315 _ => unsafe {
1318 match *self {
1319 Absolute(..) |
1320 FontRelative(..) |
1321 ViewportPercentage(..) |
1322 ContainerRelative(..) |
1323 ServoCharacterWidth(..) => {},
1324 }
1325 debug_unreachable!("Forgot an arm in partial_cmp?")
1326 },
1327 }
1328 }
1329}
1330
1331impl Zero for NoCalcLength {
1332 fn zero() -> Self {
1333 NoCalcLength::Absolute(AbsoluteLength::Px(0.))
1334 }
1335
1336 fn is_zero(&self) -> bool {
1337 NoCalcLength::is_zero(self)
1338 }
1339}
1340
1341#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
1346pub enum Length {
1347 NoCalc(NoCalcLength),
1349 Calc(Box<CalcLengthPercentage>),
1353}
1354
1355impl From<NoCalcLength> for Length {
1356 #[inline]
1357 fn from(len: NoCalcLength) -> Self {
1358 Length::NoCalc(len)
1359 }
1360}
1361
1362impl PartialOrd for FontRelativeLength {
1363 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1364 use self::FontRelativeLength::*;
1365
1366 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1367 return None;
1368 }
1369
1370 match (self, other) {
1371 (&Em(ref one), &Em(ref other)) => one.partial_cmp(other),
1372 (&Ex(ref one), &Ex(ref other)) => one.partial_cmp(other),
1373 (&Ch(ref one), &Ch(ref other)) => one.partial_cmp(other),
1374 (&Cap(ref one), &Cap(ref other)) => one.partial_cmp(other),
1375 (&Ic(ref one), &Ic(ref other)) => one.partial_cmp(other),
1376 (&Rem(ref one), &Rem(ref other)) => one.partial_cmp(other),
1377 (&Lh(ref one), &Lh(ref other)) => one.partial_cmp(other),
1378 (&Rlh(ref one), &Rlh(ref other)) => one.partial_cmp(other),
1379 _ => unsafe {
1382 match *self {
1383 Em(..) | Ex(..) | Ch(..) | Cap(..) | Ic(..) | Rem(..) | Lh(..) | Rlh(..) => {},
1384 }
1385 debug_unreachable!("Forgot an arm in partial_cmp?")
1386 },
1387 }
1388 }
1389}
1390
1391impl PartialOrd for ContainerRelativeLength {
1392 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1393 use self::ContainerRelativeLength::*;
1394
1395 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1396 return None;
1397 }
1398
1399 match (self, other) {
1400 (&Cqw(ref one), &Cqw(ref other)) => one.partial_cmp(other),
1401 (&Cqh(ref one), &Cqh(ref other)) => one.partial_cmp(other),
1402 (&Cqi(ref one), &Cqi(ref other)) => one.partial_cmp(other),
1403 (&Cqb(ref one), &Cqb(ref other)) => one.partial_cmp(other),
1404 (&Cqmin(ref one), &Cqmin(ref other)) => one.partial_cmp(other),
1405 (&Cqmax(ref one), &Cqmax(ref other)) => one.partial_cmp(other),
1406
1407 _ => unsafe {
1411 match *self {
1412 Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
1413 }
1414 debug_unreachable!("Forgot to handle unit in partial_cmp()")
1415 },
1416 }
1417 }
1418}
1419
1420impl PartialOrd for ViewportPercentageLength {
1421 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
1422 use self::ViewportPercentageLength::*;
1423
1424 if std::mem::discriminant(self) != std::mem::discriminant(other) {
1425 return None;
1426 }
1427
1428 match (self, other) {
1429 (&Vw(ref one), &Vw(ref other)) => one.partial_cmp(other),
1430 (&Svw(ref one), &Svw(ref other)) => one.partial_cmp(other),
1431 (&Lvw(ref one), &Lvw(ref other)) => one.partial_cmp(other),
1432 (&Dvw(ref one), &Dvw(ref other)) => one.partial_cmp(other),
1433 (&Vh(ref one), &Vh(ref other)) => one.partial_cmp(other),
1434 (&Svh(ref one), &Svh(ref other)) => one.partial_cmp(other),
1435 (&Lvh(ref one), &Lvh(ref other)) => one.partial_cmp(other),
1436 (&Dvh(ref one), &Dvh(ref other)) => one.partial_cmp(other),
1437 (&Vmin(ref one), &Vmin(ref other)) => one.partial_cmp(other),
1438 (&Svmin(ref one), &Svmin(ref other)) => one.partial_cmp(other),
1439 (&Lvmin(ref one), &Lvmin(ref other)) => one.partial_cmp(other),
1440 (&Dvmin(ref one), &Dvmin(ref other)) => one.partial_cmp(other),
1441 (&Vmax(ref one), &Vmax(ref other)) => one.partial_cmp(other),
1442 (&Svmax(ref one), &Svmax(ref other)) => one.partial_cmp(other),
1443 (&Lvmax(ref one), &Lvmax(ref other)) => one.partial_cmp(other),
1444 (&Dvmax(ref one), &Dvmax(ref other)) => one.partial_cmp(other),
1445 (&Vb(ref one), &Vb(ref other)) => one.partial_cmp(other),
1446 (&Svb(ref one), &Svb(ref other)) => one.partial_cmp(other),
1447 (&Lvb(ref one), &Lvb(ref other)) => one.partial_cmp(other),
1448 (&Dvb(ref one), &Dvb(ref other)) => one.partial_cmp(other),
1449 (&Vi(ref one), &Vi(ref other)) => one.partial_cmp(other),
1450 (&Svi(ref one), &Svi(ref other)) => one.partial_cmp(other),
1451 (&Lvi(ref one), &Lvi(ref other)) => one.partial_cmp(other),
1452 (&Dvi(ref one), &Dvi(ref other)) => one.partial_cmp(other),
1453 _ => unsafe {
1456 match *self {
1457 Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) |
1458 Dvh(..) | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) |
1459 Svmax(..) | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) |
1460 Vi(..) | Svi(..) | Lvi(..) | Dvi(..) => {},
1461 }
1462 debug_unreachable!("Forgot an arm in partial_cmp?")
1463 },
1464 }
1465 }
1466}
1467
1468impl Length {
1469 #[inline]
1470 fn parse_internal<'i, 't>(
1471 context: &ParserContext,
1472 input: &mut Parser<'i, 't>,
1473 num_context: AllowedNumericType,
1474 allow_quirks: AllowQuirks,
1475 ) -> Result<Self, ParseError<'i>> {
1476 let location = input.current_source_location();
1477 let token = input.next()?;
1478 match *token {
1479 Token::Dimension {
1480 value, ref unit, ..
1481 } if num_context.is_ok(context.parsing_mode, value) => {
1482 NoCalcLength::parse_dimension(context, value, unit)
1483 .map(Length::NoCalc)
1484 .map_err(|()| location.new_unexpected_token_error(token.clone()))
1485 },
1486 Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
1487 if value != 0. &&
1488 !context.parsing_mode.allows_unitless_lengths() &&
1489 !allow_quirks.allowed(context.quirks_mode)
1490 {
1491 return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
1492 }
1493 Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(
1494 value,
1495 ))))
1496 },
1497 Token::Function(ref name) => {
1498 let function = CalcNode::math_function(context, name, location)?;
1499 let calc = CalcNode::parse_length(context, input, num_context, function)?;
1500 Ok(Length::Calc(Box::new(calc)))
1501 },
1502 ref token => return Err(location.new_unexpected_token_error(token.clone())),
1503 }
1504 }
1505
1506 #[inline]
1508 pub fn parse_non_negative<'i, 't>(
1509 context: &ParserContext,
1510 input: &mut Parser<'i, 't>,
1511 ) -> Result<Self, ParseError<'i>> {
1512 Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
1513 }
1514
1515 #[inline]
1517 pub fn parse_non_negative_quirky<'i, 't>(
1518 context: &ParserContext,
1519 input: &mut Parser<'i, 't>,
1520 allow_quirks: AllowQuirks,
1521 ) -> Result<Self, ParseError<'i>> {
1522 Self::parse_internal(
1523 context,
1524 input,
1525 AllowedNumericType::NonNegative,
1526 allow_quirks,
1527 )
1528 }
1529
1530 #[inline]
1532 pub fn from_px(px_value: CSSFloat) -> Length {
1533 Length::NoCalc(NoCalcLength::from_px(px_value))
1534 }
1535
1536 pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
1538 match *self {
1539 Self::NoCalc(ref l) => l.to_computed_pixel_length_without_context(),
1540 Self::Calc(ref l) => l.to_computed_pixel_length_without_context(),
1541 }
1542 }
1543
1544 #[cfg(feature = "gecko")]
1546 pub fn to_computed_pixel_length_with_font_metrics(
1547 &self,
1548 get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
1549 ) -> Result<CSSFloat, ()> {
1550 match *self {
1551 Self::NoCalc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
1552 Self::Calc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
1553 }
1554 }
1555}
1556
1557impl Parse for Length {
1558 fn parse<'i, 't>(
1559 context: &ParserContext,
1560 input: &mut Parser<'i, 't>,
1561 ) -> Result<Self, ParseError<'i>> {
1562 Self::parse_quirky(context, input, AllowQuirks::No)
1563 }
1564}
1565
1566impl Zero for Length {
1567 fn zero() -> Self {
1568 Length::NoCalc(NoCalcLength::zero())
1569 }
1570
1571 fn is_zero(&self) -> bool {
1572 match *self {
1575 Length::NoCalc(ref l) => l.is_zero(),
1576 Length::Calc(..) => false,
1577 }
1578 }
1579}
1580
1581impl Length {
1582 pub fn parse_quirky<'i, 't>(
1584 context: &ParserContext,
1585 input: &mut Parser<'i, 't>,
1586 allow_quirks: AllowQuirks,
1587 ) -> Result<Self, ParseError<'i>> {
1588 Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
1589 }
1590}
1591
1592pub type NonNegativeLength = NonNegative<Length>;
1594
1595impl Parse for NonNegativeLength {
1596 #[inline]
1597 fn parse<'i, 't>(
1598 context: &ParserContext,
1599 input: &mut Parser<'i, 't>,
1600 ) -> Result<Self, ParseError<'i>> {
1601 Ok(NonNegative(Length::parse_non_negative(context, input)?))
1602 }
1603}
1604
1605impl From<NoCalcLength> for NonNegativeLength {
1606 #[inline]
1607 fn from(len: NoCalcLength) -> Self {
1608 NonNegative(Length::NoCalc(len))
1609 }
1610}
1611
1612impl From<Length> for NonNegativeLength {
1613 #[inline]
1614 fn from(len: Length) -> Self {
1615 NonNegative(len)
1616 }
1617}
1618
1619impl NonNegativeLength {
1620 #[inline]
1622 pub fn from_px(px_value: CSSFloat) -> Self {
1623 Length::from_px(px_value.max(0.)).into()
1624 }
1625
1626 #[inline]
1628 pub fn parse_quirky<'i, 't>(
1629 context: &ParserContext,
1630 input: &mut Parser<'i, 't>,
1631 allow_quirks: AllowQuirks,
1632 ) -> Result<Self, ParseError<'i>> {
1633 Ok(NonNegative(Length::parse_non_negative_quirky(
1634 context,
1635 input,
1636 allow_quirks,
1637 )?))
1638 }
1639}
1640
1641#[allow(missing_docs)]
1646#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
1647pub enum LengthPercentage {
1648 Length(NoCalcLength),
1649 Percentage(computed::Percentage),
1650 Calc(Box<CalcLengthPercentage>),
1651}
1652
1653impl From<Length> for LengthPercentage {
1654 fn from(len: Length) -> LengthPercentage {
1655 match len {
1656 Length::NoCalc(l) => LengthPercentage::Length(l),
1657 Length::Calc(l) => LengthPercentage::Calc(l),
1658 }
1659 }
1660}
1661
1662impl From<NoCalcLength> for LengthPercentage {
1663 #[inline]
1664 fn from(len: NoCalcLength) -> Self {
1665 LengthPercentage::Length(len)
1666 }
1667}
1668
1669impl From<Percentage> for LengthPercentage {
1670 #[inline]
1671 fn from(pc: Percentage) -> Self {
1672 if let Some(clamping_mode) = pc.calc_clamping_mode() {
1673 LengthPercentage::Calc(Box::new(CalcLengthPercentage {
1674 clamping_mode,
1675 node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())),
1676 }))
1677 } else {
1678 LengthPercentage::Percentage(computed::Percentage(pc.get()))
1679 }
1680 }
1681}
1682
1683impl From<computed::Percentage> for LengthPercentage {
1684 #[inline]
1685 fn from(pc: computed::Percentage) -> Self {
1686 LengthPercentage::Percentage(pc)
1687 }
1688}
1689
1690impl Parse for LengthPercentage {
1691 #[inline]
1692 fn parse<'i, 't>(
1693 context: &ParserContext,
1694 input: &mut Parser<'i, 't>,
1695 ) -> Result<Self, ParseError<'i>> {
1696 Self::parse_quirky(context, input, AllowQuirks::No)
1697 }
1698}
1699
1700impl LengthPercentage {
1701 #[inline]
1702 pub fn zero_percent() -> LengthPercentage {
1704 LengthPercentage::Percentage(computed::Percentage::zero())
1705 }
1706
1707 #[inline]
1708 pub fn hundred_percent() -> LengthPercentage {
1710 LengthPercentage::Percentage(computed::Percentage::hundred())
1711 }
1712
1713 fn parse_internal<'i, 't>(
1714 context: &ParserContext,
1715 input: &mut Parser<'i, 't>,
1716 num_context: AllowedNumericType,
1717 allow_quirks: AllowQuirks,
1718 allow_anchor: AllowAnchorPositioningFunctions,
1719 ) -> Result<Self, ParseError<'i>> {
1720 let location = input.current_source_location();
1721 let token = input.next()?;
1722 match *token {
1723 Token::Dimension {
1724 value, ref unit, ..
1725 } if num_context.is_ok(context.parsing_mode, value) => {
1726 return NoCalcLength::parse_dimension(context, value, unit)
1727 .map(LengthPercentage::Length)
1728 .map_err(|()| location.new_unexpected_token_error(token.clone()));
1729 },
1730 Token::Percentage { unit_value, .. }
1731 if num_context.is_ok(context.parsing_mode, unit_value) =>
1732 {
1733 return Ok(LengthPercentage::Percentage(computed::Percentage(
1734 unit_value,
1735 )));
1736 },
1737 Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
1738 if value != 0. &&
1739 !context.parsing_mode.allows_unitless_lengths() &&
1740 !allow_quirks.allowed(context.quirks_mode)
1741 {
1742 return Err(location.new_unexpected_token_error(token.clone()));
1743 } else {
1744 return Ok(LengthPercentage::Length(NoCalcLength::from_px(value)));
1745 }
1746 },
1747 Token::Function(ref name) => {
1748 let function = CalcNode::math_function(context, name, location)?;
1749 let calc = CalcNode::parse_length_or_percentage(
1750 context,
1751 input,
1752 num_context,
1753 function,
1754 allow_anchor,
1755 )?;
1756 Ok(LengthPercentage::Calc(Box::new(calc)))
1757 },
1758 _ => return Err(location.new_unexpected_token_error(token.clone())),
1759 }
1760 }
1761
1762 #[inline]
1765 pub fn parse_quirky<'i, 't>(
1766 context: &ParserContext,
1767 input: &mut Parser<'i, 't>,
1768 allow_quirks: AllowQuirks,
1769 ) -> Result<Self, ParseError<'i>> {
1770 Self::parse_internal(
1771 context,
1772 input,
1773 AllowedNumericType::All,
1774 allow_quirks,
1775 AllowAnchorPositioningFunctions::No,
1776 )
1777 }
1778
1779 #[inline]
1782 fn parse_quirky_with_anchor_size_function<'i, 't>(
1783 context: &ParserContext,
1784 input: &mut Parser<'i, 't>,
1785 allow_quirks: AllowQuirks,
1786 ) -> Result<Self, ParseError<'i>> {
1787 Self::parse_internal(
1788 context,
1789 input,
1790 AllowedNumericType::All,
1791 allow_quirks,
1792 AllowAnchorPositioningFunctions::AllowAnchorSize,
1793 )
1794 }
1795
1796 #[inline]
1799 pub fn parse_quirky_with_anchor_functions<'i, 't>(
1800 context: &ParserContext,
1801 input: &mut Parser<'i, 't>,
1802 allow_quirks: AllowQuirks,
1803 ) -> Result<Self, ParseError<'i>> {
1804 Self::parse_internal(
1805 context,
1806 input,
1807 AllowedNumericType::All,
1808 allow_quirks,
1809 AllowAnchorPositioningFunctions::AllowAnchorAndAnchorSize,
1810 )
1811 }
1812
1813 pub fn parse_non_negative_with_anchor_size<'i, 't>(
1816 context: &ParserContext,
1817 input: &mut Parser<'i, 't>,
1818 allow_quirks: AllowQuirks,
1819 ) -> Result<Self, ParseError<'i>> {
1820 Self::parse_internal(
1821 context,
1822 input,
1823 AllowedNumericType::NonNegative,
1824 allow_quirks,
1825 AllowAnchorPositioningFunctions::AllowAnchorSize,
1826 )
1827 }
1828
1829 #[inline]
1834 pub fn parse_non_negative<'i, 't>(
1835 context: &ParserContext,
1836 input: &mut Parser<'i, 't>,
1837 ) -> Result<Self, ParseError<'i>> {
1838 Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
1839 }
1840
1841 #[inline]
1843 pub fn parse_non_negative_quirky<'i, 't>(
1844 context: &ParserContext,
1845 input: &mut Parser<'i, 't>,
1846 allow_quirks: AllowQuirks,
1847 ) -> Result<Self, ParseError<'i>> {
1848 Self::parse_internal(
1849 context,
1850 input,
1851 AllowedNumericType::NonNegative,
1852 allow_quirks,
1853 AllowAnchorPositioningFunctions::No,
1854 )
1855 }
1856
1857 fn to_calc_node(self) -> CalcNode {
1861 match self {
1862 LengthPercentage::Length(l) => CalcNode::Leaf(calc::Leaf::Length(l)),
1863 LengthPercentage::Percentage(p) => CalcNode::Leaf(calc::Leaf::Percentage(p.0)),
1864 LengthPercentage::Calc(p) => p.node,
1865 }
1866 }
1867
1868 pub fn hundred_percent_minus(self, clamping_mode: AllowedNumericType) -> Self {
1870 let mut sum = smallvec::SmallVec::<[CalcNode; 2]>::new();
1871 sum.push(CalcNode::Leaf(calc::Leaf::Percentage(1.0)));
1872
1873 let mut node = self.to_calc_node();
1874 node.negate();
1875 sum.push(node);
1876
1877 let calc = CalcNode::Sum(sum.into_boxed_slice().into());
1878 LengthPercentage::Calc(Box::new(
1879 calc.into_length_or_percentage(clamping_mode).unwrap(),
1880 ))
1881 }
1882}
1883
1884impl Zero for LengthPercentage {
1885 fn zero() -> Self {
1886 LengthPercentage::Length(NoCalcLength::zero())
1887 }
1888
1889 fn is_zero(&self) -> bool {
1890 match *self {
1891 LengthPercentage::Length(l) => l.is_zero(),
1892 LengthPercentage::Percentage(p) => p.0 == 0.0,
1893 LengthPercentage::Calc(_) => false,
1894 }
1895 }
1896}
1897
1898impl ZeroNoPercent for LengthPercentage {
1899 fn is_zero_no_percent(&self) -> bool {
1900 match *self {
1901 LengthPercentage::Percentage(_) => false,
1902 _ => self.is_zero(),
1903 }
1904 }
1905}
1906
1907pub type LengthPercentageOrAuto = generics::LengthPercentageOrAuto<LengthPercentage>;
1909
1910impl LengthPercentageOrAuto {
1911 #[inline]
1913 pub fn zero_percent() -> Self {
1914 generics::LengthPercentageOrAuto::LengthPercentage(LengthPercentage::zero_percent())
1915 }
1916
1917 #[inline]
1920 pub fn parse_quirky<'i, 't>(
1921 context: &ParserContext,
1922 input: &mut Parser<'i, 't>,
1923 allow_quirks: AllowQuirks,
1924 ) -> Result<Self, ParseError<'i>> {
1925 Self::parse_with(context, input, |context, input| {
1926 LengthPercentage::parse_quirky(context, input, allow_quirks)
1927 })
1928 }
1929}
1930
1931pub type NonNegativeLengthPercentageOrAuto =
1933 generics::LengthPercentageOrAuto<NonNegativeLengthPercentage>;
1934
1935impl NonNegativeLengthPercentageOrAuto {
1936 #[inline]
1938 pub fn zero_percent() -> Self {
1939 generics::LengthPercentageOrAuto::LengthPercentage(
1940 NonNegativeLengthPercentage::zero_percent(),
1941 )
1942 }
1943
1944 #[inline]
1947 pub fn parse_quirky<'i, 't>(
1948 context: &ParserContext,
1949 input: &mut Parser<'i, 't>,
1950 allow_quirks: AllowQuirks,
1951 ) -> Result<Self, ParseError<'i>> {
1952 Self::parse_with(context, input, |context, input| {
1953 NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)
1954 })
1955 }
1956}
1957
1958pub type NonNegativeLengthPercentage = NonNegative<LengthPercentage>;
1960
1961pub type NonNegativeLengthPercentageOrNormal =
1963 GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
1964
1965impl From<NoCalcLength> for NonNegativeLengthPercentage {
1966 #[inline]
1967 fn from(len: NoCalcLength) -> Self {
1968 NonNegative(LengthPercentage::from(len))
1969 }
1970}
1971
1972impl Parse for NonNegativeLengthPercentage {
1973 #[inline]
1974 fn parse<'i, 't>(
1975 context: &ParserContext,
1976 input: &mut Parser<'i, 't>,
1977 ) -> Result<Self, ParseError<'i>> {
1978 Self::parse_quirky(context, input, AllowQuirks::No)
1979 }
1980}
1981
1982impl NonNegativeLengthPercentage {
1983 #[inline]
1984 pub fn zero_percent() -> Self {
1986 NonNegative(LengthPercentage::zero_percent())
1987 }
1988
1989 #[inline]
1992 pub fn parse_quirky<'i, 't>(
1993 context: &ParserContext,
1994 input: &mut Parser<'i, 't>,
1995 allow_quirks: AllowQuirks,
1996 ) -> Result<Self, ParseError<'i>> {
1997 LengthPercentage::parse_non_negative_quirky(context, input, allow_quirks).map(NonNegative)
1998 }
1999
2000 #[inline]
2003 pub fn parse_non_negative_with_anchor_size<'i, 't>(
2004 context: &ParserContext,
2005 input: &mut Parser<'i, 't>,
2006 allow_quirks: AllowQuirks,
2007 ) -> Result<Self, ParseError<'i>> {
2008 LengthPercentage::parse_non_negative_with_anchor_size(context, input, allow_quirks)
2009 .map(NonNegative)
2010 }
2011}
2012
2013pub type LengthOrAuto = generics::LengthPercentageOrAuto<Length>;
2019
2020impl LengthOrAuto {
2021 #[inline]
2024 pub fn parse_quirky<'i, 't>(
2025 context: &ParserContext,
2026 input: &mut Parser<'i, 't>,
2027 allow_quirks: AllowQuirks,
2028 ) -> Result<Self, ParseError<'i>> {
2029 Self::parse_with(context, input, |context, input| {
2030 Length::parse_quirky(context, input, allow_quirks)
2031 })
2032 }
2033}
2034
2035pub type NonNegativeLengthOrAuto = generics::LengthPercentageOrAuto<NonNegativeLength>;
2037
2038pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
2040
2041pub type Size = GenericSize<NonNegativeLengthPercentage>;
2043
2044impl Parse for Size {
2045 fn parse<'i, 't>(
2046 context: &ParserContext,
2047 input: &mut Parser<'i, 't>,
2048 ) -> Result<Self, ParseError<'i>> {
2049 Size::parse_quirky(context, input, AllowQuirks::No)
2050 }
2051}
2052
2053macro_rules! parse_size_non_length {
2054 ($size:ident, $input:expr, $auto_or_none:expr => $auto_or_none_ident:ident) => {{
2055 let size = $input.try_parse(|input| {
2056 Ok(try_match_ident_ignore_ascii_case! { input,
2057 "min-content" | "-moz-min-content" => $size::MinContent,
2058 "max-content" | "-moz-max-content" => $size::MaxContent,
2059 "fit-content" | "-moz-fit-content" => $size::FitContent,
2060 #[cfg(feature = "gecko")]
2061 "-moz-available" => $size::MozAvailable,
2062 #[cfg(feature = "gecko")]
2063 "-webkit-fill-available" if is_webkit_fill_available_keyword_enabled() => $size::WebkitFillAvailable,
2064 "stretch" if is_stretch_enabled() => $size::Stretch,
2065 $auto_or_none => $size::$auto_or_none_ident,
2066 })
2067 });
2068 if size.is_ok() {
2069 return size;
2070 }
2071 }};
2072}
2073
2074#[cfg(feature = "gecko")]
2075fn is_webkit_fill_available_keyword_enabled() -> bool {
2076 static_prefs::pref!("layout.css.webkit-fill-available.enabled")
2077}
2078fn is_stretch_enabled() -> bool {
2079 static_prefs::pref!("layout.css.stretch-size-keyword.enabled")
2080}
2081
2082fn is_fit_content_function_enabled() -> bool {
2083 static_prefs::pref!("layout.css.fit-content-function.enabled")
2084}
2085
2086macro_rules! parse_fit_content_function {
2087 ($size:ident, $input:expr, $context:expr, $allow_quirks:expr) => {
2088 if is_fit_content_function_enabled() {
2089 if let Ok(length) = $input.try_parse(|input| {
2090 input.expect_function_matching("fit-content")?;
2091 input.parse_nested_block(|i| {
2092 NonNegativeLengthPercentage::parse_quirky($context, i, $allow_quirks)
2093 })
2094 }) {
2095 return Ok($size::FitContentFunction(length));
2096 }
2097 }
2098 };
2099}
2100
2101impl Size {
2102 pub fn parse_quirky<'i, 't>(
2104 context: &ParserContext,
2105 input: &mut Parser<'i, 't>,
2106 allow_quirks: AllowQuirks,
2107 ) -> Result<Self, ParseError<'i>> {
2108 parse_size_non_length!(Size, input, "auto" => Auto);
2109 parse_fit_content_function!(Size, input, context, allow_quirks);
2110
2111 match input
2112 .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
2113 {
2114 Ok(length) => return Ok(GenericSize::LengthPercentage(length)),
2115 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2116 return Err(e.into())
2117 },
2118 Err(_) => (),
2119 };
2120 if let Ok(length) = input.try_parse(|i| {
2121 NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
2122 context,
2123 i,
2124 allow_quirks,
2125 )
2126 }) {
2127 return Ok(GenericSize::AnchorContainingCalcFunction(length));
2128 }
2129 Ok(Self::AnchorSizeFunction(Box::new(
2130 GenericAnchorSizeFunction::parse(context, input)?,
2131 )))
2132 }
2133
2134 #[inline]
2136 pub fn zero_percent() -> Self {
2137 GenericSize::LengthPercentage(NonNegativeLengthPercentage::zero_percent())
2138 }
2139}
2140
2141pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
2143
2144impl Parse for MaxSize {
2145 fn parse<'i, 't>(
2146 context: &ParserContext,
2147 input: &mut Parser<'i, 't>,
2148 ) -> Result<Self, ParseError<'i>> {
2149 MaxSize::parse_quirky(context, input, AllowQuirks::No)
2150 }
2151}
2152
2153impl MaxSize {
2154 pub fn parse_quirky<'i, 't>(
2156 context: &ParserContext,
2157 input: &mut Parser<'i, 't>,
2158 allow_quirks: AllowQuirks,
2159 ) -> Result<Self, ParseError<'i>> {
2160 parse_size_non_length!(MaxSize, input, "none" => None);
2161 parse_fit_content_function!(MaxSize, input, context, allow_quirks);
2162
2163 match input
2164 .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
2165 {
2166 Ok(length) => return Ok(GenericMaxSize::LengthPercentage(length)),
2167 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2168 return Err(e.into())
2169 },
2170 Err(_) => (),
2171 };
2172 if let Ok(length) = input.try_parse(|i| {
2173 NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
2174 context,
2175 i,
2176 allow_quirks,
2177 )
2178 }) {
2179 return Ok(GenericMaxSize::AnchorContainingCalcFunction(length));
2180 }
2181 Ok(Self::AnchorSizeFunction(Box::new(
2182 GenericAnchorSizeFunction::parse(context, input)?,
2183 )))
2184 }
2185}
2186
2187pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
2189
2190pub type AnchorSizeFunction = GenericAnchorSizeFunction<LengthPercentage>;
2192
2193pub type Margin = GenericMargin<LengthPercentage>;
2195
2196impl Margin {
2197 #[inline]
2200 pub fn parse_quirky<'i, 't>(
2201 context: &ParserContext,
2202 input: &mut Parser<'i, 't>,
2203 allow_quirks: AllowQuirks,
2204 ) -> Result<Self, ParseError<'i>> {
2205 if let Ok(l) = input.try_parse(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
2206 {
2207 return Ok(Self::LengthPercentage(l));
2208 }
2209 match input.try_parse(|i| i.expect_ident_matching("auto")) {
2210 Ok(_) => return Ok(Self::Auto),
2211 Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
2212 return Err(e.into())
2213 },
2214 Err(_) => (),
2215 };
2216 if let Ok(l) = input.try_parse(|i| {
2217 LengthPercentage::parse_quirky_with_anchor_size_function(context, i, allow_quirks)
2218 }) {
2219 return Ok(Self::AnchorContainingCalcFunction(l));
2220 }
2221 let inner = AnchorSizeFunction::parse(context, input)?;
2222 Ok(Self::AnchorSizeFunction(Box::new(inner)))
2223 }
2224}
2225
2226impl Parse for Margin {
2227 fn parse<'i, 't>(
2228 context: &ParserContext,
2229 input: &mut Parser<'i, 't>,
2230 ) -> Result<Self, ParseError<'i>> {
2231 Self::parse_quirky(context, input, AllowQuirks::No)
2232 }
2233}