style/values/generics/
calc.rs

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