tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

length.rs (90734B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
      4 
      5 //! [Length values][length].
      6 //!
      7 //! [length]: https://drafts.csswg.org/css-values/#lengths
      8 
      9 use super::{AllowQuirks, Number, Percentage, ToComputedValue};
     10 use crate::computed_value_flags::ComputedValueFlags;
     11 use crate::derives::*;
     12 use crate::font_metrics::{FontMetrics, FontMetricsOrientation};
     13 #[cfg(feature = "gecko")]
     14 use crate::gecko_bindings::structs::GeckoFontMetrics;
     15 use crate::parser::{Parse, ParserContext};
     16 use crate::values::computed::{self, CSSPixelLength, Context, FontSize};
     17 use crate::values::generics::length as generics;
     18 use crate::values::generics::length::{
     19    GenericAnchorSizeFunction, GenericLengthOrNumber, GenericLengthPercentageOrNormal,
     20    GenericMargin, GenericMaxSize, GenericSize,
     21 };
     22 use crate::values::generics::NonNegative;
     23 use crate::values::specified::calc::{self, AllowAnchorPositioningFunctions, CalcNode};
     24 use crate::values::specified::font::QueryFontMetricsFlags;
     25 use crate::values::specified::NonNegativeNumber;
     26 use crate::values::CSSFloat;
     27 use crate::{Zero, ZeroNoPercent};
     28 use app_units::AU_PER_PX;
     29 use cssparser::{match_ignore_ascii_case, Parser, Token};
     30 use debug_unreachable::debug_unreachable;
     31 use std::cmp;
     32 use std::fmt::{self, Write};
     33 use style_traits::values::specified::AllowedNumericType;
     34 use style_traits::{
     35    CssString, CssWriter, NumericValue, ParseError, SpecifiedValueInfo, StyleParseErrorKind, ToCss,
     36    ToTyped, TypedValue,
     37 };
     38 
     39 pub use super::image::Image;
     40 pub use super::image::{EndingShape as GradientEndingShape, Gradient};
     41 pub use crate::values::specified::calc::CalcLengthPercentage;
     42 
     43 /// Number of pixels per inch
     44 pub const PX_PER_IN: CSSFloat = 96.;
     45 /// Number of pixels per centimeter
     46 pub const PX_PER_CM: CSSFloat = PX_PER_IN / 2.54;
     47 /// Number of pixels per millimeter
     48 pub const PX_PER_MM: CSSFloat = PX_PER_IN / 25.4;
     49 /// Number of pixels per quarter
     50 pub const PX_PER_Q: CSSFloat = PX_PER_MM / 4.;
     51 /// Number of pixels per point
     52 pub const PX_PER_PT: CSSFloat = PX_PER_IN / 72.;
     53 /// Number of pixels per pica
     54 pub const PX_PER_PC: CSSFloat = PX_PER_PT * 12.;
     55 
     56 /// A font relative length. Note that if any new value is
     57 /// added here, `custom_properties::NonCustomReferences::from_unit`
     58 /// must also be updated. Consult the comment in that function as to why.
     59 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
     60 #[repr(u8)]
     61 pub enum FontRelativeLength {
     62    /// A "em" value: https://drafts.csswg.org/css-values/#em
     63    #[css(dimension)]
     64    Em(CSSFloat),
     65    /// A "ex" value: https://drafts.csswg.org/css-values/#ex
     66    #[css(dimension)]
     67    Ex(CSSFloat),
     68    /// A "rex" value: https://drafts.csswg.org/css-values/#rex
     69    #[css(dimension)]
     70    Rex(CSSFloat),
     71    /// A "ch" value: https://drafts.csswg.org/css-values/#ch
     72    #[css(dimension)]
     73    Ch(CSSFloat),
     74    /// A "rch" value: https://drafts.csswg.org/css-values/#rch
     75    #[css(dimension)]
     76    Rch(CSSFloat),
     77    /// A "cap" value: https://drafts.csswg.org/css-values/#cap
     78    #[css(dimension)]
     79    Cap(CSSFloat),
     80    /// A "rcap" value: https://drafts.csswg.org/css-values/#rcap
     81    #[css(dimension)]
     82    Rcap(CSSFloat),
     83    /// An "ic" value: https://drafts.csswg.org/css-values/#ic
     84    #[css(dimension)]
     85    Ic(CSSFloat),
     86    /// A "ric" value: https://drafts.csswg.org/css-values/#ric
     87    #[css(dimension)]
     88    Ric(CSSFloat),
     89    /// A "rem" value: https://drafts.csswg.org/css-values/#rem
     90    #[css(dimension)]
     91    Rem(CSSFloat),
     92    /// A "lh" value: https://drafts.csswg.org/css-values/#lh
     93    #[css(dimension)]
     94    Lh(CSSFloat),
     95    /// A "rlh" value: https://drafts.csswg.org/css-values/#rlh
     96    #[css(dimension)]
     97    Rlh(CSSFloat),
     98 }
     99 
    100 /// A source to resolve font-relative units against
    101 #[derive(Clone, Copy, Debug, PartialEq)]
    102 pub enum FontBaseSize {
    103    /// Use the font-size of the current element.
    104    CurrentStyle,
    105    /// Use the inherited font-size.
    106    InheritedStyle,
    107 }
    108 
    109 /// A source to resolve font-relative line-height units against.
    110 #[derive(Clone, Copy, Debug, PartialEq)]
    111 pub enum LineHeightBase {
    112    /// Use the line-height of the current element.
    113    CurrentStyle,
    114    /// Use the inherited line-height.
    115    InheritedStyle,
    116 }
    117 
    118 impl FontBaseSize {
    119    /// Calculate the actual size for a given context
    120    pub fn resolve(&self, context: &Context) -> computed::FontSize {
    121        let style = context.style();
    122        match *self {
    123            Self::CurrentStyle => style.get_font().clone_font_size(),
    124            Self::InheritedStyle => {
    125                // If we're using the size from our inherited style, we still need to apply our
    126                // own zoom.
    127                let zoom = style.effective_zoom_for_inheritance;
    128                style.get_parent_font().clone_font_size().zoom(zoom)
    129            },
    130        }
    131    }
    132 }
    133 
    134 impl FontRelativeLength {
    135    /// Unit identifier for `em`.
    136    pub const EM: &'static str = "em";
    137    /// Unit identifier for `ex`.
    138    pub const EX: &'static str = "ex";
    139    /// Unit identifier for `rex`.
    140    pub const REX: &'static str = "rex";
    141    /// Unit identifier for `ch`.
    142    pub const CH: &'static str = "ch";
    143    /// Unit identifier for `rch`.
    144    pub const RCH: &'static str = "rch";
    145    /// Unit identifier for `cap`.
    146    pub const CAP: &'static str = "cap";
    147    /// Unit identifier for `rcap`.
    148    pub const RCAP: &'static str = "rcap";
    149    /// Unit identifier for `ic`.
    150    pub const IC: &'static str = "ic";
    151    /// Unit identifier for `ric`.
    152    pub const RIC: &'static str = "ric";
    153    /// Unit identifier for `rem`.
    154    pub const REM: &'static str = "rem";
    155    /// Unit identifier for `lh`.
    156    pub const LH: &'static str = "lh";
    157    /// Unit identifier for `rlh`.
    158    pub const RLH: &'static str = "rlh";
    159 
    160    /// Return the unitless, raw value.
    161    fn unitless_value(&self) -> CSSFloat {
    162        match *self {
    163            Self::Em(v)
    164            | Self::Ex(v)
    165            | Self::Rex(v)
    166            | Self::Ch(v)
    167            | Self::Rch(v)
    168            | Self::Cap(v)
    169            | Self::Rcap(v)
    170            | Self::Ic(v)
    171            | Self::Ric(v)
    172            | Self::Rem(v)
    173            | Self::Lh(v)
    174            | Self::Rlh(v) => v,
    175        }
    176    }
    177 
    178    // Return the unit, as a string.
    179    fn unit(&self) -> &'static str {
    180        match *self {
    181            Self::Em(_) => Self::EM,
    182            Self::Ex(_) => Self::EX,
    183            Self::Rex(_) => Self::REX,
    184            Self::Ch(_) => Self::CH,
    185            Self::Rch(_) => Self::RCH,
    186            Self::Cap(_) => Self::CAP,
    187            Self::Rcap(_) => Self::RCAP,
    188            Self::Ic(_) => Self::IC,
    189            Self::Ric(_) => Self::RIC,
    190            Self::Rem(_) => Self::REM,
    191            Self::Lh(_) => Self::LH,
    192            Self::Rlh(_) => Self::RLH,
    193        }
    194    }
    195 
    196    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
    197    where
    198        O: Fn(f32, f32) -> f32,
    199    {
    200        use self::FontRelativeLength::*;
    201 
    202        if std::mem::discriminant(self) != std::mem::discriminant(other) {
    203            return Err(());
    204        }
    205 
    206        Ok(match (self, other) {
    207            (&Em(one), &Em(other)) => Em(op(one, other)),
    208            (&Ex(one), &Ex(other)) => Ex(op(one, other)),
    209            (&Rex(one), &Rex(other)) => Rex(op(one, other)),
    210            (&Ch(one), &Ch(other)) => Ch(op(one, other)),
    211            (&Rch(one), &Rch(other)) => Rch(op(one, other)),
    212            (&Cap(one), &Cap(other)) => Cap(op(one, other)),
    213            (&Rcap(one), &Rcap(other)) => Rcap(op(one, other)),
    214            (&Ic(one), &Ic(other)) => Ic(op(one, other)),
    215            (&Ric(one), &Ric(other)) => Ric(op(one, other)),
    216            (&Rem(one), &Rem(other)) => Rem(op(one, other)),
    217            (&Lh(one), &Lh(other)) => Lh(op(one, other)),
    218            (&Rlh(one), &Rlh(other)) => Rlh(op(one, other)),
    219            // See https://github.com/rust-lang/rust/issues/68867. rustc isn't
    220            // able to figure it own on its own so we help.
    221            _ => unsafe {
    222                match *self {
    223                    Em(..) | Rem(..) | Ex(..) | Rex(..) | Ch(..) | Rch(..) | Cap(..) | Rcap(..)
    224                    | Ic(..) | Ric(..) | Lh(..) | Rlh(..) => {},
    225                }
    226                debug_unreachable!("Forgot to handle unit in try_op()")
    227            },
    228        })
    229    }
    230 
    231    fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
    232        match self {
    233            Self::Em(x) => Self::Em(op(*x)),
    234            Self::Ex(x) => Self::Ex(op(*x)),
    235            Self::Rex(x) => Self::Rex(op(*x)),
    236            Self::Ch(x) => Self::Ch(op(*x)),
    237            Self::Rch(x) => Self::Rch(op(*x)),
    238            Self::Cap(x) => Self::Cap(op(*x)),
    239            Self::Rcap(x) => Self::Rcap(op(*x)),
    240            Self::Ic(x) => Self::Ic(op(*x)),
    241            Self::Ric(x) => Self::Ric(op(*x)),
    242            Self::Rem(x) => Self::Rem(op(*x)),
    243            Self::Lh(x) => Self::Lh(op(*x)),
    244            Self::Rlh(x) => Self::Rlh(op(*x)),
    245        }
    246    }
    247 
    248    /// Computes the font-relative length.
    249    pub fn to_computed_value(
    250        &self,
    251        context: &Context,
    252        base_size: FontBaseSize,
    253        line_height_base: LineHeightBase,
    254    ) -> computed::Length {
    255        let (reference_size, length) =
    256            self.reference_font_size_and_length(context, base_size, line_height_base);
    257        (reference_size * length).finite()
    258    }
    259 
    260    /// Computes the length, given a GeckoFontMetrics getter to resolve font-relative units.
    261    #[cfg(feature = "gecko")]
    262    pub fn to_computed_pixel_length_with_font_metrics(
    263        &self,
    264        get_font_metrics: impl Fn() -> GeckoFontMetrics,
    265    ) -> Result<CSSFloat, ()> {
    266        let metrics = get_font_metrics();
    267        Ok(match *self {
    268            Self::Em(v) => v * metrics.mComputedEmSize.px(),
    269            Self::Ex(v) => v * metrics.mXSize.px(),
    270            Self::Ch(v) => v * metrics.mChSize.px(),
    271            Self::Cap(v) => v * metrics.mCapHeight.px(),
    272            Self::Ic(v) => v * metrics.mIcWidth.px(),
    273            // `lh`, `rlh` are unsupported as we have no line-height context
    274            // `rem`, `rex`, `rch`, `rcap`, and `ric` are unsupported as we have no root font context.
    275            Self::Lh(_)
    276            | Self::Rlh(_)
    277            | Self::Rem(_)
    278            | Self::Rex(_)
    279            | Self::Rch(_)
    280            | Self::Rcap(_)
    281            | Self::Ric(_) => return Err(()),
    282        })
    283    }
    284 
    285    /// Return reference font size.
    286    ///
    287    /// We use the base_size flag to pass a different size for computing
    288    /// font-size and unconstrained font-size.
    289    ///
    290    /// This returns a pair, the first one is the reference font size, and the
    291    /// second one is the unpacked relative length.
    292    fn reference_font_size_and_length(
    293        &self,
    294        context: &Context,
    295        base_size: FontBaseSize,
    296        line_height_base: LineHeightBase,
    297    ) -> (computed::Length, CSSFloat) {
    298        fn query_font_metrics(
    299            context: &Context,
    300            base_size: FontBaseSize,
    301            orientation: FontMetricsOrientation,
    302            flags: QueryFontMetricsFlags,
    303        ) -> FontMetrics {
    304            context.query_font_metrics(base_size, orientation, flags)
    305        }
    306 
    307        fn ex_size(
    308            context: &Context,
    309            base_size: FontBaseSize,
    310            reference_font_size: &FontSize,
    311        ) -> computed::Length {
    312            // The x-height is an intrinsically horizontal metric.
    313            let metrics = query_font_metrics(
    314                context,
    315                base_size,
    316                FontMetricsOrientation::Horizontal,
    317                QueryFontMetricsFlags::empty(),
    318            );
    319            metrics.x_height_or_default(reference_font_size.used_size())
    320        }
    321 
    322        fn ch_size(
    323            context: &Context,
    324            base_size: FontBaseSize,
    325            reference_font_size: &FontSize,
    326        ) -> computed::Length {
    327            // https://drafts.csswg.org/css-values/#ch:
    328            //
    329            //     Equal to the used advance measure of the “0” (ZERO,
    330            //     U+0030) glyph in the font used to render it. (The advance
    331            //     measure of a glyph is its advance width or height,
    332            //     whichever is in the inline axis of the element.)
    333            //
    334            let metrics = query_font_metrics(
    335                context,
    336                base_size,
    337                FontMetricsOrientation::MatchContextPreferHorizontal,
    338                QueryFontMetricsFlags::NEEDS_CH,
    339            );
    340            metrics.zero_advance_measure_or_default(
    341                reference_font_size.used_size(),
    342                context.style().writing_mode.is_upright(),
    343            )
    344        }
    345 
    346        fn cap_size(context: &Context, base_size: FontBaseSize) -> computed::Length {
    347            let metrics = query_font_metrics(
    348                context,
    349                base_size,
    350                FontMetricsOrientation::Horizontal,
    351                QueryFontMetricsFlags::empty(),
    352            );
    353            metrics.cap_height_or_default()
    354        }
    355 
    356        fn ic_size(
    357            context: &Context,
    358            base_size: FontBaseSize,
    359            reference_font_size: &FontSize,
    360        ) -> computed::Length {
    361            let metrics = query_font_metrics(
    362                context,
    363                base_size,
    364                FontMetricsOrientation::MatchContextPreferVertical,
    365                QueryFontMetricsFlags::NEEDS_IC,
    366            );
    367            metrics.ic_width_or_default(reference_font_size.used_size())
    368        }
    369 
    370        let reference_font_size = base_size.resolve(context);
    371        match *self {
    372            // Local font-relative units
    373            Self::Em(length) => {
    374                if context.for_non_inherited_property && base_size == FontBaseSize::CurrentStyle {
    375                    context
    376                        .rule_cache_conditions
    377                        .borrow_mut()
    378                        .set_font_size_dependency(reference_font_size.computed_size);
    379                }
    380 
    381                (reference_font_size.computed_size(), length)
    382            },
    383            Self::Lh(length) => {
    384                // https://drafts.csswg.org/css-values-4/#lh
    385                //
    386                //     When specified in media-query, the lh units refer to the
    387                //     initial values of font and line-height properties.
    388                //
    389                let reference_size = if context.in_media_query {
    390                    context
    391                        .device()
    392                        .calc_line_height(
    393                            &context.default_style().get_font(),
    394                            context.style().writing_mode,
    395                            None,
    396                        )
    397                        .0
    398                } else {
    399                    let line_height = context.builder.calc_line_height(
    400                        context.device(),
    401                        line_height_base,
    402                        context.style().writing_mode,
    403                    );
    404                    if context.for_non_inherited_property
    405                        && line_height_base == LineHeightBase::CurrentStyle
    406                    {
    407                        context
    408                            .rule_cache_conditions
    409                            .borrow_mut()
    410                            .set_line_height_dependency(line_height)
    411                    }
    412                    line_height.0
    413                };
    414                (reference_size, length)
    415            },
    416            Self::Ex(length) => (ex_size(context, base_size, &reference_font_size), length),
    417            Self::Ch(length) => (ch_size(context, base_size, &reference_font_size), length),
    418            Self::Cap(length) => (cap_size(context, base_size), length),
    419            Self::Ic(length) => (ic_size(context, base_size, &reference_font_size), length),
    420 
    421            // Root font relative units
    422            Self::Rex(length) => {
    423                let reference_size = if context.builder.is_root_element || context.in_media_query {
    424                    ex_size(context, base_size, &reference_font_size)
    425                } else {
    426                    context
    427                        .device()
    428                        .root_font_metrics_ex()
    429                        .zoom(context.builder.effective_zoom)
    430                };
    431                (reference_size, length)
    432            },
    433            Self::Rch(length) => {
    434                let reference_size = if context.builder.is_root_element || context.in_media_query {
    435                    ch_size(context, base_size, &reference_font_size)
    436                } else {
    437                    context
    438                        .device()
    439                        .root_font_metrics_ch()
    440                        .zoom(context.builder.effective_zoom)
    441                };
    442                (reference_size, length)
    443            },
    444            Self::Rcap(length) => {
    445                let reference_size = if context.builder.is_root_element || context.in_media_query {
    446                    cap_size(context, base_size)
    447                } else {
    448                    context
    449                        .device()
    450                        .root_font_metrics_cap()
    451                        .zoom(context.builder.effective_zoom)
    452                };
    453                (reference_size, length)
    454            },
    455            Self::Ric(length) => {
    456                let reference_size = if context.builder.is_root_element || context.in_media_query {
    457                    ic_size(context, base_size, &reference_font_size)
    458                } else {
    459                    context
    460                        .device()
    461                        .root_font_metrics_ic()
    462                        .zoom(context.builder.effective_zoom)
    463                };
    464                (reference_size, length)
    465            },
    466            Self::Rem(length) => {
    467                // https://drafts.csswg.org/css-values/#rem:
    468                //
    469                //     When specified on the font-size property of the root
    470                //     element, the rem units refer to the property's initial
    471                //     value.
    472                //
    473                let reference_size = if context.builder.is_root_element || context.in_media_query {
    474                    reference_font_size.computed_size()
    475                } else {
    476                    context
    477                        .device()
    478                        .root_font_size()
    479                        .zoom(context.builder.effective_zoom)
    480                };
    481                (reference_size, length)
    482            },
    483            Self::Rlh(length) => {
    484                // https://drafts.csswg.org/css-values-4/#rlh
    485                //
    486                //     When specified on the root element, the rlh units refer
    487                //     to the initial values of font and line-height properties.
    488                //
    489                let reference_size = if context.builder.is_root_element {
    490                    context
    491                        .builder
    492                        .calc_line_height(
    493                            context.device(),
    494                            line_height_base,
    495                            context.style().writing_mode,
    496                        )
    497                        .0
    498                } else if context.in_media_query {
    499                    context
    500                        .device()
    501                        .calc_line_height(
    502                            &context.default_style().get_font(),
    503                            context.style().writing_mode,
    504                            None,
    505                        )
    506                        .0
    507                } else {
    508                    context.device().root_line_height()
    509                };
    510                let reference_size = reference_size.zoom(context.builder.effective_zoom);
    511                (reference_size, length)
    512            },
    513        }
    514    }
    515 }
    516 
    517 /// https://drafts.csswg.org/css-values/#viewport-variants
    518 pub enum ViewportVariant {
    519    /// https://drafts.csswg.org/css-values/#ua-default-viewport-size
    520    UADefault,
    521    /// https://drafts.csswg.org/css-values/#small-viewport-percentage-units
    522    Small,
    523    /// https://drafts.csswg.org/css-values/#large-viewport-percentage-units
    524    Large,
    525    /// https://drafts.csswg.org/css-values/#dynamic-viewport-percentage-units
    526    Dynamic,
    527 }
    528 
    529 /// https://drafts.csswg.org/css-values/#viewport-relative-units
    530 #[derive(PartialEq)]
    531 enum ViewportUnit {
    532    /// *vw units.
    533    Vw,
    534    /// *vh units.
    535    Vh,
    536    /// *vmin units.
    537    Vmin,
    538    /// *vmax units.
    539    Vmax,
    540    /// *vb units.
    541    Vb,
    542    /// *vi units.
    543    Vi,
    544 }
    545 
    546 /// A viewport-relative length.
    547 ///
    548 /// <https://drafts.csswg.org/css-values/#viewport-relative-lengths>
    549 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
    550 #[repr(u8)]
    551 pub enum ViewportPercentageLength {
    552    /// <https://drafts.csswg.org/css-values/#valdef-length-vw>
    553    #[css(dimension)]
    554    Vw(CSSFloat),
    555    /// <https://drafts.csswg.org/css-values/#valdef-length-svw>
    556    #[css(dimension)]
    557    Svw(CSSFloat),
    558    /// <https://drafts.csswg.org/css-values/#valdef-length-lvw>
    559    #[css(dimension)]
    560    Lvw(CSSFloat),
    561    /// <https://drafts.csswg.org/css-values/#valdef-length-dvw>
    562    #[css(dimension)]
    563    Dvw(CSSFloat),
    564    /// <https://drafts.csswg.org/css-values/#valdef-length-vh>
    565    #[css(dimension)]
    566    Vh(CSSFloat),
    567    /// <https://drafts.csswg.org/css-values/#valdef-length-svh>
    568    #[css(dimension)]
    569    Svh(CSSFloat),
    570    /// <https://drafts.csswg.org/css-values/#valdef-length-lvh>
    571    #[css(dimension)]
    572    Lvh(CSSFloat),
    573    /// <https://drafts.csswg.org/css-values/#valdef-length-dvh>
    574    #[css(dimension)]
    575    Dvh(CSSFloat),
    576    /// <https://drafts.csswg.org/css-values/#valdef-length-vmin>
    577    #[css(dimension)]
    578    Vmin(CSSFloat),
    579    /// <https://drafts.csswg.org/css-values/#valdef-length-svmin>
    580    #[css(dimension)]
    581    Svmin(CSSFloat),
    582    /// <https://drafts.csswg.org/css-values/#valdef-length-lvmin>
    583    #[css(dimension)]
    584    Lvmin(CSSFloat),
    585    /// <https://drafts.csswg.org/css-values/#valdef-length-dvmin>
    586    #[css(dimension)]
    587    Dvmin(CSSFloat),
    588    /// <https://drafts.csswg.org/css-values/#valdef-length-vmax>
    589    #[css(dimension)]
    590    Vmax(CSSFloat),
    591    /// <https://drafts.csswg.org/css-values/#valdef-length-svmax>
    592    #[css(dimension)]
    593    Svmax(CSSFloat),
    594    /// <https://drafts.csswg.org/css-values/#valdef-length-lvmax>
    595    #[css(dimension)]
    596    Lvmax(CSSFloat),
    597    /// <https://drafts.csswg.org/css-values/#valdef-length-dvmax>
    598    #[css(dimension)]
    599    Dvmax(CSSFloat),
    600    /// <https://drafts.csswg.org/css-values/#valdef-length-vb>
    601    #[css(dimension)]
    602    Vb(CSSFloat),
    603    /// <https://drafts.csswg.org/css-values/#valdef-length-svb>
    604    #[css(dimension)]
    605    Svb(CSSFloat),
    606    /// <https://drafts.csswg.org/css-values/#valdef-length-lvb>
    607    #[css(dimension)]
    608    Lvb(CSSFloat),
    609    /// <https://drafts.csswg.org/css-values/#valdef-length-dvb>
    610    #[css(dimension)]
    611    Dvb(CSSFloat),
    612    /// <https://drafts.csswg.org/css-values/#valdef-length-vi>
    613    #[css(dimension)]
    614    Vi(CSSFloat),
    615    /// <https://drafts.csswg.org/css-values/#valdef-length-svi>
    616    #[css(dimension)]
    617    Svi(CSSFloat),
    618    /// <https://drafts.csswg.org/css-values/#valdef-length-lvi>
    619    #[css(dimension)]
    620    Lvi(CSSFloat),
    621    /// <https://drafts.csswg.org/css-values/#valdef-length-dvi>
    622    #[css(dimension)]
    623    Dvi(CSSFloat),
    624 }
    625 
    626 impl ViewportPercentageLength {
    627    /// Return the unitless, raw value.
    628    fn unitless_value(&self) -> CSSFloat {
    629        self.unpack().2
    630    }
    631 
    632    // Return the unit, as a string.
    633    fn unit(&self) -> &'static str {
    634        match *self {
    635            Self::Vw(_) => "vw",
    636            Self::Lvw(_) => "lvw",
    637            Self::Svw(_) => "svw",
    638            Self::Dvw(_) => "dvw",
    639            Self::Vh(_) => "vh",
    640            Self::Svh(_) => "svh",
    641            Self::Lvh(_) => "lvh",
    642            Self::Dvh(_) => "dvh",
    643            Self::Vmin(_) => "vmin",
    644            Self::Svmin(_) => "svmin",
    645            Self::Lvmin(_) => "lvmin",
    646            Self::Dvmin(_) => "dvmin",
    647            Self::Vmax(_) => "vmax",
    648            Self::Svmax(_) => "svmax",
    649            Self::Lvmax(_) => "lvmax",
    650            Self::Dvmax(_) => "dvmax",
    651            Self::Vb(_) => "vb",
    652            Self::Svb(_) => "svb",
    653            Self::Lvb(_) => "lvb",
    654            Self::Dvb(_) => "dvb",
    655            Self::Vi(_) => "vi",
    656            Self::Svi(_) => "svi",
    657            Self::Lvi(_) => "lvi",
    658            Self::Dvi(_) => "dvi",
    659        }
    660    }
    661 
    662    fn unpack(&self) -> (ViewportVariant, ViewportUnit, CSSFloat) {
    663        match *self {
    664            Self::Vw(v) => (ViewportVariant::UADefault, ViewportUnit::Vw, v),
    665            Self::Svw(v) => (ViewportVariant::Small, ViewportUnit::Vw, v),
    666            Self::Lvw(v) => (ViewportVariant::Large, ViewportUnit::Vw, v),
    667            Self::Dvw(v) => (ViewportVariant::Dynamic, ViewportUnit::Vw, v),
    668            Self::Vh(v) => (ViewportVariant::UADefault, ViewportUnit::Vh, v),
    669            Self::Svh(v) => (ViewportVariant::Small, ViewportUnit::Vh, v),
    670            Self::Lvh(v) => (ViewportVariant::Large, ViewportUnit::Vh, v),
    671            Self::Dvh(v) => (ViewportVariant::Dynamic, ViewportUnit::Vh, v),
    672            Self::Vmin(v) => (ViewportVariant::UADefault, ViewportUnit::Vmin, v),
    673            Self::Svmin(v) => (ViewportVariant::Small, ViewportUnit::Vmin, v),
    674            Self::Lvmin(v) => (ViewportVariant::Large, ViewportUnit::Vmin, v),
    675            Self::Dvmin(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmin, v),
    676            Self::Vmax(v) => (ViewportVariant::UADefault, ViewportUnit::Vmax, v),
    677            Self::Svmax(v) => (ViewportVariant::Small, ViewportUnit::Vmax, v),
    678            Self::Lvmax(v) => (ViewportVariant::Large, ViewportUnit::Vmax, v),
    679            Self::Dvmax(v) => (ViewportVariant::Dynamic, ViewportUnit::Vmax, v),
    680            Self::Vb(v) => (ViewportVariant::UADefault, ViewportUnit::Vb, v),
    681            Self::Svb(v) => (ViewportVariant::Small, ViewportUnit::Vb, v),
    682            Self::Lvb(v) => (ViewportVariant::Large, ViewportUnit::Vb, v),
    683            Self::Dvb(v) => (ViewportVariant::Dynamic, ViewportUnit::Vb, v),
    684            Self::Vi(v) => (ViewportVariant::UADefault, ViewportUnit::Vi, v),
    685            Self::Svi(v) => (ViewportVariant::Small, ViewportUnit::Vi, v),
    686            Self::Lvi(v) => (ViewportVariant::Large, ViewportUnit::Vi, v),
    687            Self::Dvi(v) => (ViewportVariant::Dynamic, ViewportUnit::Vi, v),
    688        }
    689    }
    690 
    691    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
    692    where
    693        O: Fn(f32, f32) -> f32,
    694    {
    695        use self::ViewportPercentageLength::*;
    696 
    697        if std::mem::discriminant(self) != std::mem::discriminant(other) {
    698            return Err(());
    699        }
    700 
    701        Ok(match (self, other) {
    702            (&Vw(one), &Vw(other)) => Vw(op(one, other)),
    703            (&Svw(one), &Svw(other)) => Svw(op(one, other)),
    704            (&Lvw(one), &Lvw(other)) => Lvw(op(one, other)),
    705            (&Dvw(one), &Dvw(other)) => Dvw(op(one, other)),
    706            (&Vh(one), &Vh(other)) => Vh(op(one, other)),
    707            (&Svh(one), &Svh(other)) => Svh(op(one, other)),
    708            (&Lvh(one), &Lvh(other)) => Lvh(op(one, other)),
    709            (&Dvh(one), &Dvh(other)) => Dvh(op(one, other)),
    710            (&Vmin(one), &Vmin(other)) => Vmin(op(one, other)),
    711            (&Svmin(one), &Svmin(other)) => Svmin(op(one, other)),
    712            (&Lvmin(one), &Lvmin(other)) => Lvmin(op(one, other)),
    713            (&Dvmin(one), &Dvmin(other)) => Dvmin(op(one, other)),
    714            (&Vmax(one), &Vmax(other)) => Vmax(op(one, other)),
    715            (&Svmax(one), &Svmax(other)) => Svmax(op(one, other)),
    716            (&Lvmax(one), &Lvmax(other)) => Lvmax(op(one, other)),
    717            (&Dvmax(one), &Dvmax(other)) => Dvmax(op(one, other)),
    718            (&Vb(one), &Vb(other)) => Vb(op(one, other)),
    719            (&Svb(one), &Svb(other)) => Svb(op(one, other)),
    720            (&Lvb(one), &Lvb(other)) => Lvb(op(one, other)),
    721            (&Dvb(one), &Dvb(other)) => Dvb(op(one, other)),
    722            (&Vi(one), &Vi(other)) => Vi(op(one, other)),
    723            (&Svi(one), &Svi(other)) => Svi(op(one, other)),
    724            (&Lvi(one), &Lvi(other)) => Lvi(op(one, other)),
    725            (&Dvi(one), &Dvi(other)) => Dvi(op(one, other)),
    726            // See https://github.com/rust-lang/rust/issues/68867. rustc isn't
    727            // able to figure it own on its own so we help.
    728            _ => unsafe {
    729                match *self {
    730                    Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) | Dvh(..)
    731                    | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) | Svmax(..)
    732                    | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) | Vi(..)
    733                    | Svi(..) | Lvi(..) | Dvi(..) => {},
    734                }
    735                debug_unreachable!("Forgot to handle unit in try_op()")
    736            },
    737        })
    738    }
    739 
    740    fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
    741        match self {
    742            Self::Vw(x) => Self::Vw(op(*x)),
    743            Self::Svw(x) => Self::Svw(op(*x)),
    744            Self::Lvw(x) => Self::Lvw(op(*x)),
    745            Self::Dvw(x) => Self::Dvw(op(*x)),
    746            Self::Vh(x) => Self::Vh(op(*x)),
    747            Self::Svh(x) => Self::Svh(op(*x)),
    748            Self::Lvh(x) => Self::Lvh(op(*x)),
    749            Self::Dvh(x) => Self::Dvh(op(*x)),
    750            Self::Vmin(x) => Self::Vmin(op(*x)),
    751            Self::Svmin(x) => Self::Svmin(op(*x)),
    752            Self::Lvmin(x) => Self::Lvmin(op(*x)),
    753            Self::Dvmin(x) => Self::Dvmin(op(*x)),
    754            Self::Vmax(x) => Self::Vmax(op(*x)),
    755            Self::Svmax(x) => Self::Svmax(op(*x)),
    756            Self::Lvmax(x) => Self::Lvmax(op(*x)),
    757            Self::Dvmax(x) => Self::Dvmax(op(*x)),
    758            Self::Vb(x) => Self::Vb(op(*x)),
    759            Self::Svb(x) => Self::Svb(op(*x)),
    760            Self::Lvb(x) => Self::Lvb(op(*x)),
    761            Self::Dvb(x) => Self::Dvb(op(*x)),
    762            Self::Vi(x) => Self::Vi(op(*x)),
    763            Self::Svi(x) => Self::Svi(op(*x)),
    764            Self::Lvi(x) => Self::Lvi(op(*x)),
    765            Self::Dvi(x) => Self::Dvi(op(*x)),
    766        }
    767    }
    768 
    769    /// Computes the given viewport-relative length for the given viewport size.
    770    pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
    771        let (variant, unit, factor) = self.unpack();
    772        let size = context.viewport_size_for_viewport_unit_resolution(variant);
    773        let length: app_units::Au = match unit {
    774            ViewportUnit::Vw => size.width,
    775            ViewportUnit::Vh => size.height,
    776            ViewportUnit::Vmin => cmp::min(size.width, size.height),
    777            ViewportUnit::Vmax => cmp::max(size.width, size.height),
    778            ViewportUnit::Vi | ViewportUnit::Vb => {
    779                context
    780                    .rule_cache_conditions
    781                    .borrow_mut()
    782                    .set_writing_mode_dependency(context.builder.writing_mode);
    783                if (unit == ViewportUnit::Vb) == context.style().writing_mode.is_vertical() {
    784                    size.width
    785                } else {
    786                    size.height
    787                }
    788            },
    789        };
    790 
    791        // NOTE: This is in app units!
    792        let length = context.builder.effective_zoom.zoom(length.0 as f32);
    793 
    794        // FIXME: Bug 1396535, we need to fix the extremely small viewport length for transform.
    795        // See bug 989802. We truncate so that adding multiple viewport units that add up to 100
    796        // does not overflow due to rounding differences. We convert appUnits to CSS px manually
    797        // here to avoid premature clamping by going through the Au type.
    798        let trunc_scaled =
    799            ((length as f64 * factor as f64 / 100.).trunc() / AU_PER_PX as f64) as f32;
    800        CSSPixelLength::new(crate::values::normalize(trunc_scaled))
    801    }
    802 }
    803 
    804 /// HTML5 "character width", as defined in HTML5 § 14.5.4.
    805 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
    806 #[repr(C)]
    807 pub struct CharacterWidth(pub i32);
    808 
    809 impl CharacterWidth {
    810    /// Computes the given character width.
    811    pub fn to_computed_value(&self, reference_font_size: computed::Length) -> computed::Length {
    812        // This applies the *converting a character width to pixels* algorithm
    813        // as specified in HTML5 § 14.5.4.
    814        //
    815        // TODO(pcwalton): Find these from the font.
    816        let average_advance = reference_font_size * 0.5;
    817        let max_advance = reference_font_size;
    818        (average_advance * (self.0 as CSSFloat - 1.0) + max_advance).finite()
    819    }
    820 }
    821 
    822 /// Represents an absolute length with its unit
    823 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
    824 #[repr(u8)]
    825 pub enum AbsoluteLength {
    826    /// An absolute length in pixels (px)
    827    #[css(dimension)]
    828    Px(CSSFloat),
    829    /// An absolute length in inches (in)
    830    #[css(dimension)]
    831    In(CSSFloat),
    832    /// An absolute length in centimeters (cm)
    833    #[css(dimension)]
    834    Cm(CSSFloat),
    835    /// An absolute length in millimeters (mm)
    836    #[css(dimension)]
    837    Mm(CSSFloat),
    838    /// An absolute length in quarter-millimeters (q)
    839    #[css(dimension)]
    840    Q(CSSFloat),
    841    /// An absolute length in points (pt)
    842    #[css(dimension)]
    843    Pt(CSSFloat),
    844    /// An absolute length in pica (pc)
    845    #[css(dimension)]
    846    Pc(CSSFloat),
    847 }
    848 
    849 impl AbsoluteLength {
    850    /// Return the unitless, raw value.
    851    fn unitless_value(&self) -> CSSFloat {
    852        match *self {
    853            Self::Px(v)
    854            | Self::In(v)
    855            | Self::Cm(v)
    856            | Self::Mm(v)
    857            | Self::Q(v)
    858            | Self::Pt(v)
    859            | Self::Pc(v) => v,
    860        }
    861    }
    862 
    863    // Return the unit, as a string.
    864    fn unit(&self) -> &'static str {
    865        match *self {
    866            Self::Px(_) => "px",
    867            Self::In(_) => "in",
    868            Self::Cm(_) => "cm",
    869            Self::Mm(_) => "mm",
    870            Self::Q(_) => "q",
    871            Self::Pt(_) => "pt",
    872            Self::Pc(_) => "pc",
    873        }
    874    }
    875 
    876    /// Convert this into a pixel value.
    877    #[inline]
    878    pub fn to_px(&self) -> CSSFloat {
    879        match *self {
    880            Self::Px(value) => value,
    881            Self::In(value) => value * PX_PER_IN,
    882            Self::Cm(value) => value * PX_PER_CM,
    883            Self::Mm(value) => value * PX_PER_MM,
    884            Self::Q(value) => value * PX_PER_Q,
    885            Self::Pt(value) => value * PX_PER_PT,
    886            Self::Pc(value) => value * PX_PER_PC,
    887        }
    888    }
    889 
    890    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
    891    where
    892        O: Fn(f32, f32) -> f32,
    893    {
    894        Ok(Self::Px(op(self.to_px(), other.to_px())))
    895    }
    896 
    897    fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
    898        Self::Px(op(self.to_px()))
    899    }
    900 }
    901 
    902 impl ToComputedValue for AbsoluteLength {
    903    type ComputedValue = CSSPixelLength;
    904 
    905    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
    906        CSSPixelLength::new(self.to_px())
    907            .zoom(context.builder.effective_zoom)
    908            .finite()
    909    }
    910 
    911    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
    912        Self::Px(computed.px())
    913    }
    914 }
    915 
    916 impl PartialOrd for AbsoluteLength {
    917    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
    918        self.to_px().partial_cmp(&other.to_px())
    919    }
    920 }
    921 
    922 /// A container query length.
    923 ///
    924 /// <https://drafts.csswg.org/css-contain-3/#container-lengths>
    925 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToShmem)]
    926 #[repr(u8)]
    927 pub enum ContainerRelativeLength {
    928    /// 1% of query container's width
    929    #[css(dimension)]
    930    Cqw(CSSFloat),
    931    /// 1% of query container's height
    932    #[css(dimension)]
    933    Cqh(CSSFloat),
    934    /// 1% of query container's inline size
    935    #[css(dimension)]
    936    Cqi(CSSFloat),
    937    /// 1% of query container's block size
    938    #[css(dimension)]
    939    Cqb(CSSFloat),
    940    /// The smaller value of `cqi` or `cqb`
    941    #[css(dimension)]
    942    Cqmin(CSSFloat),
    943    /// The larger value of `cqi` or `cqb`
    944    #[css(dimension)]
    945    Cqmax(CSSFloat),
    946 }
    947 
    948 impl ContainerRelativeLength {
    949    fn unitless_value(&self) -> CSSFloat {
    950        match *self {
    951            Self::Cqw(v)
    952            | Self::Cqh(v)
    953            | Self::Cqi(v)
    954            | Self::Cqb(v)
    955            | Self::Cqmin(v)
    956            | Self::Cqmax(v) => v,
    957        }
    958    }
    959 
    960    // Return the unit, as a string.
    961    fn unit(&self) -> &'static str {
    962        match *self {
    963            Self::Cqw(_) => "cqw",
    964            Self::Cqh(_) => "cqh",
    965            Self::Cqi(_) => "cqi",
    966            Self::Cqb(_) => "cqb",
    967            Self::Cqmin(_) => "cqmin",
    968            Self::Cqmax(_) => "cqmax",
    969        }
    970    }
    971 
    972    pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
    973    where
    974        O: Fn(f32, f32) -> f32,
    975    {
    976        use self::ContainerRelativeLength::*;
    977 
    978        if std::mem::discriminant(self) != std::mem::discriminant(other) {
    979            return Err(());
    980        }
    981 
    982        Ok(match (self, other) {
    983            (&Cqw(one), &Cqw(other)) => Cqw(op(one, other)),
    984            (&Cqh(one), &Cqh(other)) => Cqh(op(one, other)),
    985            (&Cqi(one), &Cqi(other)) => Cqi(op(one, other)),
    986            (&Cqb(one), &Cqb(other)) => Cqb(op(one, other)),
    987            (&Cqmin(one), &Cqmin(other)) => Cqmin(op(one, other)),
    988            (&Cqmax(one), &Cqmax(other)) => Cqmax(op(one, other)),
    989 
    990            // See https://github.com/rust-lang/rust/issues/68867, then
    991            // https://github.com/rust-lang/rust/pull/95161. rustc isn't
    992            // able to figure it own on its own so we help.
    993            _ => unsafe {
    994                match *self {
    995                    Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
    996                }
    997                debug_unreachable!("Forgot to handle unit in try_op()")
    998            },
    999        })
   1000    }
   1001 
   1002    pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
   1003        match self {
   1004            Self::Cqw(x) => Self::Cqw(op(*x)),
   1005            Self::Cqh(x) => Self::Cqh(op(*x)),
   1006            Self::Cqi(x) => Self::Cqi(op(*x)),
   1007            Self::Cqb(x) => Self::Cqb(op(*x)),
   1008            Self::Cqmin(x) => Self::Cqmin(op(*x)),
   1009            Self::Cqmax(x) => Self::Cqmax(op(*x)),
   1010        }
   1011    }
   1012 
   1013    /// Computes the given container-relative length.
   1014    pub fn to_computed_value(&self, context: &Context) -> CSSPixelLength {
   1015        if context.for_non_inherited_property {
   1016            context.rule_cache_conditions.borrow_mut().set_uncacheable();
   1017        }
   1018        context
   1019            .builder
   1020            .add_flags(ComputedValueFlags::USES_CONTAINER_UNITS);
   1021 
   1022        // TODO(emilio, bug 1894104): Need to handle zoom here, probably something like
   1023        // container_zoom - effective_zoom or so. See
   1024        // https://github.com/w3c/csswg-drafts/issues/10268
   1025        let size = context.get_container_size_query();
   1026        let (factor, container_length) = match *self {
   1027            Self::Cqw(v) => (v, size.get_container_width(context)),
   1028            Self::Cqh(v) => (v, size.get_container_height(context)),
   1029            Self::Cqi(v) => (v, size.get_container_inline_size(context)),
   1030            Self::Cqb(v) => (v, size.get_container_block_size(context)),
   1031            Self::Cqmin(v) => (
   1032                v,
   1033                cmp::min(
   1034                    size.get_container_inline_size(context),
   1035                    size.get_container_block_size(context),
   1036                ),
   1037            ),
   1038            Self::Cqmax(v) => (
   1039                v,
   1040                cmp::max(
   1041                    size.get_container_inline_size(context),
   1042                    size.get_container_block_size(context),
   1043                ),
   1044            ),
   1045        };
   1046        CSSPixelLength::new((container_length.to_f64_px() * factor as f64 / 100.0) as f32).finite()
   1047    }
   1048 }
   1049 
   1050 /// A `<length>` without taking `calc` expressions into account
   1051 ///
   1052 /// <https://drafts.csswg.org/css-values/#lengths>
   1053 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToShmem)]
   1054 #[repr(u8)]
   1055 pub enum NoCalcLength {
   1056    /// An absolute length
   1057    ///
   1058    /// <https://drafts.csswg.org/css-values/#absolute-length>
   1059    Absolute(AbsoluteLength),
   1060 
   1061    /// A font-relative length:
   1062    ///
   1063    /// <https://drafts.csswg.org/css-values/#font-relative-lengths>
   1064    FontRelative(FontRelativeLength),
   1065 
   1066    /// A viewport-relative length.
   1067    ///
   1068    /// <https://drafts.csswg.org/css-values/#viewport-relative-lengths>
   1069    ViewportPercentage(ViewportPercentageLength),
   1070 
   1071    /// A container query length.
   1072    ///
   1073    /// <https://drafts.csswg.org/css-contain-3/#container-lengths>
   1074    ContainerRelative(ContainerRelativeLength),
   1075    /// HTML5 "character width", as defined in HTML5 § 14.5.4.
   1076    ///
   1077    /// This cannot be specified by the user directly and is only generated by
   1078    /// `Stylist::synthesize_rules_for_legacy_attributes()`.
   1079    ServoCharacterWidth(CharacterWidth),
   1080 }
   1081 
   1082 impl NoCalcLength {
   1083    /// Return the unitless, raw value.
   1084    pub fn unitless_value(&self) -> CSSFloat {
   1085        match *self {
   1086            Self::Absolute(v) => v.unitless_value(),
   1087            Self::FontRelative(v) => v.unitless_value(),
   1088            Self::ViewportPercentage(v) => v.unitless_value(),
   1089            Self::ContainerRelative(v) => v.unitless_value(),
   1090            Self::ServoCharacterWidth(c) => c.0 as f32,
   1091        }
   1092    }
   1093 
   1094    // Return the unit, as a string.
   1095    fn unit(&self) -> &'static str {
   1096        match *self {
   1097            Self::Absolute(v) => v.unit(),
   1098            Self::FontRelative(v) => v.unit(),
   1099            Self::ViewportPercentage(v) => v.unit(),
   1100            Self::ContainerRelative(v) => v.unit(),
   1101            Self::ServoCharacterWidth(_) => "",
   1102        }
   1103    }
   1104 
   1105    /// Returns whether the value of this length without unit is less than zero.
   1106    pub fn is_negative(&self) -> bool {
   1107        self.unitless_value().is_sign_negative()
   1108    }
   1109 
   1110    /// Returns whether the value of this length without unit is equal to zero.
   1111    pub fn is_zero(&self) -> bool {
   1112        self.unitless_value() == 0.0
   1113    }
   1114 
   1115    /// Returns whether the value of this length without unit is infinite.
   1116    pub fn is_infinite(&self) -> bool {
   1117        self.unitless_value().is_infinite()
   1118    }
   1119 
   1120    /// Returns whether the value of this length without unit is NaN.
   1121    pub fn is_nan(&self) -> bool {
   1122        self.unitless_value().is_nan()
   1123    }
   1124 
   1125    /// Whether text-only zoom should be applied to this length.
   1126    ///
   1127    /// Generally, font-dependent/relative units don't get text-only-zoomed,
   1128    /// because the font they're relative to should be zoomed already.
   1129    pub fn should_zoom_text(&self) -> bool {
   1130        match *self {
   1131            Self::Absolute(..) | Self::ViewportPercentage(..) | Self::ContainerRelative(..) => true,
   1132            Self::ServoCharacterWidth(..) | Self::FontRelative(..) => false,
   1133        }
   1134    }
   1135 
   1136    /// Parse a given absolute or relative dimension.
   1137    pub fn parse_dimension(
   1138        context: &ParserContext,
   1139        value: CSSFloat,
   1140        unit: &str,
   1141    ) -> Result<Self, ()> {
   1142        Ok(match_ignore_ascii_case! { unit,
   1143            "px" => Self::Absolute(AbsoluteLength::Px(value)),
   1144            "in" => Self::Absolute(AbsoluteLength::In(value)),
   1145            "cm" => Self::Absolute(AbsoluteLength::Cm(value)),
   1146            "mm" => Self::Absolute(AbsoluteLength::Mm(value)),
   1147            "q" => Self::Absolute(AbsoluteLength::Q(value)),
   1148            "pt" => Self::Absolute(AbsoluteLength::Pt(value)),
   1149            "pc" => Self::Absolute(AbsoluteLength::Pc(value)),
   1150            // font-relative
   1151            "em" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Em(value)),
   1152            "ex" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ex(value)),
   1153            "rex" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rex(value)),
   1154            "ch" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ch(value)),
   1155            "rch" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rch(value)),
   1156            "cap" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Cap(value)),
   1157            "rcap" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rcap(value)),
   1158            "ic" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ic(value)),
   1159            "ric" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Ric(value)),
   1160            "rem" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rem(value)),
   1161            "lh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Lh(value)),
   1162            "rlh" if context.allows_computational_dependence() => Self::FontRelative(FontRelativeLength::Rlh(value)),
   1163            // viewport percentages
   1164            "vw" if !context.in_page_rule() => {
   1165                Self::ViewportPercentage(ViewportPercentageLength::Vw(value))
   1166            },
   1167            "svw" if !context.in_page_rule() => {
   1168                Self::ViewportPercentage(ViewportPercentageLength::Svw(value))
   1169            },
   1170            "lvw" if !context.in_page_rule() => {
   1171                Self::ViewportPercentage(ViewportPercentageLength::Lvw(value))
   1172            },
   1173            "dvw" if !context.in_page_rule() => {
   1174                Self::ViewportPercentage(ViewportPercentageLength::Dvw(value))
   1175            },
   1176            "vh" if !context.in_page_rule() => {
   1177                Self::ViewportPercentage(ViewportPercentageLength::Vh(value))
   1178            },
   1179            "svh" if !context.in_page_rule() => {
   1180                Self::ViewportPercentage(ViewportPercentageLength::Svh(value))
   1181            },
   1182            "lvh" if !context.in_page_rule() => {
   1183                Self::ViewportPercentage(ViewportPercentageLength::Lvh(value))
   1184            },
   1185            "dvh" if !context.in_page_rule() => {
   1186                Self::ViewportPercentage(ViewportPercentageLength::Dvh(value))
   1187            },
   1188            "vmin" if !context.in_page_rule() => {
   1189                Self::ViewportPercentage(ViewportPercentageLength::Vmin(value))
   1190            },
   1191            "svmin" if !context.in_page_rule() => {
   1192                Self::ViewportPercentage(ViewportPercentageLength::Svmin(value))
   1193            },
   1194            "lvmin" if !context.in_page_rule() => {
   1195                Self::ViewportPercentage(ViewportPercentageLength::Lvmin(value))
   1196            },
   1197            "dvmin" if !context.in_page_rule() => {
   1198                Self::ViewportPercentage(ViewportPercentageLength::Dvmin(value))
   1199            },
   1200            "vmax" if !context.in_page_rule() => {
   1201                Self::ViewportPercentage(ViewportPercentageLength::Vmax(value))
   1202            },
   1203            "svmax" if !context.in_page_rule() => {
   1204                Self::ViewportPercentage(ViewportPercentageLength::Svmax(value))
   1205            },
   1206            "lvmax" if !context.in_page_rule() => {
   1207                Self::ViewportPercentage(ViewportPercentageLength::Lvmax(value))
   1208            },
   1209            "dvmax" if !context.in_page_rule() => {
   1210                Self::ViewportPercentage(ViewportPercentageLength::Dvmax(value))
   1211            },
   1212            "vb" if !context.in_page_rule() => {
   1213                Self::ViewportPercentage(ViewportPercentageLength::Vb(value))
   1214            },
   1215            "svb" if !context.in_page_rule() => {
   1216                Self::ViewportPercentage(ViewportPercentageLength::Svb(value))
   1217            },
   1218            "lvb" if !context.in_page_rule() => {
   1219                Self::ViewportPercentage(ViewportPercentageLength::Lvb(value))
   1220            },
   1221            "dvb" if !context.in_page_rule() => {
   1222                Self::ViewportPercentage(ViewportPercentageLength::Dvb(value))
   1223            },
   1224            "vi" if !context.in_page_rule() => {
   1225                Self::ViewportPercentage(ViewportPercentageLength::Vi(value))
   1226            },
   1227            "svi" if !context.in_page_rule() => {
   1228                Self::ViewportPercentage(ViewportPercentageLength::Svi(value))
   1229            },
   1230            "lvi" if !context.in_page_rule() => {
   1231                Self::ViewportPercentage(ViewportPercentageLength::Lvi(value))
   1232            },
   1233            "dvi" if !context.in_page_rule() => {
   1234                Self::ViewportPercentage(ViewportPercentageLength::Dvi(value))
   1235            },
   1236            // Container query lengths. Inherit the limitation from viewport units since
   1237            // we may fall back to them.
   1238            "cqw" if !context.in_page_rule() && cfg!(feature = "gecko") => {
   1239                Self::ContainerRelative(ContainerRelativeLength::Cqw(value))
   1240            },
   1241            "cqh" if !context.in_page_rule() && cfg!(feature = "gecko") => {
   1242                Self::ContainerRelative(ContainerRelativeLength::Cqh(value))
   1243            },
   1244            "cqi" if !context.in_page_rule() && cfg!(feature = "gecko") => {
   1245                Self::ContainerRelative(ContainerRelativeLength::Cqi(value))
   1246            },
   1247            "cqb" if !context.in_page_rule() && cfg!(feature = "gecko") => {
   1248                Self::ContainerRelative(ContainerRelativeLength::Cqb(value))
   1249            },
   1250            "cqmin" if !context.in_page_rule() && cfg!(feature = "gecko") => {
   1251                Self::ContainerRelative(ContainerRelativeLength::Cqmin(value))
   1252            },
   1253            "cqmax" if !context.in_page_rule() && cfg!(feature = "gecko") => {
   1254                Self::ContainerRelative(ContainerRelativeLength::Cqmax(value))
   1255            },
   1256            _ => return Err(()),
   1257        })
   1258    }
   1259 
   1260    pub(crate) fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
   1261    where
   1262        O: Fn(f32, f32) -> f32,
   1263    {
   1264        use self::NoCalcLength::*;
   1265 
   1266        if std::mem::discriminant(self) != std::mem::discriminant(other) {
   1267            return Err(());
   1268        }
   1269 
   1270        Ok(match (self, other) {
   1271            (&Absolute(ref one), &Absolute(ref other)) => Absolute(one.try_op(other, op)?),
   1272            (&FontRelative(ref one), &FontRelative(ref other)) => {
   1273                FontRelative(one.try_op(other, op)?)
   1274            },
   1275            (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
   1276                ViewportPercentage(one.try_op(other, op)?)
   1277            },
   1278            (&ContainerRelative(ref one), &ContainerRelative(ref other)) => {
   1279                ContainerRelative(one.try_op(other, op)?)
   1280            },
   1281            (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
   1282                ServoCharacterWidth(CharacterWidth(op(one.0 as f32, other.0 as f32) as i32))
   1283            },
   1284            // See https://github.com/rust-lang/rust/issues/68867. rustc isn't
   1285            // able to figure it own on its own so we help.
   1286            _ => unsafe {
   1287                match *self {
   1288                    Absolute(..)
   1289                    | FontRelative(..)
   1290                    | ViewportPercentage(..)
   1291                    | ContainerRelative(..)
   1292                    | ServoCharacterWidth(..) => {},
   1293                }
   1294                debug_unreachable!("Forgot to handle unit in try_op()")
   1295            },
   1296        })
   1297    }
   1298 
   1299    pub(crate) fn map(&self, mut op: impl FnMut(f32) -> f32) -> Self {
   1300        use self::NoCalcLength::*;
   1301 
   1302        match self {
   1303            Absolute(ref one) => Absolute(one.map(op)),
   1304            FontRelative(ref one) => FontRelative(one.map(op)),
   1305            ViewportPercentage(ref one) => ViewportPercentage(one.map(op)),
   1306            ContainerRelative(ref one) => ContainerRelative(one.map(op)),
   1307            ServoCharacterWidth(ref one) => {
   1308                ServoCharacterWidth(CharacterWidth(op(one.0 as f32) as i32))
   1309            },
   1310        }
   1311    }
   1312 
   1313    /// Get a px value without context (so only absolute units can be handled).
   1314    #[inline]
   1315    pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
   1316        match *self {
   1317            Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
   1318            _ => Err(()),
   1319        }
   1320    }
   1321 
   1322    /// Get a px value without a full style context; this can handle either
   1323    /// absolute or (if a font metrics getter is provided) font-relative units.
   1324    #[cfg(feature = "gecko")]
   1325    #[inline]
   1326    pub fn to_computed_pixel_length_with_font_metrics(
   1327        &self,
   1328        get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
   1329    ) -> Result<CSSFloat, ()> {
   1330        match *self {
   1331            Self::Absolute(len) => Ok(CSSPixelLength::new(len.to_px()).finite().px()),
   1332            Self::FontRelative(fr) => {
   1333                if let Some(getter) = get_font_metrics {
   1334                    fr.to_computed_pixel_length_with_font_metrics(getter)
   1335                } else {
   1336                    Err(())
   1337                }
   1338            },
   1339            _ => Err(()),
   1340        }
   1341    }
   1342 
   1343    /// Get an absolute length from a px value.
   1344    #[inline]
   1345    pub fn from_px(px_value: CSSFloat) -> NoCalcLength {
   1346        NoCalcLength::Absolute(AbsoluteLength::Px(px_value))
   1347    }
   1348 }
   1349 
   1350 impl ToCss for NoCalcLength {
   1351    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
   1352    where
   1353        W: Write,
   1354    {
   1355        crate::values::serialize_specified_dimension(
   1356            self.unitless_value(),
   1357            self.unit(),
   1358            false,
   1359            dest,
   1360        )
   1361    }
   1362 }
   1363 
   1364 impl ToTyped for NoCalcLength {
   1365    fn to_typed(&self) -> Option<TypedValue> {
   1366        let value = self.unitless_value();
   1367        let unit = CssString::from(self.unit());
   1368        Some(TypedValue::Numeric(NumericValue::Unit { value, unit }))
   1369    }
   1370 }
   1371 
   1372 impl SpecifiedValueInfo for NoCalcLength {}
   1373 
   1374 impl PartialOrd for NoCalcLength {
   1375    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
   1376        use self::NoCalcLength::*;
   1377 
   1378        if std::mem::discriminant(self) != std::mem::discriminant(other) {
   1379            return None;
   1380        }
   1381 
   1382        match (self, other) {
   1383            (&Absolute(ref one), &Absolute(ref other)) => one.to_px().partial_cmp(&other.to_px()),
   1384            (&FontRelative(ref one), &FontRelative(ref other)) => one.partial_cmp(other),
   1385            (&ViewportPercentage(ref one), &ViewportPercentage(ref other)) => {
   1386                one.partial_cmp(other)
   1387            },
   1388            (&ContainerRelative(ref one), &ContainerRelative(ref other)) => one.partial_cmp(other),
   1389            (&ServoCharacterWidth(ref one), &ServoCharacterWidth(ref other)) => {
   1390                one.0.partial_cmp(&other.0)
   1391            },
   1392            // See https://github.com/rust-lang/rust/issues/68867. rustc isn't
   1393            // able to figure it own on its own so we help.
   1394            _ => unsafe {
   1395                match *self {
   1396                    Absolute(..)
   1397                    | FontRelative(..)
   1398                    | ViewportPercentage(..)
   1399                    | ContainerRelative(..)
   1400                    | ServoCharacterWidth(..) => {},
   1401                }
   1402                debug_unreachable!("Forgot an arm in partial_cmp?")
   1403            },
   1404        }
   1405    }
   1406 }
   1407 
   1408 impl Zero for NoCalcLength {
   1409    fn zero() -> Self {
   1410        NoCalcLength::Absolute(AbsoluteLength::Px(0.))
   1411    }
   1412 
   1413    fn is_zero(&self) -> bool {
   1414        NoCalcLength::is_zero(self)
   1415    }
   1416 }
   1417 
   1418 /// An extension to `NoCalcLength` to parse `calc` expressions.
   1419 /// This is commonly used for the `<length>` values.
   1420 ///
   1421 /// <https://drafts.csswg.org/css-values/#lengths>
   1422 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, ToTyped)]
   1423 #[typed_value(derive_fields)]
   1424 pub enum Length {
   1425    /// The internal length type that cannot parse `calc`
   1426    NoCalc(NoCalcLength),
   1427    /// A calc expression.
   1428    ///
   1429    /// <https://drafts.csswg.org/css-values/#calc-notation>
   1430    Calc(Box<CalcLengthPercentage>),
   1431 }
   1432 
   1433 impl From<NoCalcLength> for Length {
   1434    #[inline]
   1435    fn from(len: NoCalcLength) -> Self {
   1436        Length::NoCalc(len)
   1437    }
   1438 }
   1439 
   1440 impl PartialOrd for FontRelativeLength {
   1441    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
   1442        use self::FontRelativeLength::*;
   1443 
   1444        if std::mem::discriminant(self) != std::mem::discriminant(other) {
   1445            return None;
   1446        }
   1447 
   1448        match (self, other) {
   1449            (&Em(ref one), &Em(ref other)) => one.partial_cmp(other),
   1450            (&Ex(ref one), &Ex(ref other)) => one.partial_cmp(other),
   1451            (&Rex(ref one), &Rex(ref other)) => one.partial_cmp(other),
   1452            (&Ch(ref one), &Ch(ref other)) => one.partial_cmp(other),
   1453            (&Rch(ref one), &Rch(ref other)) => one.partial_cmp(other),
   1454            (&Cap(ref one), &Cap(ref other)) => one.partial_cmp(other),
   1455            (&Rcap(ref one), &Rcap(ref other)) => one.partial_cmp(other),
   1456            (&Ic(ref one), &Ic(ref other)) => one.partial_cmp(other),
   1457            (&Ric(ref one), &Ric(ref other)) => one.partial_cmp(other),
   1458            (&Rem(ref one), &Rem(ref other)) => one.partial_cmp(other),
   1459            (&Lh(ref one), &Lh(ref other)) => one.partial_cmp(other),
   1460            (&Rlh(ref one), &Rlh(ref other)) => one.partial_cmp(other),
   1461            // See https://github.com/rust-lang/rust/issues/68867. rustc isn't
   1462            // able to figure it own on its own so we help.
   1463            _ => unsafe {
   1464                match *self {
   1465                    Em(..) | Ex(..) | Rex(..) | Ch(..) | Rch(..) | Cap(..) | Rcap(..) | Ic(..)
   1466                    | Ric(..) | Rem(..) | Lh(..) | Rlh(..) => {},
   1467                }
   1468                debug_unreachable!("Forgot an arm in partial_cmp?")
   1469            },
   1470        }
   1471    }
   1472 }
   1473 
   1474 impl PartialOrd for ContainerRelativeLength {
   1475    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
   1476        use self::ContainerRelativeLength::*;
   1477 
   1478        if std::mem::discriminant(self) != std::mem::discriminant(other) {
   1479            return None;
   1480        }
   1481 
   1482        match (self, other) {
   1483            (&Cqw(ref one), &Cqw(ref other)) => one.partial_cmp(other),
   1484            (&Cqh(ref one), &Cqh(ref other)) => one.partial_cmp(other),
   1485            (&Cqi(ref one), &Cqi(ref other)) => one.partial_cmp(other),
   1486            (&Cqb(ref one), &Cqb(ref other)) => one.partial_cmp(other),
   1487            (&Cqmin(ref one), &Cqmin(ref other)) => one.partial_cmp(other),
   1488            (&Cqmax(ref one), &Cqmax(ref other)) => one.partial_cmp(other),
   1489 
   1490            // See https://github.com/rust-lang/rust/issues/68867, then
   1491            // https://github.com/rust-lang/rust/pull/95161. rustc isn't
   1492            // able to figure it own on its own so we help.
   1493            _ => unsafe {
   1494                match *self {
   1495                    Cqw(..) | Cqh(..) | Cqi(..) | Cqb(..) | Cqmin(..) | Cqmax(..) => {},
   1496                }
   1497                debug_unreachable!("Forgot to handle unit in partial_cmp()")
   1498            },
   1499        }
   1500    }
   1501 }
   1502 
   1503 impl PartialOrd for ViewportPercentageLength {
   1504    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
   1505        use self::ViewportPercentageLength::*;
   1506 
   1507        if std::mem::discriminant(self) != std::mem::discriminant(other) {
   1508            return None;
   1509        }
   1510 
   1511        match (self, other) {
   1512            (&Vw(ref one), &Vw(ref other)) => one.partial_cmp(other),
   1513            (&Svw(ref one), &Svw(ref other)) => one.partial_cmp(other),
   1514            (&Lvw(ref one), &Lvw(ref other)) => one.partial_cmp(other),
   1515            (&Dvw(ref one), &Dvw(ref other)) => one.partial_cmp(other),
   1516            (&Vh(ref one), &Vh(ref other)) => one.partial_cmp(other),
   1517            (&Svh(ref one), &Svh(ref other)) => one.partial_cmp(other),
   1518            (&Lvh(ref one), &Lvh(ref other)) => one.partial_cmp(other),
   1519            (&Dvh(ref one), &Dvh(ref other)) => one.partial_cmp(other),
   1520            (&Vmin(ref one), &Vmin(ref other)) => one.partial_cmp(other),
   1521            (&Svmin(ref one), &Svmin(ref other)) => one.partial_cmp(other),
   1522            (&Lvmin(ref one), &Lvmin(ref other)) => one.partial_cmp(other),
   1523            (&Dvmin(ref one), &Dvmin(ref other)) => one.partial_cmp(other),
   1524            (&Vmax(ref one), &Vmax(ref other)) => one.partial_cmp(other),
   1525            (&Svmax(ref one), &Svmax(ref other)) => one.partial_cmp(other),
   1526            (&Lvmax(ref one), &Lvmax(ref other)) => one.partial_cmp(other),
   1527            (&Dvmax(ref one), &Dvmax(ref other)) => one.partial_cmp(other),
   1528            (&Vb(ref one), &Vb(ref other)) => one.partial_cmp(other),
   1529            (&Svb(ref one), &Svb(ref other)) => one.partial_cmp(other),
   1530            (&Lvb(ref one), &Lvb(ref other)) => one.partial_cmp(other),
   1531            (&Dvb(ref one), &Dvb(ref other)) => one.partial_cmp(other),
   1532            (&Vi(ref one), &Vi(ref other)) => one.partial_cmp(other),
   1533            (&Svi(ref one), &Svi(ref other)) => one.partial_cmp(other),
   1534            (&Lvi(ref one), &Lvi(ref other)) => one.partial_cmp(other),
   1535            (&Dvi(ref one), &Dvi(ref other)) => one.partial_cmp(other),
   1536            // See https://github.com/rust-lang/rust/issues/68867. rustc isn't
   1537            // able to figure it own on its own so we help.
   1538            _ => unsafe {
   1539                match *self {
   1540                    Vw(..) | Svw(..) | Lvw(..) | Dvw(..) | Vh(..) | Svh(..) | Lvh(..) | Dvh(..)
   1541                    | Vmin(..) | Svmin(..) | Lvmin(..) | Dvmin(..) | Vmax(..) | Svmax(..)
   1542                    | Lvmax(..) | Dvmax(..) | Vb(..) | Svb(..) | Lvb(..) | Dvb(..) | Vi(..)
   1543                    | Svi(..) | Lvi(..) | Dvi(..) => {},
   1544                }
   1545                debug_unreachable!("Forgot an arm in partial_cmp?")
   1546            },
   1547        }
   1548    }
   1549 }
   1550 
   1551 impl Length {
   1552    #[inline]
   1553    fn parse_internal<'i, 't>(
   1554        context: &ParserContext,
   1555        input: &mut Parser<'i, 't>,
   1556        num_context: AllowedNumericType,
   1557        allow_quirks: AllowQuirks,
   1558    ) -> Result<Self, ParseError<'i>> {
   1559        let location = input.current_source_location();
   1560        let token = input.next()?;
   1561        match *token {
   1562            Token::Dimension {
   1563                value, ref unit, ..
   1564            } if num_context.is_ok(context.parsing_mode, value) => {
   1565                NoCalcLength::parse_dimension(context, value, unit)
   1566                    .map(Length::NoCalc)
   1567                    .map_err(|()| location.new_unexpected_token_error(token.clone()))
   1568            },
   1569            Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
   1570                if value != 0.
   1571                    && !context.parsing_mode.allows_unitless_lengths()
   1572                    && !allow_quirks.allowed(context.quirks_mode)
   1573                {
   1574                    return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
   1575                }
   1576                Ok(Length::NoCalc(NoCalcLength::Absolute(AbsoluteLength::Px(
   1577                    value,
   1578                ))))
   1579            },
   1580            Token::Function(ref name) => {
   1581                let function = CalcNode::math_function(context, name, location)?;
   1582                let calc = CalcNode::parse_length(context, input, num_context, function)?;
   1583                Ok(Length::Calc(Box::new(calc)))
   1584            },
   1585            ref token => return Err(location.new_unexpected_token_error(token.clone())),
   1586        }
   1587    }
   1588 
   1589    /// Parse a non-negative length
   1590    #[inline]
   1591    pub fn parse_non_negative<'i, 't>(
   1592        context: &ParserContext,
   1593        input: &mut Parser<'i, 't>,
   1594    ) -> Result<Self, ParseError<'i>> {
   1595        Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
   1596    }
   1597 
   1598    /// Parse a non-negative length, allowing quirks.
   1599    #[inline]
   1600    pub fn parse_non_negative_quirky<'i, 't>(
   1601        context: &ParserContext,
   1602        input: &mut Parser<'i, 't>,
   1603        allow_quirks: AllowQuirks,
   1604    ) -> Result<Self, ParseError<'i>> {
   1605        Self::parse_internal(
   1606            context,
   1607            input,
   1608            AllowedNumericType::NonNegative,
   1609            allow_quirks,
   1610        )
   1611    }
   1612 
   1613    /// Get an absolute length from a px value.
   1614    #[inline]
   1615    pub fn from_px(px_value: CSSFloat) -> Length {
   1616        Length::NoCalc(NoCalcLength::from_px(px_value))
   1617    }
   1618 
   1619    /// Get a px value without context.
   1620    pub fn to_computed_pixel_length_without_context(&self) -> Result<CSSFloat, ()> {
   1621        match *self {
   1622            Self::NoCalc(ref l) => l.to_computed_pixel_length_without_context(),
   1623            Self::Calc(ref l) => l.to_computed_pixel_length_without_context(),
   1624        }
   1625    }
   1626 
   1627    /// Get a px value, with an optional GeckoFontMetrics getter to resolve font-relative units.
   1628    #[cfg(feature = "gecko")]
   1629    pub fn to_computed_pixel_length_with_font_metrics(
   1630        &self,
   1631        get_font_metrics: Option<impl Fn() -> GeckoFontMetrics>,
   1632    ) -> Result<CSSFloat, ()> {
   1633        match *self {
   1634            Self::NoCalc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
   1635            Self::Calc(ref l) => l.to_computed_pixel_length_with_font_metrics(get_font_metrics),
   1636        }
   1637    }
   1638 }
   1639 
   1640 impl Parse for Length {
   1641    fn parse<'i, 't>(
   1642        context: &ParserContext,
   1643        input: &mut Parser<'i, 't>,
   1644    ) -> Result<Self, ParseError<'i>> {
   1645        Self::parse_quirky(context, input, AllowQuirks::No)
   1646    }
   1647 }
   1648 
   1649 impl Zero for Length {
   1650    fn zero() -> Self {
   1651        Length::NoCalc(NoCalcLength::zero())
   1652    }
   1653 
   1654    fn is_zero(&self) -> bool {
   1655        // FIXME(emilio): Seems a bit weird to treat calc() unconditionally as
   1656        // non-zero here?
   1657        match *self {
   1658            Length::NoCalc(ref l) => l.is_zero(),
   1659            Length::Calc(..) => false,
   1660        }
   1661    }
   1662 }
   1663 
   1664 impl Length {
   1665    /// Parses a length, with quirks.
   1666    pub fn parse_quirky<'i, 't>(
   1667        context: &ParserContext,
   1668        input: &mut Parser<'i, 't>,
   1669        allow_quirks: AllowQuirks,
   1670    ) -> Result<Self, ParseError<'i>> {
   1671        Self::parse_internal(context, input, AllowedNumericType::All, allow_quirks)
   1672    }
   1673 }
   1674 
   1675 /// A wrapper of Length, whose value must be >= 0.
   1676 pub type NonNegativeLength = NonNegative<Length>;
   1677 
   1678 impl Parse for NonNegativeLength {
   1679    #[inline]
   1680    fn parse<'i, 't>(
   1681        context: &ParserContext,
   1682        input: &mut Parser<'i, 't>,
   1683    ) -> Result<Self, ParseError<'i>> {
   1684        Ok(NonNegative(Length::parse_non_negative(context, input)?))
   1685    }
   1686 }
   1687 
   1688 impl From<NoCalcLength> for NonNegativeLength {
   1689    #[inline]
   1690    fn from(len: NoCalcLength) -> Self {
   1691        NonNegative(Length::NoCalc(len))
   1692    }
   1693 }
   1694 
   1695 impl From<Length> for NonNegativeLength {
   1696    #[inline]
   1697    fn from(len: Length) -> Self {
   1698        NonNegative(len)
   1699    }
   1700 }
   1701 
   1702 impl NonNegativeLength {
   1703    /// Get an absolute length from a px value.
   1704    #[inline]
   1705    pub fn from_px(px_value: CSSFloat) -> Self {
   1706        Length::from_px(px_value.max(0.)).into()
   1707    }
   1708 
   1709    /// Parses a non-negative length, optionally with quirks.
   1710    #[inline]
   1711    pub fn parse_quirky<'i, 't>(
   1712        context: &ParserContext,
   1713        input: &mut Parser<'i, 't>,
   1714        allow_quirks: AllowQuirks,
   1715    ) -> Result<Self, ParseError<'i>> {
   1716        Ok(NonNegative(Length::parse_non_negative_quirky(
   1717            context,
   1718            input,
   1719            allow_quirks,
   1720        )?))
   1721    }
   1722 }
   1723 
   1724 /// A `<length-percentage>` value. This can be either a `<length>`, a
   1725 /// `<percentage>`, or a combination of both via `calc()`.
   1726 ///
   1727 /// https://drafts.csswg.org/css-values-4/#typedef-length-percentage
   1728 #[allow(missing_docs)]
   1729 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem, ToTyped)]
   1730 pub enum LengthPercentage {
   1731    Length(NoCalcLength),
   1732    Percentage(computed::Percentage),
   1733    Calc(Box<CalcLengthPercentage>),
   1734 }
   1735 
   1736 impl From<Length> for LengthPercentage {
   1737    fn from(len: Length) -> LengthPercentage {
   1738        match len {
   1739            Length::NoCalc(l) => LengthPercentage::Length(l),
   1740            Length::Calc(l) => LengthPercentage::Calc(l),
   1741        }
   1742    }
   1743 }
   1744 
   1745 impl From<NoCalcLength> for LengthPercentage {
   1746    #[inline]
   1747    fn from(len: NoCalcLength) -> Self {
   1748        LengthPercentage::Length(len)
   1749    }
   1750 }
   1751 
   1752 impl From<Percentage> for LengthPercentage {
   1753    #[inline]
   1754    fn from(pc: Percentage) -> Self {
   1755        if let Some(clamping_mode) = pc.calc_clamping_mode() {
   1756            LengthPercentage::Calc(Box::new(CalcLengthPercentage {
   1757                clamping_mode,
   1758                node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())),
   1759            }))
   1760        } else {
   1761            LengthPercentage::Percentage(computed::Percentage(pc.get()))
   1762        }
   1763    }
   1764 }
   1765 
   1766 impl From<computed::Percentage> for LengthPercentage {
   1767    #[inline]
   1768    fn from(pc: computed::Percentage) -> Self {
   1769        LengthPercentage::Percentage(pc)
   1770    }
   1771 }
   1772 
   1773 impl Parse for LengthPercentage {
   1774    #[inline]
   1775    fn parse<'i, 't>(
   1776        context: &ParserContext,
   1777        input: &mut Parser<'i, 't>,
   1778    ) -> Result<Self, ParseError<'i>> {
   1779        Self::parse_quirky(context, input, AllowQuirks::No)
   1780    }
   1781 }
   1782 
   1783 impl LengthPercentage {
   1784    #[inline]
   1785    /// Returns a `0%` value.
   1786    pub fn zero_percent() -> LengthPercentage {
   1787        LengthPercentage::Percentage(computed::Percentage::zero())
   1788    }
   1789 
   1790    #[inline]
   1791    /// Returns a `100%` value.
   1792    pub fn hundred_percent() -> LengthPercentage {
   1793        LengthPercentage::Percentage(computed::Percentage::hundred())
   1794    }
   1795 
   1796    fn parse_internal<'i, 't>(
   1797        context: &ParserContext,
   1798        input: &mut Parser<'i, 't>,
   1799        num_context: AllowedNumericType,
   1800        allow_quirks: AllowQuirks,
   1801        allow_anchor: AllowAnchorPositioningFunctions,
   1802    ) -> Result<Self, ParseError<'i>> {
   1803        let location = input.current_source_location();
   1804        let token = input.next()?;
   1805        match *token {
   1806            Token::Dimension {
   1807                value, ref unit, ..
   1808            } if num_context.is_ok(context.parsing_mode, value) => {
   1809                return NoCalcLength::parse_dimension(context, value, unit)
   1810                    .map(LengthPercentage::Length)
   1811                    .map_err(|()| location.new_unexpected_token_error(token.clone()));
   1812            },
   1813            Token::Percentage { unit_value, .. }
   1814                if num_context.is_ok(context.parsing_mode, unit_value) =>
   1815            {
   1816                return Ok(LengthPercentage::Percentage(computed::Percentage(
   1817                    unit_value,
   1818                )));
   1819            },
   1820            Token::Number { value, .. } if num_context.is_ok(context.parsing_mode, value) => {
   1821                if value != 0.
   1822                    && !context.parsing_mode.allows_unitless_lengths()
   1823                    && !allow_quirks.allowed(context.quirks_mode)
   1824                {
   1825                    return Err(location.new_unexpected_token_error(token.clone()));
   1826                } else {
   1827                    return Ok(LengthPercentage::Length(NoCalcLength::from_px(value)));
   1828                }
   1829            },
   1830            Token::Function(ref name) => {
   1831                let function = CalcNode::math_function(context, name, location)?;
   1832                let calc = CalcNode::parse_length_or_percentage(
   1833                    context,
   1834                    input,
   1835                    num_context,
   1836                    function,
   1837                    allow_anchor,
   1838                )?;
   1839                Ok(LengthPercentage::Calc(Box::new(calc)))
   1840            },
   1841            _ => return Err(location.new_unexpected_token_error(token.clone())),
   1842        }
   1843    }
   1844 
   1845    /// Parses allowing the unitless length quirk.
   1846    /// <https://quirks.spec.whatwg.org/#the-unitless-length-quirk>
   1847    #[inline]
   1848    pub fn parse_quirky<'i, 't>(
   1849        context: &ParserContext,
   1850        input: &mut Parser<'i, 't>,
   1851        allow_quirks: AllowQuirks,
   1852    ) -> Result<Self, ParseError<'i>> {
   1853        Self::parse_internal(
   1854            context,
   1855            input,
   1856            AllowedNumericType::All,
   1857            allow_quirks,
   1858            AllowAnchorPositioningFunctions::No,
   1859        )
   1860    }
   1861 
   1862    /// Parses allowing the unitless length quirk, as well as allowing
   1863    /// anchor-positioning related function, `anchor-size()`.
   1864    #[inline]
   1865    fn parse_quirky_with_anchor_size_function<'i, 't>(
   1866        context: &ParserContext,
   1867        input: &mut Parser<'i, 't>,
   1868        allow_quirks: AllowQuirks,
   1869    ) -> Result<Self, ParseError<'i>> {
   1870        Self::parse_internal(
   1871            context,
   1872            input,
   1873            AllowedNumericType::All,
   1874            allow_quirks,
   1875            AllowAnchorPositioningFunctions::AllowAnchorSize,
   1876        )
   1877    }
   1878 
   1879    /// Parses allowing the unitless length quirk, as well as allowing
   1880    /// anchor-positioning related functions, `anchor()` and `anchor-size()`.
   1881    #[inline]
   1882    pub fn parse_quirky_with_anchor_functions<'i, 't>(
   1883        context: &ParserContext,
   1884        input: &mut Parser<'i, 't>,
   1885        allow_quirks: AllowQuirks,
   1886    ) -> Result<Self, ParseError<'i>> {
   1887        Self::parse_internal(
   1888            context,
   1889            input,
   1890            AllowedNumericType::All,
   1891            allow_quirks,
   1892            AllowAnchorPositioningFunctions::AllowAnchorAndAnchorSize,
   1893        )
   1894    }
   1895 
   1896    /// Parses non-negative length, allowing the unitless length quirk,
   1897    /// as well as allowing `anchor-size()`.
   1898    pub fn parse_non_negative_with_anchor_size<'i, 't>(
   1899        context: &ParserContext,
   1900        input: &mut Parser<'i, 't>,
   1901        allow_quirks: AllowQuirks,
   1902    ) -> Result<Self, ParseError<'i>> {
   1903        Self::parse_internal(
   1904            context,
   1905            input,
   1906            AllowedNumericType::NonNegative,
   1907            allow_quirks,
   1908            AllowAnchorPositioningFunctions::AllowAnchorSize,
   1909        )
   1910    }
   1911 
   1912    /// Parse a non-negative length.
   1913    ///
   1914    /// FIXME(emilio): This should be not public and we should use
   1915    /// NonNegativeLengthPercentage instead.
   1916    #[inline]
   1917    pub fn parse_non_negative<'i, 't>(
   1918        context: &ParserContext,
   1919        input: &mut Parser<'i, 't>,
   1920    ) -> Result<Self, ParseError<'i>> {
   1921        Self::parse_non_negative_quirky(context, input, AllowQuirks::No)
   1922    }
   1923 
   1924    /// Parse a non-negative length, with quirks.
   1925    #[inline]
   1926    pub fn parse_non_negative_quirky<'i, 't>(
   1927        context: &ParserContext,
   1928        input: &mut Parser<'i, 't>,
   1929        allow_quirks: AllowQuirks,
   1930    ) -> Result<Self, ParseError<'i>> {
   1931        Self::parse_internal(
   1932            context,
   1933            input,
   1934            AllowedNumericType::NonNegative,
   1935            allow_quirks,
   1936            AllowAnchorPositioningFunctions::No,
   1937        )
   1938    }
   1939 
   1940    /// Returns self as specified::calc::CalcNode.
   1941    /// Note that this expect the clamping_mode is AllowedNumericType::All for Calc. The caller
   1942    /// should take care about it when using this function.
   1943    fn to_calc_node(self) -> CalcNode {
   1944        match self {
   1945            LengthPercentage::Length(l) => CalcNode::Leaf(calc::Leaf::Length(l)),
   1946            LengthPercentage::Percentage(p) => CalcNode::Leaf(calc::Leaf::Percentage(p.0)),
   1947            LengthPercentage::Calc(p) => p.node,
   1948        }
   1949    }
   1950 
   1951    /// Construct the value representing `calc(100% - self)`.
   1952    pub fn hundred_percent_minus(self, clamping_mode: AllowedNumericType) -> Self {
   1953        let mut sum = smallvec::SmallVec::<[CalcNode; 2]>::new();
   1954        sum.push(CalcNode::Leaf(calc::Leaf::Percentage(1.0)));
   1955 
   1956        let mut node = self.to_calc_node();
   1957        node.negate();
   1958        sum.push(node);
   1959 
   1960        let calc = CalcNode::Sum(sum.into_boxed_slice().into());
   1961        LengthPercentage::Calc(Box::new(
   1962            calc.into_length_or_percentage(clamping_mode).unwrap(),
   1963        ))
   1964    }
   1965 }
   1966 
   1967 impl Zero for LengthPercentage {
   1968    fn zero() -> Self {
   1969        LengthPercentage::Length(NoCalcLength::zero())
   1970    }
   1971 
   1972    fn is_zero(&self) -> bool {
   1973        match *self {
   1974            LengthPercentage::Length(l) => l.is_zero(),
   1975            LengthPercentage::Percentage(p) => p.0 == 0.0,
   1976            LengthPercentage::Calc(_) => false,
   1977        }
   1978    }
   1979 }
   1980 
   1981 impl ZeroNoPercent for LengthPercentage {
   1982    fn is_zero_no_percent(&self) -> bool {
   1983        match *self {
   1984            LengthPercentage::Percentage(_) => false,
   1985            _ => self.is_zero(),
   1986        }
   1987    }
   1988 }
   1989 
   1990 /// A specified type for `<length-percentage> | auto`.
   1991 pub type LengthPercentageOrAuto = generics::LengthPercentageOrAuto<LengthPercentage>;
   1992 
   1993 impl LengthPercentageOrAuto {
   1994    /// Returns a value representing `0%`.
   1995    #[inline]
   1996    pub fn zero_percent() -> Self {
   1997        generics::LengthPercentageOrAuto::LengthPercentage(LengthPercentage::zero_percent())
   1998    }
   1999 
   2000    /// Parses a length or a percentage, allowing the unitless length quirk.
   2001    /// <https://quirks.spec.whatwg.org/#the-unitless-length-quirk>
   2002    #[inline]
   2003    pub fn parse_quirky<'i, 't>(
   2004        context: &ParserContext,
   2005        input: &mut Parser<'i, 't>,
   2006        allow_quirks: AllowQuirks,
   2007    ) -> Result<Self, ParseError<'i>> {
   2008        Self::parse_with(context, input, |context, input| {
   2009            LengthPercentage::parse_quirky(context, input, allow_quirks)
   2010        })
   2011    }
   2012 }
   2013 
   2014 /// A wrapper of LengthPercentageOrAuto, whose value must be >= 0.
   2015 pub type NonNegativeLengthPercentageOrAuto =
   2016    generics::LengthPercentageOrAuto<NonNegativeLengthPercentage>;
   2017 
   2018 impl NonNegativeLengthPercentageOrAuto {
   2019    /// Returns a value representing `0%`.
   2020    #[inline]
   2021    pub fn zero_percent() -> Self {
   2022        generics::LengthPercentageOrAuto::LengthPercentage(
   2023            NonNegativeLengthPercentage::zero_percent(),
   2024        )
   2025    }
   2026 
   2027    /// Parses a non-negative length-percentage, allowing the unitless length
   2028    /// quirk.
   2029    #[inline]
   2030    pub fn parse_quirky<'i, 't>(
   2031        context: &ParserContext,
   2032        input: &mut Parser<'i, 't>,
   2033        allow_quirks: AllowQuirks,
   2034    ) -> Result<Self, ParseError<'i>> {
   2035        Self::parse_with(context, input, |context, input| {
   2036            NonNegativeLengthPercentage::parse_quirky(context, input, allow_quirks)
   2037        })
   2038    }
   2039 }
   2040 
   2041 /// A wrapper of LengthPercentage, whose value must be >= 0.
   2042 pub type NonNegativeLengthPercentage = NonNegative<LengthPercentage>;
   2043 
   2044 /// Either a NonNegativeLengthPercentage or the `normal` keyword.
   2045 pub type NonNegativeLengthPercentageOrNormal =
   2046    GenericLengthPercentageOrNormal<NonNegativeLengthPercentage>;
   2047 
   2048 impl From<NoCalcLength> for NonNegativeLengthPercentage {
   2049    #[inline]
   2050    fn from(len: NoCalcLength) -> Self {
   2051        NonNegative(LengthPercentage::from(len))
   2052    }
   2053 }
   2054 
   2055 impl Parse for NonNegativeLengthPercentage {
   2056    #[inline]
   2057    fn parse<'i, 't>(
   2058        context: &ParserContext,
   2059        input: &mut Parser<'i, 't>,
   2060    ) -> Result<Self, ParseError<'i>> {
   2061        Self::parse_quirky(context, input, AllowQuirks::No)
   2062    }
   2063 }
   2064 
   2065 impl NonNegativeLengthPercentage {
   2066    #[inline]
   2067    /// Returns a `0%` value.
   2068    pub fn zero_percent() -> Self {
   2069        NonNegative(LengthPercentage::zero_percent())
   2070    }
   2071 
   2072    /// Parses a length or a percentage, allowing the unitless length quirk.
   2073    /// <https://quirks.spec.whatwg.org/#the-unitless-length-quirk>
   2074    #[inline]
   2075    pub fn parse_quirky<'i, 't>(
   2076        context: &ParserContext,
   2077        input: &mut Parser<'i, 't>,
   2078        allow_quirks: AllowQuirks,
   2079    ) -> Result<Self, ParseError<'i>> {
   2080        LengthPercentage::parse_non_negative_quirky(context, input, allow_quirks).map(NonNegative)
   2081    }
   2082 
   2083    /// Parses a length or a percentage, allowing the unitless length quirk,
   2084    /// as well as allowing `anchor-size()`.
   2085    #[inline]
   2086    pub fn parse_non_negative_with_anchor_size<'i, 't>(
   2087        context: &ParserContext,
   2088        input: &mut Parser<'i, 't>,
   2089        allow_quirks: AllowQuirks,
   2090    ) -> Result<Self, ParseError<'i>> {
   2091        LengthPercentage::parse_non_negative_with_anchor_size(context, input, allow_quirks)
   2092            .map(NonNegative)
   2093    }
   2094 }
   2095 
   2096 /// Either a `<length>` or the `auto` keyword.
   2097 ///
   2098 /// Note that we use LengthPercentage just for convenience, since it pretty much
   2099 /// is everything we care about, but we could just add a similar LengthOrAuto
   2100 /// instead if we think getting rid of this weirdness is worth it.
   2101 pub type LengthOrAuto = generics::LengthPercentageOrAuto<Length>;
   2102 
   2103 impl LengthOrAuto {
   2104    /// Parses a length, allowing the unitless length quirk.
   2105    /// <https://quirks.spec.whatwg.org/#the-unitless-length-quirk>
   2106    #[inline]
   2107    pub fn parse_quirky<'i, 't>(
   2108        context: &ParserContext,
   2109        input: &mut Parser<'i, 't>,
   2110        allow_quirks: AllowQuirks,
   2111    ) -> Result<Self, ParseError<'i>> {
   2112        Self::parse_with(context, input, |context, input| {
   2113            Length::parse_quirky(context, input, allow_quirks)
   2114        })
   2115    }
   2116 }
   2117 
   2118 /// Either a non-negative `<length>` or the `auto` keyword.
   2119 pub type NonNegativeLengthOrAuto = generics::LengthPercentageOrAuto<NonNegativeLength>;
   2120 
   2121 /// Either a `<length>` or a `<number>`.
   2122 pub type LengthOrNumber = GenericLengthOrNumber<Length, Number>;
   2123 
   2124 /// A specified value for `min-width`, `min-height`, `width` or `height` property.
   2125 pub type Size = GenericSize<NonNegativeLengthPercentage>;
   2126 
   2127 impl Parse for Size {
   2128    fn parse<'i, 't>(
   2129        context: &ParserContext,
   2130        input: &mut Parser<'i, 't>,
   2131    ) -> Result<Self, ParseError<'i>> {
   2132        Size::parse_quirky(context, input, AllowQuirks::No)
   2133    }
   2134 }
   2135 
   2136 macro_rules! parse_size_non_length {
   2137    ($size:ident, $input:expr, $allow_webkit_fill_available:expr,
   2138     $auto_or_none:expr => $auto_or_none_ident:ident) => {{
   2139        let size = $input.try_parse(|input| {
   2140            Ok(try_match_ident_ignore_ascii_case! { input,
   2141                "min-content" | "-moz-min-content" => $size::MinContent,
   2142                "max-content" | "-moz-max-content" => $size::MaxContent,
   2143                "fit-content" | "-moz-fit-content" => $size::FitContent,
   2144                #[cfg(feature = "gecko")]
   2145                "-moz-available" => $size::MozAvailable,
   2146                "-webkit-fill-available" if $allow_webkit_fill_available => $size::WebkitFillAvailable,
   2147                "stretch" if is_stretch_enabled() => $size::Stretch,
   2148                $auto_or_none => $size::$auto_or_none_ident,
   2149            })
   2150        });
   2151        if size.is_ok() {
   2152            return size;
   2153        }
   2154    }};
   2155 }
   2156 
   2157 fn is_webkit_fill_available_enabled_in_width_and_height() -> bool {
   2158    static_prefs::pref!("layout.css.webkit-fill-available.enabled")
   2159 }
   2160 
   2161 fn is_webkit_fill_available_enabled_in_all_size_properties() -> bool {
   2162    // For convenience at the callsites, we check both prefs here,
   2163    // since both must be 'true' in order for the keyword to be
   2164    // enabled in all size properties.
   2165    static_prefs::pref!("layout.css.webkit-fill-available.enabled")
   2166        && static_prefs::pref!("layout.css.webkit-fill-available.all-size-properties.enabled")
   2167 }
   2168 
   2169 fn is_stretch_enabled() -> bool {
   2170    static_prefs::pref!("layout.css.stretch-size-keyword.enabled")
   2171 }
   2172 
   2173 fn is_fit_content_function_enabled() -> bool {
   2174    static_prefs::pref!("layout.css.fit-content-function.enabled")
   2175 }
   2176 
   2177 macro_rules! parse_fit_content_function {
   2178    ($size:ident, $input:expr, $context:expr, $allow_quirks:expr) => {
   2179        if is_fit_content_function_enabled() {
   2180            if let Ok(length) = $input.try_parse(|input| {
   2181                input.expect_function_matching("fit-content")?;
   2182                input.parse_nested_block(|i| {
   2183                    NonNegativeLengthPercentage::parse_quirky($context, i, $allow_quirks)
   2184                })
   2185            }) {
   2186                return Ok($size::FitContentFunction(length));
   2187            }
   2188        }
   2189    };
   2190 }
   2191 
   2192 #[derive(Clone, Copy, PartialEq, Eq)]
   2193 enum ParseAnchorFunctions {
   2194    Yes,
   2195    No,
   2196 }
   2197 
   2198 impl Size {
   2199    /// Parses, with quirks.
   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        let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_all_size_properties();
   2206        Self::parse_quirky_internal(
   2207            context,
   2208            input,
   2209            allow_quirks,
   2210            allow_webkit_fill_available,
   2211            ParseAnchorFunctions::Yes,
   2212        )
   2213    }
   2214 
   2215    /// Parses for flex-basis: <width>
   2216    pub fn parse_size_for_flex_basis_width<'i, 't>(
   2217        context: &ParserContext,
   2218        input: &mut Parser<'i, 't>,
   2219    ) -> Result<Self, ParseError<'i>> {
   2220        Self::parse_quirky_internal(
   2221            context,
   2222            input,
   2223            AllowQuirks::No,
   2224            true,
   2225            ParseAnchorFunctions::No,
   2226        )
   2227    }
   2228 
   2229    /// Parses, with quirks and configurable support for
   2230    /// whether the '-webkit-fill-available' keyword is allowed.
   2231    /// TODO(dholbert) Fold this function into callsites in bug 1989073 when
   2232    /// removing 'layout.css.webkit-fill-available.all-size-properties.enabled'.
   2233    fn parse_quirky_internal<'i, 't>(
   2234        context: &ParserContext,
   2235        input: &mut Parser<'i, 't>,
   2236        allow_quirks: AllowQuirks,
   2237        allow_webkit_fill_available: bool,
   2238        allow_anchor_functions: ParseAnchorFunctions,
   2239    ) -> Result<Self, ParseError<'i>> {
   2240        parse_size_non_length!(Size, input, allow_webkit_fill_available,
   2241                               "auto" => Auto);
   2242        parse_fit_content_function!(Size, input, context, allow_quirks);
   2243 
   2244        let allow_anchor = allow_anchor_functions == ParseAnchorFunctions::Yes
   2245            && static_prefs::pref!("layout.css.anchor-positioning.enabled");
   2246        match input
   2247            .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
   2248        {
   2249            Ok(length) => return Ok(GenericSize::LengthPercentage(length)),
   2250            Err(e) if !allow_anchor => return Err(e.into()),
   2251            Err(_) => (),
   2252        };
   2253        if let Ok(length) = input.try_parse(|i| {
   2254            NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
   2255                context,
   2256                i,
   2257                allow_quirks,
   2258            )
   2259        }) {
   2260            return Ok(GenericSize::AnchorContainingCalcFunction(length));
   2261        }
   2262        Ok(Self::AnchorSizeFunction(Box::new(
   2263            GenericAnchorSizeFunction::parse(context, input)?,
   2264        )))
   2265    }
   2266 
   2267    /// Parse a size for width or height, where -webkit-fill-available
   2268    /// support is only controlled by one pref (vs. other properties where
   2269    /// there's an additional pref check):
   2270    /// TODO(dholbert) Remove this custom parse func in bug 1989073, along with
   2271    /// 'layout.css.webkit-fill-available.all-size-properties.enabled'.
   2272    pub fn parse_size_for_width_or_height_quirky<'i, 't>(
   2273        context: &ParserContext,
   2274        input: &mut Parser<'i, 't>,
   2275        allow_quirks: AllowQuirks,
   2276    ) -> Result<Self, ParseError<'i>> {
   2277        let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_width_and_height();
   2278        Self::parse_quirky_internal(
   2279            context,
   2280            input,
   2281            allow_quirks,
   2282            allow_webkit_fill_available,
   2283            ParseAnchorFunctions::Yes,
   2284        )
   2285    }
   2286 
   2287    /// Parse a size for width or height, where -webkit-fill-available
   2288    /// support is only controlled by one pref (vs. other properties where
   2289    /// there's an additional pref check):
   2290    /// TODO(dholbert) Remove this custom parse func in bug 1989073, along with
   2291    /// 'layout.css.webkit-fill-available.all-size-properties.enabled'.
   2292    pub fn parse_size_for_width_or_height<'i, 't>(
   2293        context: &ParserContext,
   2294        input: &mut Parser<'i, 't>,
   2295    ) -> Result<Self, ParseError<'i>> {
   2296        let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_width_and_height();
   2297        Self::parse_quirky_internal(
   2298            context,
   2299            input,
   2300            AllowQuirks::No,
   2301            allow_webkit_fill_available,
   2302            ParseAnchorFunctions::Yes,
   2303        )
   2304    }
   2305 
   2306    /// Returns `0%`.
   2307    #[inline]
   2308    pub fn zero_percent() -> Self {
   2309        GenericSize::LengthPercentage(NonNegativeLengthPercentage::zero_percent())
   2310    }
   2311 }
   2312 
   2313 /// A specified value for `max-width` or `max-height` property.
   2314 pub type MaxSize = GenericMaxSize<NonNegativeLengthPercentage>;
   2315 
   2316 impl Parse for MaxSize {
   2317    fn parse<'i, 't>(
   2318        context: &ParserContext,
   2319        input: &mut Parser<'i, 't>,
   2320    ) -> Result<Self, ParseError<'i>> {
   2321        MaxSize::parse_quirky(context, input, AllowQuirks::No)
   2322    }
   2323 }
   2324 
   2325 impl MaxSize {
   2326    /// Parses, with quirks.
   2327    pub fn parse_quirky<'i, 't>(
   2328        context: &ParserContext,
   2329        input: &mut Parser<'i, 't>,
   2330        allow_quirks: AllowQuirks,
   2331    ) -> Result<Self, ParseError<'i>> {
   2332        let allow_webkit_fill_available = is_webkit_fill_available_enabled_in_all_size_properties();
   2333        parse_size_non_length!(MaxSize, input, allow_webkit_fill_available,
   2334                               "none" => None);
   2335        parse_fit_content_function!(MaxSize, input, context, allow_quirks);
   2336 
   2337        match input
   2338            .try_parse(|i| NonNegativeLengthPercentage::parse_quirky(context, i, allow_quirks))
   2339        {
   2340            Ok(length) => return Ok(GenericMaxSize::LengthPercentage(length)),
   2341            Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
   2342                return Err(e.into())
   2343            },
   2344            Err(_) => (),
   2345        };
   2346        if let Ok(length) = input.try_parse(|i| {
   2347            NonNegativeLengthPercentage::parse_non_negative_with_anchor_size(
   2348                context,
   2349                i,
   2350                allow_quirks,
   2351            )
   2352        }) {
   2353            return Ok(GenericMaxSize::AnchorContainingCalcFunction(length));
   2354        }
   2355        Ok(Self::AnchorSizeFunction(Box::new(
   2356            GenericAnchorSizeFunction::parse(context, input)?,
   2357        )))
   2358    }
   2359 }
   2360 
   2361 /// A specified non-negative `<length>` | `<number>`.
   2362 pub type NonNegativeLengthOrNumber = GenericLengthOrNumber<NonNegativeLength, NonNegativeNumber>;
   2363 
   2364 /// A specified value for `margin` properties.
   2365 pub type Margin = GenericMargin<LengthPercentage>;
   2366 
   2367 impl Margin {
   2368    /// Parses a margin type, allowing the unitless length quirk.
   2369    /// <https://quirks.spec.whatwg.org/#the-unitless-length-quirk>
   2370    #[inline]
   2371    pub fn parse_quirky<'i, 't>(
   2372        context: &ParserContext,
   2373        input: &mut Parser<'i, 't>,
   2374        allow_quirks: AllowQuirks,
   2375    ) -> Result<Self, ParseError<'i>> {
   2376        if let Ok(l) = input.try_parse(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
   2377        {
   2378            return Ok(Self::LengthPercentage(l));
   2379        }
   2380        match input.try_parse(|i| i.expect_ident_matching("auto")) {
   2381            Ok(_) => return Ok(Self::Auto),
   2382            Err(e) if !static_prefs::pref!("layout.css.anchor-positioning.enabled") => {
   2383                return Err(e.into())
   2384            },
   2385            Err(_) => (),
   2386        };
   2387        if let Ok(l) = input.try_parse(|i| {
   2388            LengthPercentage::parse_quirky_with_anchor_size_function(context, i, allow_quirks)
   2389        }) {
   2390            return Ok(Self::AnchorContainingCalcFunction(l));
   2391        }
   2392        let inner = GenericAnchorSizeFunction::<Margin>::parse(context, input)?;
   2393        Ok(Self::AnchorSizeFunction(Box::new(inner)))
   2394    }
   2395 }
   2396 
   2397 impl Parse for Margin {
   2398    fn parse<'i, 't>(
   2399        context: &ParserContext,
   2400        input: &mut Parser<'i, 't>,
   2401    ) -> Result<Self, ParseError<'i>> {
   2402        Self::parse_quirky(context, input, AllowQuirks::No)
   2403    }
   2404 }