tor-browser

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

calc.rs (74784B)


      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 //! [Calc expressions][calc].
      6 //!
      7 //! [calc]: https://drafts.csswg.org/css-values/#calc-notation
      8 
      9 use crate::derives::*;
     10 use crate::values::generics::length::GenericAnchorSizeFunction;
     11 use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide};
     12 use num_traits::Zero;
     13 use smallvec::SmallVec;
     14 use std::convert::AsRef;
     15 use std::fmt::{self, Write};
     16 use std::ops::{Add, Mul, Neg, Rem, Sub};
     17 use std::{cmp, mem};
     18 use strum_macros::AsRefStr;
     19 use style_traits::{CssWriter, NumericValue, ToCss, ToTyped, TypedValue};
     20 
     21 use thin_vec::ThinVec;
     22 
     23 /// Whether we're a `min` or `max` function.
     24 #[derive(
     25    Clone,
     26    Copy,
     27    Debug,
     28    Deserialize,
     29    MallocSizeOf,
     30    PartialEq,
     31    Serialize,
     32    ToAnimatedZero,
     33    ToResolvedValue,
     34    ToShmem,
     35 )]
     36 #[repr(u8)]
     37 pub enum MinMaxOp {
     38    /// `min()`
     39    Min,
     40    /// `max()`
     41    Max,
     42 }
     43 
     44 /// Whether we're a `mod` or `rem` function.
     45 #[derive(
     46    Clone,
     47    Copy,
     48    Debug,
     49    Deserialize,
     50    MallocSizeOf,
     51    PartialEq,
     52    Serialize,
     53    ToAnimatedZero,
     54    ToResolvedValue,
     55    ToShmem,
     56 )]
     57 #[repr(u8)]
     58 pub enum ModRemOp {
     59    /// `mod()`
     60    Mod,
     61    /// `rem()`
     62    Rem,
     63 }
     64 
     65 impl ModRemOp {
     66    fn apply(self, dividend: f32, divisor: f32) -> f32 {
     67        // In mod(A, B) only, if B is infinite and A has opposite sign to B
     68        // (including an oppositely-signed zero), the result is NaN.
     69        // https://drafts.csswg.org/css-values/#round-infinities
     70        if matches!(self, Self::Mod)
     71            && divisor.is_infinite()
     72            && dividend.is_sign_negative() != divisor.is_sign_negative()
     73        {
     74            return f32::NAN;
     75        }
     76 
     77        let (r, same_sign_as) = match self {
     78            Self::Mod => (dividend - divisor * (dividend / divisor).floor(), divisor),
     79            Self::Rem => (dividend - divisor * (dividend / divisor).trunc(), dividend),
     80        };
     81        if r == 0.0 && same_sign_as.is_sign_negative() {
     82            -0.0
     83        } else {
     84            r
     85        }
     86    }
     87 }
     88 
     89 /// The strategy used in `round()`
     90 #[derive(
     91    Clone,
     92    Copy,
     93    Debug,
     94    Deserialize,
     95    MallocSizeOf,
     96    PartialEq,
     97    Serialize,
     98    ToAnimatedZero,
     99    ToResolvedValue,
    100    ToShmem,
    101 )]
    102 #[repr(u8)]
    103 pub enum RoundingStrategy {
    104    /// `round(nearest, a, b)`
    105    /// round a to the nearest multiple of b
    106    Nearest,
    107    /// `round(up, a, b)`
    108    /// round a up to the nearest multiple of b
    109    Up,
    110    /// `round(down, a, b)`
    111    /// round a down to the nearest multiple of b
    112    Down,
    113    /// `round(to-zero, a, b)`
    114    /// round a to the nearest multiple of b that is towards zero
    115    ToZero,
    116 }
    117 
    118 /// This determines the order in which we serialize members of a calc() sum.
    119 ///
    120 /// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children
    121 #[derive(
    122    AsRefStr, Clone, Copy, Debug, Eq, Ord, Parse, PartialEq, PartialOrd, MallocSizeOf, ToShmem,
    123 )]
    124 #[strum(serialize_all = "lowercase")]
    125 #[allow(missing_docs)]
    126 pub enum SortKey {
    127    #[strum(serialize = "")]
    128    Number,
    129    #[css(skip)]
    130    #[strum(serialize = "%")]
    131    Percentage,
    132    Cap,
    133    Ch,
    134    Cqb,
    135    Cqh,
    136    Cqi,
    137    Cqmax,
    138    Cqmin,
    139    Cqw,
    140    Deg,
    141    Dppx,
    142    Dvb,
    143    Dvh,
    144    Dvi,
    145    Dvmax,
    146    Dvmin,
    147    Dvw,
    148    Em,
    149    Ex,
    150    Ic,
    151    Lh,
    152    Lvb,
    153    Lvh,
    154    Lvi,
    155    Lvmax,
    156    Lvmin,
    157    Lvw,
    158    Ms,
    159    Px,
    160    Rcap,
    161    Rch,
    162    Rem,
    163    Rex,
    164    Ric,
    165    Rlh,
    166    S, // Sec
    167    Svb,
    168    Svh,
    169    Svi,
    170    Svmax,
    171    Svmin,
    172    Svw,
    173    Vb,
    174    Vh,
    175    Vi,
    176    Vmax,
    177    Vmin,
    178    Vw,
    179    #[css(skip)]
    180    ColorComponent,
    181    #[css(skip)]
    182    Other,
    183 }
    184 
    185 /// `anchor()` function used in math functions.
    186 pub type GenericCalcAnchorFunction<L> =
    187    GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericCalcNode<L>>>;
    188 /// `anchor-size()` function used in math functions.
    189 pub type GenericCalcAnchorSizeFunction<L> = GenericAnchorSizeFunction<Box<GenericCalcNode<L>>>;
    190 
    191 /// A generic node in a calc expression.
    192 ///
    193 /// FIXME: This would be much more elegant if we used `Self` in the types below,
    194 /// but we can't because of https://github.com/serde-rs/serde/issues/1565.
    195 ///
    196 /// FIXME: The following annotations are to workaround an LLVM inlining bug, see
    197 /// bug 1631929.
    198 ///
    199 /// cbindgen:destructor-attributes=MOZ_NEVER_INLINE
    200 /// cbindgen:copy-constructor-attributes=MOZ_NEVER_INLINE
    201 /// cbindgen:eq-attributes=MOZ_NEVER_INLINE
    202 #[repr(u8)]
    203 #[derive(
    204    Clone,
    205    Debug,
    206    Deserialize,
    207    MallocSizeOf,
    208    PartialEq,
    209    Serialize,
    210    ToAnimatedZero,
    211    ToResolvedValue,
    212    ToShmem,
    213 )]
    214 pub enum GenericCalcNode<L> {
    215    /// A leaf node.
    216    Leaf(L),
    217    /// A node that negates its child, e.g. Negate(1) == -1.
    218    Negate(Box<GenericCalcNode<L>>),
    219    /// A node that inverts its child, e.g. Invert(10) == 1 / 10 == 0.1. The child must always
    220    /// resolve to a number unit.
    221    Invert(Box<GenericCalcNode<L>>),
    222    /// A sum node, representing `a + b + c` where a, b, and c are the
    223    /// arguments.
    224    Sum(crate::OwnedSlice<GenericCalcNode<L>>),
    225    /// A product node, representing `a * b * c` where a, b, and c are the
    226    /// arguments.
    227    Product(crate::OwnedSlice<GenericCalcNode<L>>),
    228    /// A `min` or `max` function.
    229    MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp),
    230    /// A `clamp()` function.
    231    Clamp {
    232        /// The minimum value.
    233        min: Box<GenericCalcNode<L>>,
    234        /// The central value.
    235        center: Box<GenericCalcNode<L>>,
    236        /// The maximum value.
    237        max: Box<GenericCalcNode<L>>,
    238    },
    239    /// A `round()` function.
    240    Round {
    241        /// The rounding strategy.
    242        strategy: RoundingStrategy,
    243        /// The value to round.
    244        value: Box<GenericCalcNode<L>>,
    245        /// The step value.
    246        step: Box<GenericCalcNode<L>>,
    247    },
    248    /// A `mod()` or `rem()` function.
    249    ModRem {
    250        /// The dividend calculation.
    251        dividend: Box<GenericCalcNode<L>>,
    252        /// The divisor calculation.
    253        divisor: Box<GenericCalcNode<L>>,
    254        /// Is the function mod or rem?
    255        op: ModRemOp,
    256    },
    257    /// A `hypot()` function
    258    Hypot(crate::OwnedSlice<GenericCalcNode<L>>),
    259    /// An `abs()` function.
    260    Abs(Box<GenericCalcNode<L>>),
    261    /// A `sign()` function.
    262    Sign(Box<GenericCalcNode<L>>),
    263    /// An `anchor()` function.
    264    Anchor(Box<GenericCalcAnchorFunction<L>>),
    265    /// An `anchor-size()` function.
    266    AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>),
    267 }
    268 
    269 pub use self::GenericCalcNode as CalcNode;
    270 
    271 bitflags! {
    272    /// Expected units we allow parsing within a `calc()` expression.
    273    ///
    274    /// This is used as a hint for the parser to fast-reject invalid
    275    /// expressions. Numbers are always allowed because they multiply other
    276    /// units.
    277    #[derive(Clone, Copy, PartialEq, Eq)]
    278    pub struct CalcUnits: u8 {
    279        /// <length>
    280        const LENGTH = 1 << 0;
    281        /// <percentage>
    282        const PERCENTAGE = 1 << 1;
    283        /// <angle>
    284        const ANGLE = 1 << 2;
    285        /// <time>
    286        const TIME = 1 << 3;
    287        /// <resolution>
    288        const RESOLUTION = 1 << 4;
    289        /// A component of a color (r, g, b, h, s, l, alpha, etc.)
    290        const COLOR_COMPONENT = 1 << 5;
    291 
    292        /// <length-percentage>
    293        const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits();
    294        // NOTE: When you add to this, make sure to make Atan2 deal with these.
    295        /// Allow all units.
    296        const ALL = Self::LENGTH.bits() | Self::PERCENTAGE.bits() | Self::ANGLE.bits() |
    297            Self::TIME.bits() | Self::RESOLUTION.bits() | Self::COLOR_COMPONENT.bits();
    298    }
    299 }
    300 
    301 impl CalcUnits {
    302    /// Returns whether the flags only represent a single unit. This will return true for 0, which
    303    /// is a "number" this is also fine.
    304    #[inline]
    305    fn is_single_unit(&self) -> bool {
    306        self.bits() == 0 || self.bits() & (self.bits() - 1) == 0
    307    }
    308 
    309    /// Returns true if this unit is allowed to be summed with the given unit, otherwise false.
    310    #[inline]
    311    fn can_sum_with(&self, other: Self) -> bool {
    312        match *self {
    313            Self::LENGTH => other.intersects(Self::LENGTH | Self::PERCENTAGE),
    314            Self::PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
    315            Self::LENGTH_PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
    316            u => u.is_single_unit() && other == u,
    317        }
    318    }
    319 }
    320 
    321 /// For percentage resolution, sometimes we can't assume that the percentage basis is positive (so
    322 /// we don't know whether a percentage is larger than another).
    323 pub enum PositivePercentageBasis {
    324    /// The percent basis is not known-positive, we can't compare percentages.
    325    Unknown,
    326    /// The percent basis is known-positive, we assume larger percentages are larger.
    327    Yes,
    328 }
    329 
    330 macro_rules! compare_helpers {
    331    () => {
    332        /// Return whether a leaf is greater than another.
    333        #[allow(unused)]
    334        fn gt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
    335            self.compare(other, basis_positive) == Some(cmp::Ordering::Greater)
    336        }
    337 
    338        /// Return whether a leaf is less than another.
    339        fn lt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
    340            self.compare(other, basis_positive) == Some(cmp::Ordering::Less)
    341        }
    342 
    343        /// Return whether a leaf is smaller or equal than another.
    344        fn lte(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
    345            match self.compare(other, basis_positive) {
    346                Some(cmp::Ordering::Less) => true,
    347                Some(cmp::Ordering::Equal) => true,
    348                Some(cmp::Ordering::Greater) => false,
    349                None => false,
    350            }
    351        }
    352    };
    353 }
    354 
    355 /// A trait that represents all the stuff a valid leaf of a calc expression.
    356 pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss + ToTyped {
    357    /// Returns the unit of the leaf.
    358    fn unit(&self) -> CalcUnits;
    359 
    360    /// Returns the unitless value of this leaf if one is available.
    361    fn unitless_value(&self) -> Option<f32>;
    362 
    363    /// Return true if the units of both leaves are equal. (NOTE: Does not take
    364    /// the values into account)
    365    fn is_same_unit_as(&self, other: &Self) -> bool {
    366        std::mem::discriminant(self) == std::mem::discriminant(other)
    367    }
    368 
    369    /// Do a partial comparison of these values.
    370    fn compare(
    371        &self,
    372        other: &Self,
    373        base_is_positive: PositivePercentageBasis,
    374    ) -> Option<cmp::Ordering>;
    375    compare_helpers!();
    376 
    377    /// Create a new leaf with a number value.
    378    fn new_number(value: f32) -> Self;
    379 
    380    /// Returns a float value if the leaf is a number.
    381    fn as_number(&self) -> Option<f32>;
    382 
    383    /// Whether this value is known-negative.
    384    fn is_negative(&self) -> Result<bool, ()> {
    385        self.unitless_value()
    386            .map(|v| Ok(v.is_sign_negative()))
    387            .unwrap_or_else(|| Err(()))
    388    }
    389 
    390    /// Whether this value is infinite.
    391    fn is_infinite(&self) -> Result<bool, ()> {
    392        self.unitless_value()
    393            .map(|v| Ok(v.is_infinite()))
    394            .unwrap_or_else(|| Err(()))
    395    }
    396 
    397    /// Whether this value is zero.
    398    fn is_zero(&self) -> Result<bool, ()> {
    399        self.unitless_value()
    400            .map(|v| Ok(v.is_zero()))
    401            .unwrap_or_else(|| Err(()))
    402    }
    403 
    404    /// Whether this value is NaN.
    405    fn is_nan(&self) -> Result<bool, ()> {
    406        self.unitless_value()
    407            .map(|v| Ok(v.is_nan()))
    408            .unwrap_or_else(|| Err(()))
    409    }
    410 
    411    /// Tries to merge one leaf into another using the sum, that is, perform `x` + `y`.
    412    fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
    413 
    414    /// Try to merge the right leaf into the left by using a multiplication. Return true if the
    415    /// merge was successful, otherwise false.
    416    fn try_product_in_place(&mut self, other: &mut Self) -> bool;
    417 
    418    /// Tries a generic arithmetic operation.
    419    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
    420    where
    421        O: Fn(f32, f32) -> f32;
    422 
    423    /// Map the value of this node with the given operation.
    424    fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>;
    425 
    426    /// Canonicalizes the expression if necessary.
    427    fn simplify(&mut self);
    428 
    429    /// Returns the sort key for simplification.
    430    fn sort_key(&self) -> SortKey;
    431 
    432    /// Create a new leaf containing the sign() result of the given leaf.
    433    fn sign_from(leaf: &impl CalcNodeLeaf) -> Result<Self, ()> {
    434        let Some(value) = leaf.unitless_value() else {
    435            return Err(());
    436        };
    437 
    438        Ok(Self::new_number(if value.is_nan() {
    439            f32::NAN
    440        } else if value.is_zero() {
    441            value
    442        } else if value.is_sign_negative() {
    443            -1.0
    444        } else {
    445            1.0
    446        }))
    447    }
    448 }
    449 
    450 /// The level of any argument being serialized in `to_css_impl`.
    451 enum ArgumentLevel {
    452    /// The root of a calculation tree.
    453    CalculationRoot,
    454    /// The root of an operand node's argument, e.g. `min(10, 20)`, `10` and `20` will have this
    455    /// level, but min in this case will have `TopMost`.
    456    ArgumentRoot,
    457    /// Any other values serialized in the tree.
    458    Nested,
    459 }
    460 
    461 impl<L: CalcNodeLeaf> CalcNode<L> {
    462    /// Create a dummy CalcNode that can be used to do replacements of other nodes.
    463    fn dummy() -> Self {
    464        Self::MinMax(Default::default(), MinMaxOp::Max)
    465    }
    466 
    467    /// Change all the leaf nodes to have the given value. This is useful when
    468    /// you have `calc(1px * nan)` and you want to replace the product node with
    469    /// `calc(nan)`, in which case the unit will be retained.
    470    fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
    471        self.map(|_| value)
    472    }
    473 
    474    /// Return true if a product is distributive over this node.
    475    /// Is distributive: (2 + 3) * 4 = 8 + 12
    476    /// Not distributive: sign(2 + 3) * 4 != sign(8 + 12)
    477    #[inline]
    478    pub fn is_product_distributive(&self) -> bool {
    479        match self {
    480            Self::Leaf(l) => l.unit() != CalcUnits::COLOR_COMPONENT,
    481            Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()),
    482            _ => false,
    483        }
    484    }
    485 
    486    /// If the node has a valid unit outcome, then return it, otherwise fail.
    487    pub fn unit(&self) -> Result<CalcUnits, ()> {
    488        Ok(match self {
    489            CalcNode::Leaf(l) => l.unit(),
    490            CalcNode::Negate(child) | CalcNode::Invert(child) | CalcNode::Abs(child) => {
    491                child.unit()?
    492            },
    493            CalcNode::Sum(children) => {
    494                let mut unit = children.first().unwrap().unit()?;
    495                for child in children.iter().skip(1) {
    496                    let child_unit = child.unit()?;
    497                    if !child_unit.can_sum_with(unit) {
    498                        return Err(());
    499                    }
    500                    unit |= child_unit;
    501                }
    502                unit
    503            },
    504            CalcNode::Product(children) => {
    505                // Only one node is allowed to have a unit, the rest must be numbers.
    506                let mut unit = None;
    507                for child in children.iter() {
    508                    let child_unit = child.unit()?;
    509                    if child_unit.is_empty() {
    510                        // Numbers are always allowed in a product, so continue with the next.
    511                        continue;
    512                    }
    513 
    514                    if unit.is_some() {
    515                        // We already have a unit for the node, so another unit node is invalid.
    516                        return Err(());
    517                    }
    518 
    519                    // We have the unit for the node.
    520                    unit = Some(child_unit);
    521                }
    522                // We only keep track of specified units, so if we end up with a None and no failure
    523                // so far, then we have a number.
    524                unit.unwrap_or(CalcUnits::empty())
    525            },
    526            CalcNode::MinMax(children, _) | CalcNode::Hypot(children) => {
    527                let mut unit = children.first().unwrap().unit()?;
    528                for child in children.iter().skip(1) {
    529                    let child_unit = child.unit()?;
    530                    if !child_unit.can_sum_with(unit) {
    531                        return Err(());
    532                    }
    533                    unit |= child_unit;
    534                }
    535                unit
    536            },
    537            CalcNode::Clamp { min, center, max } => {
    538                let min_unit = min.unit()?;
    539                let center_unit = center.unit()?;
    540 
    541                if !min_unit.can_sum_with(center_unit) {
    542                    return Err(());
    543                }
    544 
    545                let max_unit = max.unit()?;
    546 
    547                if !center_unit.can_sum_with(max_unit) {
    548                    return Err(());
    549                }
    550 
    551                min_unit | center_unit | max_unit
    552            },
    553            CalcNode::Round { value, step, .. } => {
    554                let value_unit = value.unit()?;
    555                let step_unit = step.unit()?;
    556                if !step_unit.can_sum_with(value_unit) {
    557                    return Err(());
    558                }
    559                value_unit | step_unit
    560            },
    561            CalcNode::ModRem {
    562                dividend, divisor, ..
    563            } => {
    564                let dividend_unit = dividend.unit()?;
    565                let divisor_unit = divisor.unit()?;
    566                if !divisor_unit.can_sum_with(dividend_unit) {
    567                    return Err(());
    568                }
    569                dividend_unit | divisor_unit
    570            },
    571            CalcNode::Sign(ref child) => {
    572                // sign() always resolves to a number, but we still need to make sure that the
    573                // child units make sense.
    574                let _ = child.unit()?;
    575                CalcUnits::empty()
    576            },
    577            CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
    578        })
    579    }
    580 
    581    /// Negate the node inline.  If the node is distributive, it is replaced by the result,
    582    /// otherwise the node is wrapped in a [`Negate`] node.
    583    pub fn negate(&mut self) {
    584        /// Node(params) -> Negate(Node(params))
    585        fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
    586            let result = mem::replace(s, CalcNode::dummy());
    587            *s = CalcNode::Negate(Box::new(result));
    588        }
    589 
    590        match *self {
    591            CalcNode::Leaf(ref mut leaf) => {
    592                if leaf.map(std::ops::Neg::neg).is_err() {
    593                    wrap_self_in_negate(self)
    594                }
    595            },
    596            CalcNode::Negate(ref mut value) => {
    597                // Don't negate the value here.  Replace `self` with it's child.
    598                let result = mem::replace(value.as_mut(), Self::dummy());
    599                *self = result;
    600            },
    601            CalcNode::Invert(_) => {
    602                // -(1 / -10) == -(-0.1) == 0.1
    603                wrap_self_in_negate(self)
    604            },
    605            CalcNode::Sum(ref mut children) => {
    606                for child in children.iter_mut() {
    607                    child.negate();
    608                }
    609            },
    610            CalcNode::Product(_) => {
    611                // -(2 * 3 / 4) == -(1.5)
    612                wrap_self_in_negate(self);
    613            },
    614            CalcNode::MinMax(ref mut children, ref mut op) => {
    615                for child in children.iter_mut() {
    616                    child.negate();
    617                }
    618 
    619                // Negating min-max means the operation is swapped.
    620                *op = match *op {
    621                    MinMaxOp::Min => MinMaxOp::Max,
    622                    MinMaxOp::Max => MinMaxOp::Min,
    623                };
    624            },
    625            CalcNode::Clamp {
    626                ref mut min,
    627                ref mut center,
    628                ref mut max,
    629            } => {
    630                if min.lte(max, PositivePercentageBasis::Unknown) {
    631                    min.negate();
    632                    center.negate();
    633                    max.negate();
    634 
    635                    mem::swap(min, max);
    636                } else {
    637                    wrap_self_in_negate(self);
    638                }
    639            },
    640            CalcNode::Round {
    641                ref mut strategy,
    642                ref mut value,
    643                ref mut step,
    644            } => {
    645                match *strategy {
    646                    RoundingStrategy::Nearest => {
    647                        // Nearest is tricky because we'd have to swap the
    648                        // behavior at the half-way point from using the upper
    649                        // to lower bound.
    650                        // Simpler to just wrap self in a negate node.
    651                        wrap_self_in_negate(self);
    652                        return;
    653                    },
    654                    RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
    655                    RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
    656                    RoundingStrategy::ToZero => (),
    657                }
    658                value.negate();
    659                step.negate();
    660            },
    661            CalcNode::ModRem {
    662                ref mut dividend,
    663                ref mut divisor,
    664                ..
    665            } => {
    666                dividend.negate();
    667                divisor.negate();
    668            },
    669            CalcNode::Hypot(ref mut children) => {
    670                for child in children.iter_mut() {
    671                    child.negate();
    672                }
    673            },
    674            CalcNode::Abs(_) => {
    675                wrap_self_in_negate(self);
    676            },
    677            CalcNode::Sign(ref mut child) => {
    678                child.negate();
    679            },
    680            CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => {
    681                wrap_self_in_negate(self);
    682            },
    683        }
    684    }
    685 
    686    fn sort_key(&self) -> SortKey {
    687        match *self {
    688            Self::Leaf(ref l) => l.sort_key(),
    689            Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
    690            _ => SortKey::Other,
    691        }
    692    }
    693 
    694    /// Returns the leaf if we can (if simplification has allowed it).
    695    pub fn as_leaf(&self) -> Option<&L> {
    696        match *self {
    697            Self::Leaf(ref l) => Some(l),
    698            _ => None,
    699        }
    700    }
    701 
    702    /// Tries to merge one node into another using the sum, that is, perform `x` + `y`.
    703    pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
    704        match (self, other) {
    705            (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
    706                one.try_sum_in_place(other)
    707            },
    708            _ => Err(()),
    709        }
    710    }
    711 
    712    /// Tries to merge one node into another using the product, that is, perform `x` * `y`.
    713    pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
    714        if let Ok(resolved) = other.resolve() {
    715            if let Some(number) = resolved.as_number() {
    716                if number == 1.0 {
    717                    return true;
    718                }
    719 
    720                if self.is_product_distributive() {
    721                    if self.map(|v| v * number).is_err() {
    722                        return false;
    723                    }
    724                    return true;
    725                }
    726            }
    727        }
    728 
    729        if let Ok(resolved) = self.resolve() {
    730            if let Some(number) = resolved.as_number() {
    731                if number == 1.0 {
    732                    std::mem::swap(self, other);
    733                    return true;
    734                }
    735 
    736                if other.is_product_distributive() {
    737                    if other.map(|v| v * number).is_err() {
    738                        return false;
    739                    }
    740                    std::mem::swap(self, other);
    741                    return true;
    742                }
    743            }
    744        }
    745 
    746        false
    747    }
    748 
    749    /// Tries to apply a generic arithmetic operator
    750    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
    751    where
    752        O: Fn(f32, f32) -> f32,
    753    {
    754        match (self, other) {
    755            (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
    756                Ok(CalcNode::Leaf(one.try_op(other, op)?))
    757            },
    758            _ => Err(()),
    759        }
    760    }
    761 
    762    /// Map the value of this node with the given operation.
    763    pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
    764        fn map_internal<L: CalcNodeLeaf>(
    765            node: &mut CalcNode<L>,
    766            op: &mut impl FnMut(f32) -> f32,
    767        ) -> Result<(), ()> {
    768            match node {
    769                CalcNode::Leaf(l) => l.map(op),
    770                CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
    771                CalcNode::Sum(children) | CalcNode::Product(children) => {
    772                    for node in &mut **children {
    773                        map_internal(node, op)?;
    774                    }
    775                    Ok(())
    776                },
    777                CalcNode::MinMax(children, _) => {
    778                    for node in &mut **children {
    779                        map_internal(node, op)?;
    780                    }
    781                    Ok(())
    782                },
    783                CalcNode::Clamp { min, center, max } => {
    784                    map_internal(min, op)?;
    785                    map_internal(center, op)?;
    786                    map_internal(max, op)
    787                },
    788                CalcNode::Round { value, step, .. } => {
    789                    map_internal(value, op)?;
    790                    map_internal(step, op)
    791                },
    792                CalcNode::ModRem {
    793                    dividend, divisor, ..
    794                } => {
    795                    map_internal(dividend, op)?;
    796                    map_internal(divisor, op)
    797                },
    798                CalcNode::Hypot(children) => {
    799                    for node in &mut **children {
    800                        map_internal(node, op)?;
    801                    }
    802                    Ok(())
    803                },
    804                CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
    805                // It is invalid to treat inner `CalcNode`s here - `anchor(--foo 50%) / 2` != `anchor(--foo 25%)`.
    806                // Same applies to fallback, as we don't know if it will be used. Similar reasoning applies to `anchor-size()`.
    807                CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
    808            }
    809        }
    810 
    811        map_internal(self, &mut op)
    812    }
    813 
    814    /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind.
    815    pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
    816    where
    817        O: CalcNodeLeaf,
    818        F: FnMut(&L) -> O,
    819    {
    820        self.map_leaves_internal(&mut map)
    821    }
    822 
    823    fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
    824    where
    825        O: CalcNodeLeaf,
    826        F: FnMut(&L) -> O,
    827    {
    828        fn map_children<L, O, F>(
    829            children: &[CalcNode<L>],
    830            map: &mut F,
    831        ) -> crate::OwnedSlice<CalcNode<O>>
    832        where
    833            L: CalcNodeLeaf,
    834            O: CalcNodeLeaf,
    835            F: FnMut(&L) -> O,
    836        {
    837            children
    838                .iter()
    839                .map(|c| c.map_leaves_internal(map))
    840                .collect()
    841        }
    842 
    843        match *self {
    844            Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
    845            Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
    846            Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
    847            Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
    848            Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
    849            Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
    850            Self::Clamp {
    851                ref min,
    852                ref center,
    853                ref max,
    854            } => {
    855                let min = Box::new(min.map_leaves_internal(map));
    856                let center = Box::new(center.map_leaves_internal(map));
    857                let max = Box::new(max.map_leaves_internal(map));
    858                CalcNode::Clamp { min, center, max }
    859            },
    860            Self::Round {
    861                strategy,
    862                ref value,
    863                ref step,
    864            } => {
    865                let value = Box::new(value.map_leaves_internal(map));
    866                let step = Box::new(step.map_leaves_internal(map));
    867                CalcNode::Round {
    868                    strategy,
    869                    value,
    870                    step,
    871                }
    872            },
    873            Self::ModRem {
    874                ref dividend,
    875                ref divisor,
    876                op,
    877            } => {
    878                let dividend = Box::new(dividend.map_leaves_internal(map));
    879                let divisor = Box::new(divisor.map_leaves_internal(map));
    880                CalcNode::ModRem {
    881                    dividend,
    882                    divisor,
    883                    op,
    884                }
    885            },
    886            Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
    887            Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
    888            Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
    889            Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
    890                target_element: f.target_element.clone(),
    891                side: match &f.side {
    892                    GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
    893                    GenericAnchorSide::Percentage(p) => {
    894                        GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
    895                    },
    896                },
    897                fallback: f
    898                    .fallback
    899                    .as_ref()
    900                    .map(|fb| Box::new(fb.map_leaves_internal(map)))
    901                    .into(),
    902            })),
    903            Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
    904                target_element: f.target_element.clone(),
    905                size: f.size,
    906                fallback: f
    907                    .fallback
    908                    .as_ref()
    909                    .map(|fb| Box::new(fb.map_leaves_internal(map)))
    910                    .into(),
    911            })),
    912        }
    913    }
    914 
    915    /// Resolve this node into a value.
    916    pub fn resolve(&self) -> Result<L, ()> {
    917        self.resolve_map(|l| Ok(l.clone()))
    918    }
    919 
    920    /// Resolve this node into a value, given a function that maps the leaf values.
    921    pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
    922    where
    923        F: FnMut(&L) -> Result<L, ()>,
    924    {
    925        self.resolve_internal(&mut leaf_to_output_fn)
    926    }
    927 
    928    fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<L, ()>
    929    where
    930        F: FnMut(&L) -> Result<L, ()>,
    931    {
    932        match self {
    933            Self::Leaf(l) => leaf_to_output_fn(l),
    934            Self::Negate(child) => {
    935                let mut result = child.resolve_internal(leaf_to_output_fn)?;
    936                result.map(|v| v.neg())?;
    937                Ok(result)
    938            },
    939            Self::Invert(child) => {
    940                let mut result = child.resolve_internal(leaf_to_output_fn)?;
    941                result.map(|v| 1.0 / v)?;
    942                Ok(result)
    943            },
    944            Self::Sum(children) => {
    945                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
    946 
    947                for child in children.iter().skip(1) {
    948                    let right = child.resolve_internal(leaf_to_output_fn)?;
    949                    // try_op will make sure we only sum leaves with the same type.
    950                    result = result.try_op(&right, |left, right| left + right)?;
    951                }
    952 
    953                Ok(result)
    954            },
    955            Self::Product(children) => {
    956                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
    957 
    958                for child in children.iter().skip(1) {
    959                    let right = child.resolve_internal(leaf_to_output_fn)?;
    960                    // Mutliply only allowed when either side is a number.
    961                    match result.as_number() {
    962                        Some(left) => {
    963                            // Left side is a number, so we use the right node as the result.
    964                            result = right;
    965                            result.map(|v| v * left)?;
    966                        },
    967                        None => {
    968                            // Left side is not a number, so check if the right side is.
    969                            match right.as_number() {
    970                                Some(right) => {
    971                                    result.map(|v| v * right)?;
    972                                },
    973                                None => {
    974                                    // Multiplying with both sides having units.
    975                                    return Err(());
    976                                },
    977                            }
    978                        },
    979                    }
    980                }
    981 
    982                Ok(result)
    983            },
    984            Self::MinMax(children, op) => {
    985                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
    986 
    987                if result.is_nan()? {
    988                    return Ok(result);
    989                }
    990 
    991                for child in children.iter().skip(1) {
    992                    let candidate = child.resolve_internal(leaf_to_output_fn)?;
    993 
    994                    // Leaf types must match for each child.
    995                    if !result.is_same_unit_as(&candidate) {
    996                        return Err(());
    997                    }
    998 
    999                    if candidate.is_nan()? {
   1000                        result = candidate;
   1001                        break;
   1002                    }
   1003 
   1004                    let candidate_wins = match op {
   1005                        MinMaxOp::Min => candidate.lt(&result, PositivePercentageBasis::Yes),
   1006                        MinMaxOp::Max => candidate.gt(&result, PositivePercentageBasis::Yes),
   1007                    };
   1008 
   1009                    if candidate_wins {
   1010                        result = candidate;
   1011                    }
   1012                }
   1013 
   1014                Ok(result)
   1015            },
   1016            Self::Clamp { min, center, max } => {
   1017                let min = min.resolve_internal(leaf_to_output_fn)?;
   1018                let center = center.resolve_internal(leaf_to_output_fn)?;
   1019                let max = max.resolve_internal(leaf_to_output_fn)?;
   1020 
   1021                if !min.is_same_unit_as(&center) || !max.is_same_unit_as(&center) {
   1022                    return Err(());
   1023                }
   1024 
   1025                if min.is_nan()? {
   1026                    return Ok(min);
   1027                }
   1028 
   1029                if center.is_nan()? {
   1030                    return Ok(center);
   1031                }
   1032 
   1033                if max.is_nan()? {
   1034                    return Ok(max);
   1035                }
   1036 
   1037                let mut result = center;
   1038                if result.gt(&max, PositivePercentageBasis::Yes) {
   1039                    result = max;
   1040                }
   1041                if result.lt(&min, PositivePercentageBasis::Yes) {
   1042                    result = min
   1043                }
   1044 
   1045                Ok(result)
   1046            },
   1047            Self::Round {
   1048                strategy,
   1049                value,
   1050                step,
   1051            } => {
   1052                let mut value = value.resolve_internal(leaf_to_output_fn)?;
   1053                let step = step.resolve_internal(leaf_to_output_fn)?;
   1054 
   1055                if !value.is_same_unit_as(&step) {
   1056                    return Err(());
   1057                }
   1058 
   1059                let Some(step) = step.unitless_value() else {
   1060                    return Err(());
   1061                };
   1062                let step = step.abs();
   1063 
   1064                value.map(|value| {
   1065                    // TODO(emilio): Seems like at least a few of these
   1066                    // special-cases could be removed if we do the math in a
   1067                    // particular order.
   1068                    if step.is_zero() {
   1069                        return f32::NAN;
   1070                    }
   1071 
   1072                    if value.is_infinite() {
   1073                        if step.is_infinite() {
   1074                            return f32::NAN;
   1075                        }
   1076                        return value;
   1077                    }
   1078 
   1079                    if step.is_infinite() {
   1080                        match strategy {
   1081                            RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
   1082                                return if value.is_sign_negative() { -0.0 } else { 0.0 }
   1083                            },
   1084                            RoundingStrategy::Up => {
   1085                                return if !value.is_sign_negative() && !value.is_zero() {
   1086                                    f32::INFINITY
   1087                                } else if !value.is_sign_negative() && value.is_zero() {
   1088                                    value
   1089                                } else {
   1090                                    -0.0
   1091                                }
   1092                            },
   1093                            RoundingStrategy::Down => {
   1094                                return if value.is_sign_negative() && !value.is_zero() {
   1095                                    -f32::INFINITY
   1096                                } else if value.is_sign_negative() && value.is_zero() {
   1097                                    value
   1098                                } else {
   1099                                    0.0
   1100                                }
   1101                            },
   1102                        }
   1103                    }
   1104 
   1105                    let div = value / step;
   1106                    let lower_bound = div.floor() * step;
   1107                    let upper_bound = div.ceil() * step;
   1108 
   1109                    match strategy {
   1110                        RoundingStrategy::Nearest => {
   1111                            // In case of a tie, use the upper bound
   1112                            if value - lower_bound < upper_bound - value {
   1113                                lower_bound
   1114                            } else {
   1115                                upper_bound
   1116                            }
   1117                        },
   1118                        RoundingStrategy::Up => upper_bound,
   1119                        RoundingStrategy::Down => lower_bound,
   1120                        RoundingStrategy::ToZero => {
   1121                            // In case of a tie, use the upper bound
   1122                            if lower_bound.abs() < upper_bound.abs() {
   1123                                lower_bound
   1124                            } else {
   1125                                upper_bound
   1126                            }
   1127                        },
   1128                    }
   1129                })?;
   1130 
   1131                Ok(value)
   1132            },
   1133            Self::ModRem {
   1134                dividend,
   1135                divisor,
   1136                op,
   1137            } => {
   1138                let mut dividend = dividend.resolve_internal(leaf_to_output_fn)?;
   1139                let divisor = divisor.resolve_internal(leaf_to_output_fn)?;
   1140 
   1141                if !dividend.is_same_unit_as(&divisor) {
   1142                    return Err(());
   1143                }
   1144 
   1145                let Some(divisor) = divisor.unitless_value() else {
   1146                    return Err(());
   1147                };
   1148                dividend.map(|dividend| op.apply(dividend, divisor))?;
   1149                Ok(dividend)
   1150            },
   1151            Self::Hypot(children) => {
   1152                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
   1153                result.map(|v| v.powi(2))?;
   1154 
   1155                for child in children.iter().skip(1) {
   1156                    let child_value = child.resolve_internal(leaf_to_output_fn)?;
   1157 
   1158                    if !result.is_same_unit_as(&child_value) {
   1159                        return Err(());
   1160                    }
   1161 
   1162                    let Some(child_value) = child_value.unitless_value() else {
   1163                        return Err(());
   1164                    };
   1165                    result.map(|v| v + child_value.powi(2))?;
   1166                }
   1167 
   1168                result.map(|v| v.sqrt())?;
   1169                Ok(result)
   1170            },
   1171            Self::Abs(ref c) => {
   1172                let mut result = c.resolve_internal(leaf_to_output_fn)?;
   1173 
   1174                result.map(|v| v.abs())?;
   1175 
   1176                Ok(result)
   1177            },
   1178            Self::Sign(ref c) => {
   1179                let result = c.resolve_internal(leaf_to_output_fn)?;
   1180                Ok(L::sign_from(&result)?)
   1181            },
   1182            Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
   1183        }
   1184    }
   1185 
   1186    /// Mutate nodes within this calc node tree using given the mapping function.
   1187    pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
   1188    where
   1189        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
   1190    {
   1191        self.map_node_internal(&mut mapping_fn)
   1192    }
   1193 
   1194    fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
   1195    where
   1196        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
   1197    {
   1198        if let Some(node) = mapping_fn(self)? {
   1199            *self = node;
   1200            // Assume that any sub-nodes don't need to be mutated.
   1201            return Ok(());
   1202        }
   1203        match self {
   1204            Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
   1205            Self::Negate(child) | Self::Invert(child) | Self::Abs(child) | Self::Sign(child) => {
   1206                child.map_node_internal(mapping_fn)?;
   1207            },
   1208            Self::Sum(children)
   1209            | Self::Product(children)
   1210            | Self::Hypot(children)
   1211            | Self::MinMax(children, _) => {
   1212                for child in children.iter_mut() {
   1213                    child.map_node_internal(mapping_fn)?;
   1214                }
   1215            },
   1216            Self::Clamp { min, center, max } => {
   1217                min.map_node_internal(mapping_fn)?;
   1218                center.map_node_internal(mapping_fn)?;
   1219                max.map_node_internal(mapping_fn)?;
   1220            },
   1221            Self::Round { value, step, .. } => {
   1222                value.map_node_internal(mapping_fn)?;
   1223                step.map_node_internal(mapping_fn)?;
   1224            },
   1225            Self::ModRem {
   1226                dividend, divisor, ..
   1227            } => {
   1228                dividend.map_node_internal(mapping_fn)?;
   1229                divisor.map_node_internal(mapping_fn)?;
   1230            },
   1231        };
   1232        Ok(())
   1233    }
   1234 
   1235    fn is_negative_leaf(&self) -> Result<bool, ()> {
   1236        Ok(match *self {
   1237            Self::Leaf(ref l) => l.is_negative()?,
   1238            _ => false,
   1239        })
   1240    }
   1241 
   1242    fn is_zero_leaf(&self) -> Result<bool, ()> {
   1243        Ok(match *self {
   1244            Self::Leaf(ref l) => l.is_zero()?,
   1245            _ => false,
   1246        })
   1247    }
   1248 
   1249    fn is_infinite_leaf(&self) -> Result<bool, ()> {
   1250        Ok(match *self {
   1251            Self::Leaf(ref l) => l.is_infinite()?,
   1252            _ => false,
   1253        })
   1254    }
   1255 
   1256    fn is_nan_leaf(&self) -> Result<bool, ()> {
   1257        Ok(match *self {
   1258            Self::Leaf(ref l) => l.is_nan()?,
   1259            _ => false,
   1260        })
   1261    }
   1262 
   1263    /// Visits all the nodes in this calculation tree recursively, starting by
   1264    /// the leaves and bubbling all the way up.
   1265    ///
   1266    /// This is useful for simplification, but can also be used for validation
   1267    /// and such.
   1268    pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
   1269        self.visit_depth_first_internal(&mut f)
   1270    }
   1271 
   1272    fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
   1273        match *self {
   1274            Self::Clamp {
   1275                ref mut min,
   1276                ref mut center,
   1277                ref mut max,
   1278            } => {
   1279                min.visit_depth_first_internal(f);
   1280                center.visit_depth_first_internal(f);
   1281                max.visit_depth_first_internal(f);
   1282            },
   1283            Self::Round {
   1284                ref mut value,
   1285                ref mut step,
   1286                ..
   1287            } => {
   1288                value.visit_depth_first_internal(f);
   1289                step.visit_depth_first_internal(f);
   1290            },
   1291            Self::ModRem {
   1292                ref mut dividend,
   1293                ref mut divisor,
   1294                ..
   1295            } => {
   1296                dividend.visit_depth_first_internal(f);
   1297                divisor.visit_depth_first_internal(f);
   1298            },
   1299            Self::Sum(ref mut children)
   1300            | Self::Product(ref mut children)
   1301            | Self::MinMax(ref mut children, _)
   1302            | Self::Hypot(ref mut children) => {
   1303                for child in &mut **children {
   1304                    child.visit_depth_first_internal(f);
   1305                }
   1306            },
   1307            Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
   1308                value.visit_depth_first_internal(f);
   1309            },
   1310            Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
   1311                value.visit_depth_first_internal(f);
   1312            },
   1313            Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
   1314        }
   1315        f(self);
   1316    }
   1317 
   1318    /// This function simplifies and sorts the calculation of the specified node. It simplifies
   1319    /// directly nested nodes while assuming that all nodes below it have already been simplified.
   1320    /// It is recommended to use this function in combination with `visit_depth_first()`.
   1321    ///
   1322    /// This function is necessary only if the node needs to be preserved after parsing,
   1323    /// specifically for `<length-percentage>` cases where the calculation contains percentages or
   1324    /// relative units. Otherwise, the node can be evaluated using `resolve()`, which will
   1325    /// automatically provide a simplified value.
   1326    ///
   1327    /// <https://drafts.csswg.org/css-values-4/#calc-simplification>
   1328    pub fn simplify_and_sort_direct_children(&mut self) {
   1329        macro_rules! replace_self_with {
   1330            ($slot:expr) => {{
   1331                let result = mem::replace($slot, Self::dummy());
   1332                *self = result;
   1333            }};
   1334        }
   1335 
   1336        macro_rules! value_or_stop {
   1337            ($op:expr) => {{
   1338                match $op {
   1339                    Ok(value) => value,
   1340                    Err(_) => return,
   1341                }
   1342            }};
   1343        }
   1344 
   1345        match *self {
   1346            Self::Clamp {
   1347                ref mut min,
   1348                ref mut center,
   1349                ref mut max,
   1350            } => {
   1351                // NOTE: clamp() is max(min, min(center, max))
   1352                let min_cmp_center = match min.compare(&center, PositivePercentageBasis::Unknown) {
   1353                    Some(o) => o,
   1354                    None => return,
   1355                };
   1356 
   1357                // So if we can prove that min is more than center, then we won,
   1358                // as that's what we should always return.
   1359                if matches!(min_cmp_center, cmp::Ordering::Greater) {
   1360                    replace_self_with!(&mut **min);
   1361                    return;
   1362                }
   1363 
   1364                // Otherwise try with max.
   1365                let max_cmp_center = match max.compare(&center, PositivePercentageBasis::Unknown) {
   1366                    Some(o) => o,
   1367                    None => return,
   1368                };
   1369 
   1370                if matches!(max_cmp_center, cmp::Ordering::Less) {
   1371                    // max is less than center, so we need to return effectively
   1372                    // `max(min, max)`.
   1373                    let max_cmp_min = match max.compare(&min, PositivePercentageBasis::Unknown) {
   1374                        Some(o) => o,
   1375                        None => return,
   1376                    };
   1377 
   1378                    if matches!(max_cmp_min, cmp::Ordering::Less) {
   1379                        replace_self_with!(&mut **min);
   1380                        return;
   1381                    }
   1382 
   1383                    replace_self_with!(&mut **max);
   1384                    return;
   1385                }
   1386 
   1387                // Otherwise we're the center node.
   1388                replace_self_with!(&mut **center);
   1389            },
   1390            Self::Round {
   1391                strategy,
   1392                ref mut value,
   1393                ref mut step,
   1394            } => {
   1395                if value_or_stop!(step.is_zero_leaf()) {
   1396                    value_or_stop!(value.coerce_to_value(f32::NAN));
   1397                    replace_self_with!(&mut **value);
   1398                    return;
   1399                }
   1400 
   1401                if value_or_stop!(value.is_infinite_leaf())
   1402                    && value_or_stop!(step.is_infinite_leaf())
   1403                {
   1404                    value_or_stop!(value.coerce_to_value(f32::NAN));
   1405                    replace_self_with!(&mut **value);
   1406                    return;
   1407                }
   1408 
   1409                if value_or_stop!(value.is_infinite_leaf()) {
   1410                    replace_self_with!(&mut **value);
   1411                    return;
   1412                }
   1413 
   1414                if value_or_stop!(step.is_infinite_leaf()) {
   1415                    match strategy {
   1416                        RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
   1417                            value_or_stop!(value.coerce_to_value(0.0));
   1418                            replace_self_with!(&mut **value);
   1419                            return;
   1420                        },
   1421                        RoundingStrategy::Up => {
   1422                            if !value_or_stop!(value.is_negative_leaf())
   1423                                && !value_or_stop!(value.is_zero_leaf())
   1424                            {
   1425                                value_or_stop!(value.coerce_to_value(f32::INFINITY));
   1426                                replace_self_with!(&mut **value);
   1427                                return;
   1428                            } else if !value_or_stop!(value.is_negative_leaf())
   1429                                && value_or_stop!(value.is_zero_leaf())
   1430                            {
   1431                                replace_self_with!(&mut **value);
   1432                                return;
   1433                            } else {
   1434                                value_or_stop!(value.coerce_to_value(0.0));
   1435                                replace_self_with!(&mut **value);
   1436                                return;
   1437                            }
   1438                        },
   1439                        RoundingStrategy::Down => {
   1440                            if value_or_stop!(value.is_negative_leaf())
   1441                                && !value_or_stop!(value.is_zero_leaf())
   1442                            {
   1443                                value_or_stop!(value.coerce_to_value(f32::INFINITY));
   1444                                replace_self_with!(&mut **value);
   1445                                return;
   1446                            } else if value_or_stop!(value.is_negative_leaf())
   1447                                && value_or_stop!(value.is_zero_leaf())
   1448                            {
   1449                                replace_self_with!(&mut **value);
   1450                                return;
   1451                            } else {
   1452                                value_or_stop!(value.coerce_to_value(0.0));
   1453                                replace_self_with!(&mut **value);
   1454                                return;
   1455                            }
   1456                        },
   1457                    }
   1458                }
   1459 
   1460                if value_or_stop!(step.is_negative_leaf()) {
   1461                    step.negate();
   1462                }
   1463 
   1464                let remainder = value_or_stop!(value.try_op(step, Rem::rem));
   1465                if value_or_stop!(remainder.is_zero_leaf()) {
   1466                    replace_self_with!(&mut **value);
   1467                    return;
   1468                }
   1469 
   1470                let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
   1471                {
   1472                    let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
   1473                    let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub));
   1474 
   1475                    (lower_bound, upper_bound)
   1476                } else {
   1477                    let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
   1478                    let upper_bound = value_or_stop!(lower_bound.try_op(&step, Add::add));
   1479 
   1480                    (lower_bound, upper_bound)
   1481                };
   1482 
   1483                match strategy {
   1484                    RoundingStrategy::Nearest => {
   1485                        let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
   1486                        let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
   1487                        // In case of a tie, use the upper bound
   1488                        if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
   1489                            replace_self_with!(&mut lower_bound);
   1490                        } else {
   1491                            replace_self_with!(&mut upper_bound);
   1492                        }
   1493                    },
   1494                    RoundingStrategy::Up => {
   1495                        replace_self_with!(&mut upper_bound);
   1496                    },
   1497                    RoundingStrategy::Down => {
   1498                        replace_self_with!(&mut lower_bound);
   1499                    },
   1500                    RoundingStrategy::ToZero => {
   1501                        let mut lower_diff = lower_bound.clone();
   1502                        let mut upper_diff = upper_bound.clone();
   1503 
   1504                        if value_or_stop!(lower_diff.is_negative_leaf()) {
   1505                            lower_diff.negate();
   1506                        }
   1507 
   1508                        if value_or_stop!(upper_diff.is_negative_leaf()) {
   1509                            upper_diff.negate();
   1510                        }
   1511 
   1512                        // In case of a tie, use the upper bound
   1513                        if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
   1514                            replace_self_with!(&mut lower_bound);
   1515                        } else {
   1516                            replace_self_with!(&mut upper_bound);
   1517                        }
   1518                    },
   1519                };
   1520            },
   1521            Self::ModRem {
   1522                ref dividend,
   1523                ref divisor,
   1524                op,
   1525            } => {
   1526                let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
   1527                replace_self_with!(&mut result);
   1528            },
   1529            Self::MinMax(ref mut children, op) => {
   1530                let winning_order = match op {
   1531                    MinMaxOp::Min => cmp::Ordering::Less,
   1532                    MinMaxOp::Max => cmp::Ordering::Greater,
   1533                };
   1534 
   1535                if value_or_stop!(children[0].is_nan_leaf()) {
   1536                    replace_self_with!(&mut children[0]);
   1537                    return;
   1538                }
   1539 
   1540                let mut result = 0;
   1541                for i in 1..children.len() {
   1542                    if value_or_stop!(children[i].is_nan_leaf()) {
   1543                        replace_self_with!(&mut children[i]);
   1544                        return;
   1545                    }
   1546                    let o = match children[i]
   1547                        .compare(&children[result], PositivePercentageBasis::Unknown)
   1548                    {
   1549                        // We can't compare all the children, so we can't
   1550                        // know which one will actually win. Bail out and
   1551                        // keep ourselves as a min / max function.
   1552                        //
   1553                        // TODO: Maybe we could simplify compatible children,
   1554                        // see https://github.com/w3c/csswg-drafts/issues/4756
   1555                        None => return,
   1556                        Some(o) => o,
   1557                    };
   1558 
   1559                    if o == winning_order {
   1560                        result = i;
   1561                    }
   1562                }
   1563 
   1564                replace_self_with!(&mut children[result]);
   1565            },
   1566            Self::Sum(ref mut children_slot) => {
   1567                let mut sums_to_merge = SmallVec::<[_; 3]>::new();
   1568                let mut extra_kids = 0;
   1569                for (i, child) in children_slot.iter().enumerate() {
   1570                    if let Self::Sum(ref children) = *child {
   1571                        extra_kids += children.len();
   1572                        sums_to_merge.push(i);
   1573                    }
   1574                }
   1575 
   1576                // If we only have one kid, we've already simplified it, and it
   1577                // doesn't really matter whether it's a sum already or not, so
   1578                // lift it up and continue.
   1579                if children_slot.len() == 1 {
   1580                    replace_self_with!(&mut children_slot[0]);
   1581                    return;
   1582                }
   1583 
   1584                let mut children = mem::take(children_slot).into_vec();
   1585 
   1586                if !sums_to_merge.is_empty() {
   1587                    children.reserve(extra_kids - sums_to_merge.len());
   1588                    // Merge all our nested sums, in reverse order so that the
   1589                    // list indices are not invalidated.
   1590                    for i in sums_to_merge.drain(..).rev() {
   1591                        let kid_children = match children.swap_remove(i) {
   1592                            Self::Sum(c) => c,
   1593                            _ => unreachable!(),
   1594                        };
   1595 
   1596                        // This would be nicer with
   1597                        // https://github.com/rust-lang/rust/issues/59878 fixed.
   1598                        children.extend(kid_children.into_vec());
   1599                    }
   1600                }
   1601 
   1602                debug_assert!(children.len() >= 2, "Should still have multiple kids!");
   1603 
   1604                // Sort by spec order.
   1605                children.sort_unstable_by_key(|c| c.sort_key());
   1606 
   1607                // NOTE: if the function returns true, by the docs of dedup_by,
   1608                // a is removed.
   1609                children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
   1610 
   1611                if children.len() == 1 {
   1612                    // If only one children remains, lift it up, and carry on.
   1613                    replace_self_with!(&mut children[0]);
   1614                } else {
   1615                    // Else put our simplified children back.
   1616                    *children_slot = children.into_boxed_slice().into();
   1617                }
   1618            },
   1619            Self::Product(ref mut children_slot) => {
   1620                let mut products_to_merge = SmallVec::<[_; 3]>::new();
   1621                let mut extra_kids = 0;
   1622                for (i, child) in children_slot.iter().enumerate() {
   1623                    if let Self::Product(ref children) = *child {
   1624                        extra_kids += children.len();
   1625                        products_to_merge.push(i);
   1626                    }
   1627                }
   1628 
   1629                // If we only have one kid, we've already simplified it, and it
   1630                // doesn't really matter whether it's a product already or not,
   1631                // so lift it up and continue.
   1632                if children_slot.len() == 1 {
   1633                    replace_self_with!(&mut children_slot[0]);
   1634                    return;
   1635                }
   1636 
   1637                let mut children = mem::take(children_slot).into_vec();
   1638 
   1639                if !products_to_merge.is_empty() {
   1640                    children.reserve(extra_kids - products_to_merge.len());
   1641                    // Merge all our nested sums, in reverse order so that the
   1642                    // list indices are not invalidated.
   1643                    for i in products_to_merge.drain(..).rev() {
   1644                        let kid_children = match children.swap_remove(i) {
   1645                            Self::Product(c) => c,
   1646                            _ => unreachable!(),
   1647                        };
   1648 
   1649                        // This would be nicer with
   1650                        // https://github.com/rust-lang/rust/issues/59878 fixed.
   1651                        children.extend(kid_children.into_vec());
   1652                    }
   1653                }
   1654 
   1655                debug_assert!(children.len() >= 2, "Should still have multiple kids!");
   1656 
   1657                // Sort by spec order.
   1658                children.sort_unstable_by_key(|c| c.sort_key());
   1659 
   1660                // NOTE: if the function returns true, by the docs of dedup_by,
   1661                // a is removed.
   1662                children.dedup_by(|right, left| left.try_product_in_place(right));
   1663 
   1664                if children.len() == 1 {
   1665                    // If only one children remains, lift it up, and carry on.
   1666                    replace_self_with!(&mut children[0]);
   1667                } else {
   1668                    // Else put our simplified children back.
   1669                    *children_slot = children.into_boxed_slice().into();
   1670                }
   1671            },
   1672            Self::Hypot(ref children) => {
   1673                let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
   1674 
   1675                for child in children.iter().skip(1) {
   1676                    let square = value_or_stop!(child.try_op(&child, Mul::mul));
   1677                    result = value_or_stop!(result.try_op(&square, Add::add));
   1678                }
   1679 
   1680                result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
   1681 
   1682                replace_self_with!(&mut result);
   1683            },
   1684            Self::Abs(ref mut child) => {
   1685                if let CalcNode::Leaf(leaf) = child.as_mut() {
   1686                    value_or_stop!(leaf.map(|v| v.abs()));
   1687                    replace_self_with!(&mut **child);
   1688                }
   1689            },
   1690            Self::Sign(ref mut child) => {
   1691                if let CalcNode::Leaf(leaf) = child.as_mut() {
   1692                    let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
   1693                    replace_self_with!(&mut result);
   1694                }
   1695            },
   1696            Self::Negate(ref mut child) => {
   1697                // Step 6.
   1698                match &mut **child {
   1699                    CalcNode::Leaf(_) => {
   1700                        // 1. If root’s child is a numeric value, return an equivalent numeric value, but
   1701                        // with the value negated (0 - value).
   1702                        child.negate();
   1703                        replace_self_with!(&mut **child);
   1704                    },
   1705                    CalcNode::Negate(value) => {
   1706                        // 2. If root’s child is a Negate node, return the child’s child.
   1707                        replace_self_with!(&mut **value);
   1708                    },
   1709                    _ => {
   1710                        // 3. Return root.
   1711                    },
   1712                }
   1713            },
   1714            Self::Invert(ref mut child) => {
   1715                // Step 7.
   1716                match &mut **child {
   1717                    CalcNode::Leaf(leaf) => {
   1718                        // 1. If root’s child is a number (not a percentage or dimension) return the
   1719                        // reciprocal of the child’s value.
   1720                        if leaf.unit().is_empty() {
   1721                            value_or_stop!(child.map(|v| 1.0 / v));
   1722                            replace_self_with!(&mut **child);
   1723                        }
   1724                    },
   1725                    CalcNode::Invert(value) => {
   1726                        // 2. If root’s child is an Invert node, return the child’s child.
   1727                        replace_self_with!(&mut **value);
   1728                    },
   1729                    _ => {
   1730                        // 3. Return root.
   1731                    },
   1732                }
   1733            },
   1734            Self::Leaf(ref mut l) => {
   1735                l.simplify();
   1736            },
   1737            Self::Anchor(ref mut f) => {
   1738                if let GenericAnchorSide::Percentage(ref mut n) = f.side {
   1739                    n.simplify_and_sort();
   1740                }
   1741                if let Some(fallback) = f.fallback.as_mut() {
   1742                    fallback.simplify_and_sort();
   1743                }
   1744            },
   1745            Self::AnchorSize(ref mut f) => {
   1746                if let Some(fallback) = f.fallback.as_mut() {
   1747                    fallback.simplify_and_sort();
   1748                }
   1749            },
   1750        }
   1751    }
   1752 
   1753    /// Simplifies and sorts the kids in the whole calculation subtree.
   1754    pub fn simplify_and_sort(&mut self) {
   1755        self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
   1756    }
   1757 
   1758    fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
   1759    where
   1760        W: Write,
   1761    {
   1762        let write_closing_paren = match *self {
   1763            Self::MinMax(_, op) => {
   1764                dest.write_str(match op {
   1765                    MinMaxOp::Max => "max(",
   1766                    MinMaxOp::Min => "min(",
   1767                })?;
   1768                true
   1769            },
   1770            Self::Clamp { .. } => {
   1771                dest.write_str("clamp(")?;
   1772                true
   1773            },
   1774            Self::Round { strategy, .. } => {
   1775                match strategy {
   1776                    RoundingStrategy::Nearest => dest.write_str("round("),
   1777                    RoundingStrategy::Up => dest.write_str("round(up, "),
   1778                    RoundingStrategy::Down => dest.write_str("round(down, "),
   1779                    RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
   1780                }?;
   1781 
   1782                true
   1783            },
   1784            Self::ModRem { op, .. } => {
   1785                dest.write_str(match op {
   1786                    ModRemOp::Mod => "mod(",
   1787                    ModRemOp::Rem => "rem(",
   1788                })?;
   1789 
   1790                true
   1791            },
   1792            Self::Hypot(_) => {
   1793                dest.write_str("hypot(")?;
   1794                true
   1795            },
   1796            Self::Abs(_) => {
   1797                dest.write_str("abs(")?;
   1798                true
   1799            },
   1800            Self::Sign(_) => {
   1801                dest.write_str("sign(")?;
   1802                true
   1803            },
   1804            Self::Negate(_) => {
   1805                // We never generate a [`Negate`] node as the root of a calculation, only inside
   1806                // [`Sum`] nodes as a child. Because negate nodes are handled by the [`Sum`] node
   1807                // directly (see below), this node will never be serialized.
   1808                debug_assert!(
   1809                    false,
   1810                    "We never serialize Negate nodes as they are handled inside Sum nodes."
   1811                );
   1812                dest.write_str("(-1 * ")?;
   1813                true
   1814            },
   1815            Self::Invert(_) => {
   1816                if matches!(level, ArgumentLevel::CalculationRoot) {
   1817                    dest.write_str("calc")?;
   1818                }
   1819                dest.write_str("(1 / ")?;
   1820                true
   1821            },
   1822            Self::Sum(_) | Self::Product(_) => match level {
   1823                ArgumentLevel::CalculationRoot => {
   1824                    dest.write_str("calc(")?;
   1825                    true
   1826                },
   1827                ArgumentLevel::ArgumentRoot => false,
   1828                ArgumentLevel::Nested => {
   1829                    dest.write_str("(")?;
   1830                    true
   1831                },
   1832            },
   1833            Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => match level {
   1834                ArgumentLevel::CalculationRoot => {
   1835                    dest.write_str("calc(")?;
   1836                    true
   1837                },
   1838                ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
   1839            },
   1840        };
   1841 
   1842        match *self {
   1843            Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
   1844                let mut first = true;
   1845                for child in &**children {
   1846                    if !first {
   1847                        dest.write_str(", ")?;
   1848                    }
   1849                    first = false;
   1850                    child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1851                }
   1852            },
   1853            Self::Negate(ref value) | Self::Invert(ref value) => {
   1854                value.to_css_impl(dest, ArgumentLevel::Nested)?
   1855            },
   1856            Self::Sum(ref children) => {
   1857                let mut first = true;
   1858                for child in &**children {
   1859                    if !first {
   1860                        match child {
   1861                            Self::Leaf(l) => {
   1862                                if let Ok(true) = l.is_negative() {
   1863                                    dest.write_str(" - ")?;
   1864                                    let mut negated = l.clone();
   1865                                    // We can unwrap here, because we already
   1866                                    // checked if the value inside is negative.
   1867                                    negated.map(std::ops::Neg::neg).unwrap();
   1868                                    negated.to_css(dest)?;
   1869                                } else {
   1870                                    dest.write_str(" + ")?;
   1871                                    l.to_css(dest)?;
   1872                                }
   1873                            },
   1874                            Self::Negate(n) => {
   1875                                dest.write_str(" - ")?;
   1876                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
   1877                            },
   1878                            _ => {
   1879                                dest.write_str(" + ")?;
   1880                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
   1881                            },
   1882                        }
   1883                    } else {
   1884                        first = false;
   1885                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
   1886                    }
   1887                }
   1888            },
   1889            Self::Product(ref children) => {
   1890                let mut first = true;
   1891                for child in &**children {
   1892                    if !first {
   1893                        match child {
   1894                            Self::Invert(n) => {
   1895                                dest.write_str(" / ")?;
   1896                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
   1897                            },
   1898                            _ => {
   1899                                dest.write_str(" * ")?;
   1900                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
   1901                            },
   1902                        }
   1903                    } else {
   1904                        first = false;
   1905                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
   1906                    }
   1907                }
   1908            },
   1909            Self::Clamp {
   1910                ref min,
   1911                ref center,
   1912                ref max,
   1913            } => {
   1914                min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1915                dest.write_str(", ")?;
   1916                center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1917                dest.write_str(", ")?;
   1918                max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1919            },
   1920            Self::Round {
   1921                ref value,
   1922                ref step,
   1923                ..
   1924            } => {
   1925                value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1926                dest.write_str(", ")?;
   1927                step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1928            },
   1929            Self::ModRem {
   1930                ref dividend,
   1931                ref divisor,
   1932                ..
   1933            } => {
   1934                dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1935                dest.write_str(", ")?;
   1936                divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
   1937            },
   1938            Self::Abs(ref v) | Self::Sign(ref v) => {
   1939                v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
   1940            },
   1941            Self::Leaf(ref l) => l.to_css(dest)?,
   1942            Self::Anchor(ref f) => f.to_css(dest)?,
   1943            Self::AnchorSize(ref f) => f.to_css(dest)?,
   1944        }
   1945 
   1946        if write_closing_paren {
   1947            dest.write_char(')')?;
   1948        }
   1949        Ok(())
   1950    }
   1951 
   1952    fn to_typed_impl(&self, level: ArgumentLevel) -> Option<TypedValue> {
   1953        // XXX Only supporting Sum and Leaf for now
   1954        match *self {
   1955            Self::Sum(ref children) => {
   1956                let mut values = ThinVec::new();
   1957                for child in &**children {
   1958                    if let Some(TypedValue::Numeric(inner)) =
   1959                        child.to_typed_impl(ArgumentLevel::Nested)
   1960                    {
   1961                        values.push(inner);
   1962                    }
   1963                }
   1964                Some(TypedValue::Numeric(NumericValue::Sum { values }))
   1965            },
   1966            Self::Leaf(ref l) => match l.to_typed() {
   1967                Some(TypedValue::Numeric(inner)) => match level {
   1968                    ArgumentLevel::CalculationRoot => {
   1969                        Some(TypedValue::Numeric(NumericValue::Sum {
   1970                            values: ThinVec::from([inner]),
   1971                        }))
   1972                    },
   1973                    ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => {
   1974                        Some(TypedValue::Numeric(inner))
   1975                    },
   1976                },
   1977                _ => None,
   1978            },
   1979            _ => None,
   1980        }
   1981    }
   1982 
   1983    fn compare(
   1984        &self,
   1985        other: &Self,
   1986        basis_positive: PositivePercentageBasis,
   1987    ) -> Option<cmp::Ordering> {
   1988        match (self, other) {
   1989            (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
   1990                one.compare(other, basis_positive)
   1991            },
   1992            _ => None,
   1993        }
   1994    }
   1995 
   1996    compare_helpers!();
   1997 }
   1998 
   1999 impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
   2000    /// <https://drafts.csswg.org/css-values/#calc-serialize>
   2001    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
   2002    where
   2003        W: Write,
   2004    {
   2005        self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
   2006    }
   2007 }
   2008 
   2009 impl<L: CalcNodeLeaf> ToTyped for CalcNode<L> {
   2010    fn to_typed(&self) -> Option<TypedValue> {
   2011        self.to_typed_impl(ArgumentLevel::CalculationRoot)
   2012    }
   2013 }
   2014 
   2015 #[cfg(test)]
   2016 mod tests {
   2017    use super::*;
   2018 
   2019    #[test]
   2020    fn can_sum_with_checks() {
   2021        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH));
   2022        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::PERCENTAGE));
   2023        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
   2024 
   2025        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
   2026        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
   2027        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
   2028 
   2029        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
   2030        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
   2031        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
   2032 
   2033        assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::TIME));
   2034        assert!(CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE));
   2035 
   2036        assert!(!(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE));
   2037        assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME));
   2038        assert!(
   2039            !(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME)
   2040        );
   2041    }
   2042 }