Skip to main content

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::typed_om::{
11    MathClamp, MathInvert, MathMax, MathMin, MathNegate, MathProduct, MathSum, MathValue,
12    NumericBaseType, NumericType, NumericValue, ToTyped, TypedValue,
13};
14use crate::values::generics::length::GenericAnchorSizeFunction;
15use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide};
16use crate::values::generics::Optional;
17use num_traits::Zero;
18use smallvec::SmallVec;
19use std::convert::AsRef;
20use std::fmt::{self, Write};
21use std::ops::{Add, Mul, Rem, Sub};
22use std::{cmp, mem};
23use strum_macros::AsRefStr;
24use style_traits::{CssWriter, ToCss};
25
26use thin_vec::ThinVec;
27
28/// Whether we're a `min` or `max` function.
29#[derive(
30    Clone,
31    Copy,
32    Debug,
33    Deserialize,
34    MallocSizeOf,
35    PartialEq,
36    Serialize,
37    ToAnimatedZero,
38    ToResolvedValue,
39    ToShmem,
40)]
41#[repr(u8)]
42pub enum MinMaxOp {
43    /// `min()`
44    Min,
45    /// `max()`
46    Max,
47}
48
49/// Whether we're a `mod` or `rem` function.
50#[derive(
51    Clone,
52    Copy,
53    Debug,
54    Deserialize,
55    MallocSizeOf,
56    PartialEq,
57    Serialize,
58    ToAnimatedZero,
59    ToResolvedValue,
60    ToShmem,
61)]
62#[repr(u8)]
63pub enum ModRemOp {
64    /// `mod()`
65    Mod,
66    /// `rem()`
67    Rem,
68}
69
70impl ModRemOp {
71    fn apply(self, dividend: f32, divisor: f32) -> f32 {
72        // In mod(A, B) only, if B is infinite and A has opposite sign to B
73        // (including an oppositely-signed zero), the result is NaN.
74        // https://drafts.csswg.org/css-values/#round-infinities
75        if matches!(self, Self::Mod)
76            && divisor.is_infinite()
77            && dividend.is_sign_negative() != divisor.is_sign_negative()
78        {
79            return f32::NAN;
80        }
81
82        let (r, same_sign_as) = match self {
83            Self::Mod => (dividend - divisor * (dividend / divisor).floor(), divisor),
84            Self::Rem => (dividend - divisor * (dividend / divisor).trunc(), dividend),
85        };
86        if r == 0.0 && same_sign_as.is_sign_negative() {
87            -0.0
88        } else {
89            r
90        }
91    }
92}
93
94/// The strategy used in `round()`
95#[derive(
96    Clone,
97    Copy,
98    Debug,
99    Deserialize,
100    MallocSizeOf,
101    PartialEq,
102    Serialize,
103    ToAnimatedZero,
104    ToResolvedValue,
105    ToShmem,
106)]
107#[repr(u8)]
108pub enum RoundingStrategy {
109    /// `round(nearest, a, b)`
110    /// round a to the nearest multiple of b
111    Nearest,
112    /// `round(up, a, b)`
113    /// round a up to the nearest multiple of b
114    Up,
115    /// `round(down, a, b)`
116    /// round a down to the nearest multiple of b
117    Down,
118    /// `round(to-zero, a, b)`
119    /// round a to the nearest multiple of b that is towards zero
120    ToZero,
121}
122
123/// The clamping mode used in `progress()`
124#[derive(
125    Clone,
126    Copy,
127    Debug,
128    Deserialize,
129    MallocSizeOf,
130    Parse,
131    PartialEq,
132    Serialize,
133    ToAnimatedZero,
134    ToCss,
135    ToResolvedValue,
136    ToShmem,
137)]
138#[repr(u8)]
139pub enum ProgressClampingMode {
140    /// `progress(value, start, end)`
141    /// Progress result is clamped to the range [0, 1}.
142    #[css(skip)]
143    Clamp,
144    /// `progress(no-clamp value, start, end)`
145    /// Progress result can be any number.
146    NoClamp,
147}
148
149impl ProgressClampingMode {
150    fn evaluate(self, value: f32, start: f32, end: f32) -> f32 {
151        if start == end && self == Self::Clamp {
152            return 0.;
153        }
154        let progress = crate::values::normalize((value - start) / (end - start));
155        match self {
156            Self::Clamp => progress.max(0.).min(1.),
157            Self::NoClamp => progress,
158        }
159    }
160}
161
162/// This determines the order in which we serialize members of a calc() sum.
163///
164/// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children
165#[derive(
166    AsRefStr, Clone, Copy, Debug, Eq, Ord, Parse, PartialEq, PartialOrd, MallocSizeOf, ToShmem,
167)]
168#[strum(serialize_all = "lowercase")]
169#[allow(missing_docs)]
170pub enum SortKey {
171    #[strum(serialize = "")]
172    Number,
173    #[css(skip)]
174    #[strum(serialize = "%")]
175    Percentage,
176    Cap,
177    Ch,
178    Cqb,
179    Cqh,
180    Cqi,
181    Cqmax,
182    Cqmin,
183    Cqw,
184    Deg,
185    Dppx,
186    Dvb,
187    Dvh,
188    Dvi,
189    Dvmax,
190    Dvmin,
191    Dvw,
192    Em,
193    Ex,
194    Ic,
195    Lh,
196    Lvb,
197    Lvh,
198    Lvi,
199    Lvmax,
200    Lvmin,
201    Lvw,
202    Ms,
203    Px,
204    Rcap,
205    Rch,
206    Rem,
207    Rex,
208    Ric,
209    Rlh,
210    S, // Sec
211    Svb,
212    Svh,
213    Svi,
214    Svmax,
215    Svmin,
216    Svw,
217    Vb,
218    Vh,
219    Vi,
220    Vmax,
221    Vmin,
222    Vw,
223    #[css(skip)]
224    ColorComponent,
225    #[css(skip)]
226    Other,
227}
228
229/// Fallback type for anchor functions within `calc()`.
230/// Ideally, the fallback type is initial type of the property (e.g.
231/// `GenericInset` for `left`), but that causes circular reference.
232/// TODO(dshin, bug 2034100): Investigate ways to not require this.
233/// This handles the parsing of unitless zeros, as well as ensuring
234/// that e.g. `calc(anchor(--foo left, 1px) + 10%)` round trips
235/// (sorting aside), instead of becoming
236/// `calc(anchor(--foo left, calc(1px)) + 10%)`.
237#[repr(C)]
238#[derive(
239    Clone,
240    Debug,
241    Deserialize,
242    MallocSizeOf,
243    PartialEq,
244    Serialize,
245    ToAnimatedZero,
246    ToResolvedValue,
247    ToShmem,
248)]
249pub struct GenericAnchorFunctionFallback<L> {
250    /// Was this node parsed as a calc node?
251    #[animation(constant)]
252    is_calc_node: bool,
253    /// The parsed fallback value. Stored as a calc node to break
254    /// the circular reference.
255    pub node: GenericCalcNode<L>,
256}
257
258impl<L> GenericAnchorFunctionFallback<L> {
259    /// Create a new anchor function fallback value.
260    pub fn new(is_calc_node: bool, node: GenericCalcNode<L>) -> Self {
261        Self { is_calc_node, node }
262    }
263}
264
265impl<L: CalcNodeLeaf> ToCss for GenericAnchorFunctionFallback<L> {
266    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
267    where
268        W: Write,
269    {
270        self.node.to_css_impl(
271            dest,
272            if self.is_calc_node {
273                ArgumentLevel::CalculationRoot
274            } else {
275                ArgumentLevel::ArgumentRoot
276            },
277        )
278    }
279}
280
281/// `anchor()` function used in math functions.
282pub type GenericCalcAnchorFunction<L> =
283    GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericAnchorFunctionFallback<L>>>;
284/// `anchor-size()` function used in math functions.
285pub type GenericCalcAnchorSizeFunction<L> =
286    GenericAnchorSizeFunction<Box<GenericAnchorFunctionFallback<L>>>;
287
288/// A generic node in a calc expression.
289///
290/// FIXME: This would be much more elegant if we used `Self` in the types below,
291/// but we can't because of https://github.com/serde-rs/serde/issues/1565.
292///
293/// FIXME: The following annotations are to workaround an LLVM inlining bug, see
294/// bug 1631929.
295///
296/// cbindgen:destructor-attributes=MOZ_NEVER_INLINE
297/// cbindgen:copy-constructor-attributes=MOZ_NEVER_INLINE
298/// cbindgen:eq-attributes=MOZ_NEVER_INLINE
299#[repr(u8)]
300#[derive(
301    Clone,
302    Debug,
303    Deserialize,
304    MallocSizeOf,
305    PartialEq,
306    Serialize,
307    ToAnimatedZero,
308    ToResolvedValue,
309    ToShmem,
310)]
311pub enum GenericCalcNode<L> {
312    /// A leaf node.
313    Leaf(L),
314    /// A node that negates its child, e.g. Negate(1) == -1.
315    Negate(Box<Self>),
316    /// A node that inverts its child, e.g. Invert(10) == 1 / 10 == 0.1. The child must always
317    /// resolve to a number unit.
318    Invert(Box<Self>),
319    /// A sum node, representing `a + b + c` where a, b, and c are the
320    /// arguments.
321    Sum(crate::OwnedSlice<Self>),
322    /// A product node, representing `a * b * c` where a, b, and c are the
323    /// arguments.
324    Product(crate::OwnedSlice<Self>),
325    /// A `min` or `max` function.
326    MinMax(crate::OwnedSlice<Self>, MinMaxOp),
327    /// A `clamp()` function.
328    Clamp {
329        /// The minimum value.
330        min: Box<Self>,
331        /// The central value.
332        center: Box<Self>,
333        /// The maximum value.
334        max: Box<Self>,
335    },
336    /// A `round()` function.
337    Round {
338        /// The rounding strategy.
339        strategy: RoundingStrategy,
340        /// The value to round.
341        value: Box<Self>,
342        /// The step value.
343        step: Box<Self>,
344    },
345    /// A `mod()` or `rem()` function.
346    ModRem {
347        /// The dividend calculation.
348        dividend: Box<Self>,
349        /// The divisor calculation.
350        divisor: Box<Self>,
351        /// Is the function mod or rem?
352        op: ModRemOp,
353    },
354    /// A `sin()` function.
355    Sin(Box<Self>),
356    /// A `cos()` function.
357    Cos(Box<Self>),
358    /// A `tan()` function.
359    Tan(Box<Self>),
360    /// An `asin()` function.
361    Asin(Box<Self>),
362    /// An `acos()` function.
363    Acos(Box<Self>),
364    /// An `atan()` function.
365    Atan(Box<Self>),
366    /// An `atan2()` function.
367    Atan2(Box<Self>, Box<Self>),
368    /// A `pow()` function.
369    Pow(Box<Self>, Box<Self>),
370    /// A `sqrt()` function.
371    Sqrt(Box<Self>),
372    /// A `hypot()` function
373    Hypot(crate::OwnedSlice<Self>),
374    /// A `log()` function.
375    Log(Box<Self>, Optional<Box<Self>>),
376    /// An `exp()` function.
377    Exp(Box<Self>),
378    /// An `abs()` function.
379    Abs(Box<Self>),
380    /// A `sign()` function.
381    Sign(Box<Self>),
382    /// A `progress()` function.
383    Progress {
384        /// Clamping mode for the result.
385        clamping_mode: ProgressClampingMode,
386        /// The progress value calculation.
387        value: Box<Self>,
388        /// The progress start calculation.
389        start: Box<Self>,
390        /// The progress end calculation.
391        end: Box<Self>,
392    },
393    /// An `anchor()` function.
394    Anchor(Box<GenericCalcAnchorFunction<L>>),
395    /// An `anchor-size()` function.
396    AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>),
397}
398
399pub use self::GenericCalcNode as CalcNode;
400
401fn typed_arithmetic_enabled() -> bool {
402    crate::pref!("layout.css.calc-typed-arithmetic.enabled")
403}
404
405/// The non-mixed types that a math function can return. Note that
406/// <integer> is not represented in this list as a separate type from
407/// <number>, as "math functions that resolve to <number> can be used
408/// in any place that only accepts <integer>". CSS Typed OM also does
409/// not distinguish between numbers and integers.
410///
411/// https://drafts.csswg.org/css-values-4/#math-function
412/// https://drafts.csswg.org/css-values-4/#calc-type-checking
413///
414/// TODO(Bug 1866236) - Add the <flex> type.
415#[derive(Clone, Copy, PartialEq, Eq)]
416#[repr(u8)]
417pub enum CalcType {
418    /// <length>
419    Length,
420    /// <percentage>
421    Percentage,
422    /// <angle>
423    Angle,
424    /// <time>
425    Time,
426    /// <resolution>
427    Resolution,
428    /// <number>
429    Number,
430}
431
432/// The value of a percentage leaf node that contains an associated percent hint.
433#[derive(
434    Clone,
435    Copy,
436    Debug,
437    Deserialize,
438    MallocSizeOf,
439    PartialEq,
440    Serialize,
441    ToAnimatedZero,
442    ToCss,
443    ToResolvedValue,
444    ToShmem,
445    ToTyped,
446)]
447#[repr(C)]
448pub struct GenericCalcPercentageLeaf<P> {
449    /// The percentage value.
450    pub value: P,
451    /// The base type the percentage resolves against, or None if there is
452    /// no specific percent hint (this is used by CSS Typed OM when parsing
453    /// an expression without the context of a property).
454    #[css(skip)]
455    pub hint: Optional<NumericBaseType>,
456}
457
458impl<P> GenericCalcPercentageLeaf<P>
459where
460    P: From<f32> + Copy,
461    f32: From<P>,
462{
463    /// Builds a percentage leaf with the given percent hint.
464    pub fn new(value: f32, hint: Optional<NumericBaseType>) -> Self {
465        Self {
466            value: P::from(value),
467            hint,
468        }
469    }
470
471    /// Returns the percentage value as a float.
472    pub fn get(&self) -> f32 {
473        f32::from(self.value)
474    }
475
476    /// Returns the numeric type of this percentage.
477    pub fn numeric_type(&self) -> NumericType {
478        match self.hint {
479            Optional::Some(hint) => NumericType::percent().with_percent_hint(hint),
480            Optional::None => NumericType::percent(),
481        }
482    }
483
484    /// Returns the percent hint to use when merging two percentages with an arithmetic
485    /// operation. Mismatched hints should be impossible after type checking.
486    pub fn combined_hint(&self, other: &Self) -> Optional<NumericBaseType> {
487        debug_assert_eq!(
488            self.hint, other.hint,
489            "Merging percentages with mismatched hints"
490        );
491        self.hint
492    }
493}
494
495macro_rules! compare_helpers {
496    () => {
497        /// Return whether a leaf is greater than another.
498        #[allow(unused)]
499        fn gt(&self, other: &Self) -> bool {
500            self.compare(other) == Some(cmp::Ordering::Greater)
501        }
502
503        /// Return whether a leaf is less than another.
504        fn lt(&self, other: &Self) -> bool {
505            self.compare(other) == Some(cmp::Ordering::Less)
506        }
507
508        /// Return whether a leaf is smaller or equal than another.
509        fn lte(&self, other: &Self) -> bool {
510            match self.compare(other) {
511                Some(cmp::Ordering::Less) => true,
512                Some(cmp::Ordering::Equal) => true,
513                Some(cmp::Ordering::Greater) => false,
514                None => false,
515            }
516        }
517    };
518}
519
520/// A trait that represents all the stuff a valid leaf of a calc expression.
521pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss + ToTyped + fmt::Debug {
522    /// Returns the type of the leaf.
523    fn numeric_type(&self) -> NumericType;
524
525    /// Returns the unitless value of this leaf if one is available.
526    fn unitless_value(&self) -> Option<f32>;
527
528    /// Returns the value and percent hint if this leaf is a percentage.
529    fn as_percentage(&self) -> Option<(f32, Optional<NumericBaseType>)>;
530
531    /// Returns the canonical value of this leaf in the type's canonical unit,
532    /// if there is enough information to determine its numeric value.
533    /// https://drafts.csswg.org/css-values-4/#simplify-a-calculation-tree
534    fn canonical_value(&self) -> Option<f32>;
535
536    /// Returns the angle value in radians if this leaf is an angle.
537    fn as_angle_radians(&self) -> Option<f32>;
538
539    /// Creates a new angle leaf from a value in radians.
540    fn new_angle_from_radians(radians: f32) -> Self;
541
542    /// Return true if the units of both leaves are equal. (NOTE: Does not take
543    /// the values into account)
544    fn is_same_unit_as(&self, other: &Self) -> bool {
545        std::mem::discriminant(self) == std::mem::discriminant(other)
546    }
547
548    /// Do a partial comparison of these values.
549    fn compare(&self, other: &Self) -> Option<cmp::Ordering>;
550    compare_helpers!();
551
552    /// Create a new leaf with a number value.
553    fn new_number(value: f32) -> Self;
554
555    /// Returns a float value if the leaf is a number.
556    fn as_number(&self) -> Option<f32>;
557
558    /// Returns a number or angle radians if the leaf is a number or angle.
559    fn as_number_or_angle_radians(&self) -> Option<f32> {
560        self.as_number().or_else(|| self.as_angle_radians())
561    }
562
563    /// Create a new leaf with `value` in the canonical unit of the given type.
564    /// Returns Err(()) if the type cannot be constructed as a leaf.
565    fn new_from_typed_value(value: f32, numeric_type: NumericType) -> Result<Self, ()>;
566
567    /// Whether this value is known-negative.
568    fn is_negative(&self) -> Result<bool, ()> {
569        self.unitless_value()
570            .map(|v| Ok(v.is_sign_negative()))
571            .unwrap_or_else(|| Err(()))
572    }
573
574    /// Whether this value is infinite.
575    fn is_infinite(&self) -> Result<bool, ()> {
576        self.unitless_value()
577            .map(|v| Ok(v.is_infinite()))
578            .unwrap_or_else(|| Err(()))
579    }
580
581    /// Whether this value is zero.
582    fn is_zero(&self) -> Result<bool, ()> {
583        self.unitless_value()
584            .map(|v| Ok(v.is_zero()))
585            .unwrap_or_else(|| Err(()))
586    }
587
588    /// Whether this value is NaN.
589    fn is_nan(&self) -> Result<bool, ()> {
590        self.unitless_value()
591            .map(|v| Ok(v.is_nan()))
592            .unwrap_or_else(|| Err(()))
593    }
594
595    /// Tries to merge one leaf into another using the sum, that is, perform `x` + `y`.
596    fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
597
598    /// Try to merge the right leaf into the left by using a multiplication. Return true if the
599    /// merge was successful, otherwise false.
600    fn try_product_in_place(&mut self, other: &mut Self) -> bool;
601
602    /// Tries a generic arithmetic operation.
603    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
604    where
605        O: Fn(f32, f32) -> f32;
606
607    /// Map the value of this node with the given operation.
608    fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>;
609
610    /// Canonicalizes the expression if necessary.
611    fn simplify(&mut self) -> SimplificationResult;
612
613    /// Returns the sort key for simplification.
614    fn sort_key(&self) -> SortKey;
615
616    /// Create a new leaf containing the sign() result of the given leaf.
617    fn sign_from(leaf: &impl CalcNodeLeaf) -> Result<Self, ()> {
618        // Percentages with a non-<percent> hint are relative to some basis value, and since the basis value is
619        // unknown at this stage, the actual sign of the percentage value is also unknown.
620        if leaf
621            .as_percentage()
622            .is_some_and(|(_, hint)| hint != Optional::Some(NumericBaseType::Percent))
623        {
624            return Err(());
625        }
626
627        let Some(value) = leaf.unitless_value() else {
628            return Err(());
629        };
630
631        Ok(Self::new_number(crate::values::calc_sign(value)))
632    }
633
634    /// Whether this leaf node should serialize with a `calc()` wrapper
635    /// if this node is the root of the calculation tree.
636    fn should_serialize_with_root_calc_wrapper(&self) -> bool {
637        true
638    }
639}
640
641/// The level of any argument being serialized in `to_css_impl`.
642#[derive(Clone)]
643enum ArgumentLevel {
644    /// The root of a calculation tree.
645    CalculationRoot,
646    /// The root of an operand node's argument, e.g. `min(10, 20)`, `10` and `20` will have this
647    /// level, but min in this case will have `TopMost`.
648    ArgumentRoot,
649    /// Any other values serialized in the tree.
650    Nested,
651}
652
653/// The result of simplify_and_sort_direct_children
654#[derive(Clone, Copy)]
655pub enum SimplificationResult {
656    /// This node (Or some of its descendants, if any) was simplified.
657    Simplified,
658    /// The children was unchanged.
659    Unchanged,
660}
661
662impl<L: CalcNodeLeaf> CalcNode<L> {
663    /// Create a dummy CalcNode that can be used to do replacements of other nodes.
664    fn dummy() -> Self {
665        Self::MinMax(Default::default(), MinMaxOp::Max)
666    }
667
668    /// Change all the leaf nodes to have the given value. This is useful when
669    /// you have `calc(1px * nan)` and you want to replace the product node with
670    /// `calc(nan)`, in which case the unit will be retained.
671    fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
672        self.map(|_| value)
673    }
674
675    /// Return true if a product is distributive over this node.
676    /// Is distributive: (2 + 3) * 4 = 8 + 12
677    /// Not distributive: sign(2 + 3) * 4 != sign(8 + 12)
678    #[inline]
679    pub fn is_product_distributive(&self) -> bool {
680        match self {
681            // If there's no value, we can't distribute the product.
682            Self::Leaf(l) => l.unitless_value().is_some(),
683            Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()),
684            _ => false,
685        }
686    }
687
688    /// If the node has a valid type outcome, then return it, otherwise fail. Note that this
689    /// type may not represent a valid CSS production and it is the responsibility of the caller
690    /// to determine whether this type is acceptable (see NumericType::as_calc_type).
691    pub fn numeric_type(&self) -> Result<NumericType, ()> {
692        Ok(match self {
693            CalcNode::Leaf(l) => l.numeric_type(),
694            CalcNode::Negate(child) | CalcNode::Abs(child) => child.numeric_type()?,
695            CalcNode::Sum(children) => {
696                let mut ty = children.first().unwrap().numeric_type()?;
697                for child in children.iter().skip(1) {
698                    let child_ty = child.numeric_type()?;
699                    ty = NumericType::add_two_types(&ty, &child_ty)?;
700                }
701                ty
702            },
703            CalcNode::Product(children) => {
704                let mut ty = children.first().unwrap().numeric_type()?;
705
706                for child in children.iter().skip(1) {
707                    let child_ty = child.numeric_type()?;
708
709                    // When typed arithmetic is not enabled, at most one side of the multiplication
710                    // operation can have a non-number type.
711                    if !typed_arithmetic_enabled() && !ty.is_number() && !child_ty.is_number() {
712                        return Err(());
713                    }
714
715                    ty = NumericType::multiply_two_types(&ty, &child_ty)?;
716                }
717
718                ty
719            },
720            CalcNode::MinMax(children, _) | CalcNode::Hypot(children) => {
721                let mut ty = children.first().unwrap().numeric_type()?;
722                for child in children.iter().skip(1) {
723                    let child_ty = child.numeric_type()?;
724                    ty = NumericType::add_two_types(&ty, &child_ty)?;
725                }
726                ty
727            },
728            CalcNode::Clamp { min, center, max } => {
729                let min_ty = min.numeric_type()?;
730                let center_ty = center.numeric_type()?;
731                let max_ty = max.numeric_type()?;
732
733                let mut ty = NumericType::add_two_types(&min_ty, &center_ty)?;
734                ty = NumericType::add_two_types(&ty, &max_ty)?;
735                ty
736            },
737            CalcNode::Round { value, step, .. } => {
738                let value_ty = value.numeric_type()?;
739                let step_ty = step.numeric_type()?;
740                NumericType::add_two_types(&value_ty, &step_ty)?
741            },
742            CalcNode::ModRem {
743                dividend, divisor, ..
744            } => {
745                let dividend_ty = dividend.numeric_type()?;
746                let divisor_ty = divisor.numeric_type()?;
747                NumericType::add_two_types(&dividend_ty, &divisor_ty)?
748            },
749            CalcNode::Sign(child) => {
750                // sign() always resolves to a number, but we still need to make sure that the
751                // child units make sense.
752                let _ = child.numeric_type()?;
753                NumericType::number()
754            },
755            CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => {
756                NumericType::length().with_percent_hint(NumericBaseType::Length)
757            },
758            CalcNode::Sin(child) | CalcNode::Cos(child) | CalcNode::Tan(child) => {
759                let child_ty = child.numeric_type_as_calc_type()?;
760                if child_ty != CalcType::Number && child_ty != CalcType::Angle {
761                    return Err(());
762                }
763                NumericType::number()
764            },
765            CalcNode::Asin(child) | CalcNode::Acos(child) | CalcNode::Atan(child) => {
766                if child.numeric_type_as_calc_type()? != CalcType::Number {
767                    return Err(());
768                }
769                NumericType::angle()
770            },
771            CalcNode::Atan2(a, b) => {
772                // Ensure that the types of a and b can be made consistent
773                let a_ty = a.numeric_type()?;
774                let b_ty = b.numeric_type()?;
775                let _ = NumericType::add_two_types(&a_ty, &b_ty)?;
776                NumericType::angle()
777            },
778            CalcNode::Pow(a, b) => {
779                let a_ty = a.numeric_type_as_calc_type()?;
780                let b_ty = b.numeric_type_as_calc_type()?;
781                if a_ty != CalcType::Number || b_ty != CalcType::Number {
782                    return Err(());
783                }
784                NumericType::number()
785            },
786            CalcNode::Invert(c) => {
787                if typed_arithmetic_enabled() {
788                    let mut ty = c.numeric_type()?;
789                    ty.invert();
790                    ty
791                } else {
792                    if c.numeric_type_as_calc_type()? != CalcType::Number {
793                        return Err(());
794                    }
795                    NumericType::number()
796                }
797            },
798            CalcNode::Sqrt(c) | CalcNode::Exp(c) => {
799                if c.numeric_type_as_calc_type()? != CalcType::Number {
800                    return Err(());
801                }
802                NumericType::number()
803            },
804            CalcNode::Log(a, b) => {
805                let a_ty = a.numeric_type_as_calc_type()?;
806                let b_ty = match b {
807                    Optional::Some(b) => b.numeric_type_as_calc_type()?,
808                    Optional::None => CalcType::Number,
809                };
810                if a_ty != CalcType::Number || b_ty != CalcType::Number {
811                    return Err(());
812                }
813                NumericType::number()
814            },
815            CalcNode::Progress {
816                value, start, end, ..
817            } => {
818                let value_ty = value.numeric_type()?;
819                let start_ty = start.numeric_type()?;
820                let end_ty = end.numeric_type()?;
821
822                // Ensure that the types of the arguments are consistent.
823                let _ = NumericType::add_two_types(&value_ty, &start_ty)?;
824                let _ = NumericType::add_two_types(&value_ty, &end_ty)?;
825                NumericType::number()
826            },
827        })
828    }
829
830    /// If the node has a valid type outcome that matches one of the types that a calculation
831    /// can produce, then return it, otherwise fail.
832    pub fn numeric_type_as_calc_type(&self) -> Result<CalcType, ()> {
833        self.numeric_type()?.as_calc_type()
834    }
835
836    /// Negate the node inline.  If the node is distributive, it is replaced by the result,
837    /// otherwise the node is wrapped in a [`Negate`] node.
838    pub fn negate(&mut self) {
839        /// Node(params) -> Negate(Node(params))
840        fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
841            let result = mem::replace(s, CalcNode::dummy());
842            *s = CalcNode::Negate(Box::new(result));
843        }
844
845        match *self {
846            CalcNode::Leaf(ref mut leaf) => {
847                if leaf.map(std::ops::Neg::neg).is_err() {
848                    wrap_self_in_negate(self)
849                }
850            },
851            CalcNode::Negate(ref mut value) => {
852                // Don't negate the value here.  Replace `self` with it's child.
853                let result = mem::replace(value.as_mut(), Self::dummy());
854                *self = result;
855            },
856            CalcNode::Invert(_) => {
857                // -(1 / -10) == -(-0.1) == 0.1
858                wrap_self_in_negate(self)
859            },
860            CalcNode::Sum(ref mut children) => {
861                for child in children.iter_mut() {
862                    child.negate();
863                }
864            },
865            CalcNode::Product(_) => {
866                // -(2 * 3 / 4) == -(1.5)
867                wrap_self_in_negate(self);
868            },
869            CalcNode::MinMax(ref mut children, ref mut op) => {
870                for child in children.iter_mut() {
871                    child.negate();
872                }
873
874                // Negating min-max means the operation is swapped.
875                *op = match *op {
876                    MinMaxOp::Min => MinMaxOp::Max,
877                    MinMaxOp::Max => MinMaxOp::Min,
878                };
879            },
880            CalcNode::Clamp {
881                ref mut min,
882                ref mut center,
883                ref mut max,
884            } => {
885                if min.lte(max) {
886                    min.negate();
887                    center.negate();
888                    max.negate();
889
890                    mem::swap(min, max);
891                } else {
892                    wrap_self_in_negate(self);
893                }
894            },
895            CalcNode::Round {
896                ref mut strategy,
897                ref mut value,
898                ref mut step,
899            } => {
900                match *strategy {
901                    RoundingStrategy::Nearest => {
902                        // Nearest is tricky because we'd have to swap the
903                        // behavior at the half-way point from using the upper
904                        // to lower bound.
905                        // Simpler to just wrap self in a negate node.
906                        wrap_self_in_negate(self);
907                        return;
908                    },
909                    RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
910                    RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
911                    RoundingStrategy::ToZero => (),
912                }
913                value.negate();
914                step.negate();
915            },
916            CalcNode::ModRem {
917                ref mut dividend,
918                ref mut divisor,
919                ..
920            } => {
921                dividend.negate();
922                divisor.negate();
923            },
924            CalcNode::Hypot(ref mut children) => {
925                for child in children.iter_mut() {
926                    child.negate();
927                }
928            },
929            CalcNode::Sign(ref mut child) => {
930                child.negate();
931            },
932            CalcNode::Sin(..)
933            | CalcNode::Cos(..)
934            | CalcNode::Tan(..)
935            | CalcNode::Asin(..)
936            | CalcNode::Acos(..)
937            | CalcNode::Atan(..)
938            | CalcNode::Atan2(..)
939            | CalcNode::Pow(..)
940            | CalcNode::Sqrt(..)
941            | CalcNode::Log(..)
942            | CalcNode::Exp(..)
943            | CalcNode::Abs(..)
944            | CalcNode::Progress { .. }
945            | CalcNode::Anchor(..)
946            | CalcNode::AnchorSize(..) => {
947                wrap_self_in_negate(self);
948            },
949        }
950    }
951
952    fn sort_key(&self) -> SortKey {
953        match *self {
954            Self::Leaf(ref l) => l.sort_key(),
955            Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
956            _ => SortKey::Other,
957        }
958    }
959
960    /// Returns the leaf if we can (if simplification has allowed it).
961    pub fn as_leaf(&self) -> Option<&L> {
962        match *self {
963            Self::Leaf(ref l) => Some(l),
964            _ => None,
965        }
966    }
967
968    /// Tries to merge one node into another using the sum, that is, perform `x` + `y`.
969    pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
970        match (self, other) {
971            (&mut CalcNode::Leaf(ref mut one), CalcNode::Leaf(other)) => {
972                one.try_sum_in_place(other)
973            },
974            _ => Err(()),
975        }
976    }
977
978    /// Tries to merge one node into another using the product, that is, perform `x` * `y`.
979    pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
980        if let Ok(resolved) = other.resolve() {
981            if let Some(number) = resolved.as_number() {
982                if number == 1.0 {
983                    return true;
984                }
985
986                if self.is_product_distributive() {
987                    if self.map(|v| v * number).is_err() {
988                        return false;
989                    }
990                    return true;
991                }
992            }
993        }
994
995        if let Ok(resolved) = self.resolve() {
996            if let Some(number) = resolved.as_number() {
997                if number == 1.0 {
998                    std::mem::swap(self, other);
999                    return true;
1000                }
1001
1002                if other.is_product_distributive() {
1003                    if other.map(|v| v * number).is_err() {
1004                        return false;
1005                    }
1006                    std::mem::swap(self, other);
1007                    return true;
1008                }
1009            }
1010        }
1011
1012        false
1013    }
1014
1015    /// Tries to apply a generic arithmetic operator
1016    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
1017    where
1018        O: Fn(f32, f32) -> f32,
1019    {
1020        match (self, other) {
1021            (CalcNode::Leaf(one), CalcNode::Leaf(other)) => {
1022                Ok(CalcNode::Leaf(one.try_op(other, op)?))
1023            },
1024            _ => Err(()),
1025        }
1026    }
1027
1028    /// Map the value of this node with the given operation.
1029    pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
1030        fn map_internal<L: CalcNodeLeaf>(
1031            node: &mut CalcNode<L>,
1032            op: &mut impl FnMut(f32) -> f32,
1033        ) -> Result<(), ()> {
1034            match node {
1035                CalcNode::Leaf(l) => l.map(op),
1036                CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
1037                CalcNode::Sum(children) | CalcNode::Product(children) => {
1038                    for node in &mut **children {
1039                        map_internal(node, op)?;
1040                    }
1041                    Ok(())
1042                },
1043                CalcNode::MinMax(children, _) => {
1044                    for node in &mut **children {
1045                        map_internal(node, op)?;
1046                    }
1047                    Ok(())
1048                },
1049                CalcNode::Clamp { min, center, max } => {
1050                    map_internal(min, op)?;
1051                    map_internal(center, op)?;
1052                    map_internal(max, op)
1053                },
1054                CalcNode::Round { value, step, .. } => {
1055                    map_internal(value, op)?;
1056                    map_internal(step, op)
1057                },
1058                CalcNode::ModRem {
1059                    dividend, divisor, ..
1060                } => {
1061                    map_internal(dividend, op)?;
1062                    map_internal(divisor, op)
1063                },
1064                CalcNode::Hypot(children) => {
1065                    for node in &mut **children {
1066                        map_internal(node, op)?;
1067                    }
1068                    Ok(())
1069                },
1070                CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
1071                // It is invalid to treat inner `CalcNode`s here - `anchor(--foo 50%) / 2` != `anchor(--foo 25%)`.
1072                // Same applies to fallback, as we don't know if it will be used. Similar reasoning applies to `anchor-size()`.
1073                CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
1074                // Trig functions are nonlinear: 2 * sin(x) != sin(2*x).
1075                // Similarly for pow/sqrt/log/exp.
1076                CalcNode::Sin(_)
1077                | CalcNode::Cos(_)
1078                | CalcNode::Tan(_)
1079                | CalcNode::Asin(_)
1080                | CalcNode::Acos(_)
1081                | CalcNode::Atan(_)
1082                | CalcNode::Atan2(..)
1083                | CalcNode::Pow(..)
1084                | CalcNode::Sqrt(_)
1085                | CalcNode::Log(..)
1086                | CalcNode::Exp(_)
1087                | CalcNode::Progress { .. } => Err(()),
1088            }
1089        }
1090
1091        map_internal(self, &mut op)
1092    }
1093
1094    /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind.
1095    pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
1096    where
1097        O: CalcNodeLeaf,
1098        F: FnMut(&L) -> O,
1099    {
1100        self.map_leaves_internal(&mut map)
1101    }
1102
1103    fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
1104    where
1105        O: CalcNodeLeaf,
1106        F: FnMut(&L) -> O,
1107    {
1108        fn map_children<L, O, F>(
1109            children: &[CalcNode<L>],
1110            map: &mut F,
1111        ) -> crate::OwnedSlice<CalcNode<O>>
1112        where
1113            L: CalcNodeLeaf,
1114            O: CalcNodeLeaf,
1115            F: FnMut(&L) -> O,
1116        {
1117            children
1118                .iter()
1119                .map(|c| c.map_leaves_internal(map))
1120                .collect()
1121        }
1122
1123        match *self {
1124            Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
1125            Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
1126            Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
1127            Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
1128            Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
1129            Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
1130            Self::Clamp {
1131                ref min,
1132                ref center,
1133                ref max,
1134            } => {
1135                let min = Box::new(min.map_leaves_internal(map));
1136                let center = Box::new(center.map_leaves_internal(map));
1137                let max = Box::new(max.map_leaves_internal(map));
1138                CalcNode::Clamp { min, center, max }
1139            },
1140            Self::Round {
1141                strategy,
1142                ref value,
1143                ref step,
1144            } => {
1145                let value = Box::new(value.map_leaves_internal(map));
1146                let step = Box::new(step.map_leaves_internal(map));
1147                CalcNode::Round {
1148                    strategy,
1149                    value,
1150                    step,
1151                }
1152            },
1153            Self::ModRem {
1154                ref dividend,
1155                ref divisor,
1156                op,
1157            } => {
1158                let dividend = Box::new(dividend.map_leaves_internal(map));
1159                let divisor = Box::new(divisor.map_leaves_internal(map));
1160                CalcNode::ModRem {
1161                    dividend,
1162                    divisor,
1163                    op,
1164                }
1165            },
1166            Self::Sin(ref c) => CalcNode::Sin(Box::new(c.map_leaves_internal(map))),
1167            Self::Cos(ref c) => CalcNode::Cos(Box::new(c.map_leaves_internal(map))),
1168            Self::Tan(ref c) => CalcNode::Tan(Box::new(c.map_leaves_internal(map))),
1169            Self::Asin(ref c) => CalcNode::Asin(Box::new(c.map_leaves_internal(map))),
1170            Self::Acos(ref c) => CalcNode::Acos(Box::new(c.map_leaves_internal(map))),
1171            Self::Atan(ref c) => CalcNode::Atan(Box::new(c.map_leaves_internal(map))),
1172            Self::Atan2(ref a, ref b) => CalcNode::Atan2(
1173                Box::new(a.map_leaves_internal(map)),
1174                Box::new(b.map_leaves_internal(map)),
1175            ),
1176            Self::Pow(ref a, ref b) => CalcNode::Pow(
1177                Box::new(a.map_leaves_internal(map)),
1178                Box::new(b.map_leaves_internal(map)),
1179            ),
1180            Self::Sqrt(ref c) => CalcNode::Sqrt(Box::new(c.map_leaves_internal(map))),
1181            Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
1182            Self::Log(ref a, ref b) => CalcNode::Log(
1183                Box::new(a.map_leaves_internal(map)),
1184                b.as_ref()
1185                    .map(|b| Box::new(b.map_leaves_internal(map)))
1186                    .into(),
1187            ),
1188            Self::Exp(ref c) => CalcNode::Exp(Box::new(c.map_leaves_internal(map))),
1189            Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
1190            Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
1191            Self::Progress {
1192                clamping_mode,
1193                ref value,
1194                ref start,
1195                ref end,
1196            } => {
1197                let value = Box::new(value.map_leaves_internal(map));
1198                let start = Box::new(start.map_leaves_internal(map));
1199                let end = Box::new(end.map_leaves_internal(map));
1200                CalcNode::Progress {
1201                    clamping_mode,
1202                    value,
1203                    start,
1204                    end,
1205                }
1206            },
1207            Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
1208                target_element: f.target_element.clone(),
1209                side: match &f.side {
1210                    GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
1211                    GenericAnchorSide::Percentage(p) => {
1212                        GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
1213                    },
1214                },
1215                fallback: f
1216                    .fallback
1217                    .as_ref()
1218                    .map(|fb| {
1219                        Box::new(GenericAnchorFunctionFallback::new(
1220                            fb.is_calc_node,
1221                            fb.node.map_leaves_internal(map),
1222                        ))
1223                    })
1224                    .into(),
1225            })),
1226            Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
1227                target_element: f.target_element.clone(),
1228                size: f.size,
1229                fallback: f
1230                    .fallback
1231                    .as_ref()
1232                    .map(|fb| {
1233                        Box::new(GenericAnchorFunctionFallback::new(
1234                            fb.is_calc_node,
1235                            fb.node.map_leaves_internal(map),
1236                        ))
1237                    })
1238                    .into(),
1239            })),
1240        }
1241    }
1242
1243    /// Resolve this node into a value.
1244    pub fn resolve(&self) -> Result<L, ()> {
1245        self.resolve_map(|l| Ok(l.clone()))
1246    }
1247
1248    /// Resolve this node into a value, given a function that maps the leaf values.
1249    pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
1250    where
1251        F: FnMut(&L) -> Result<L, ()>,
1252    {
1253        let (value, ty) = self.resolve_internal(&mut leaf_to_output_fn)?;
1254        L::new_from_typed_value(value, ty)
1255    }
1256
1257    fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<(f32, NumericType), ()>
1258    where
1259        F: FnMut(&L) -> Result<L, ()>,
1260    {
1261        match self {
1262            Self::Leaf(l) => {
1263                let result = leaf_to_output_fn(l)?;
1264                let value = result.canonical_value().ok_or(())?;
1265                let ty = result.numeric_type();
1266                Ok((value, ty))
1267            },
1268            Self::Negate(child) => {
1269                let (value, ty) = child.resolve_internal(leaf_to_output_fn)?;
1270                Ok((-value, ty))
1271            },
1272            Self::Invert(child) => {
1273                let (value, mut ty) = child.resolve_internal(leaf_to_output_fn)?;
1274                if !typed_arithmetic_enabled() && !ty.is_number() {
1275                    return Err(());
1276                }
1277                ty.invert();
1278                Ok((1.0 / value, ty))
1279            },
1280            Self::Sum(children) => {
1281                let (mut value, mut ty) = children[0].resolve_internal(leaf_to_output_fn)?;
1282
1283                for child in children.iter().skip(1) {
1284                    let (right, right_ty) = child.resolve_internal(leaf_to_output_fn)?;
1285                    value += right;
1286                    ty = NumericType::add_two_types(&ty, &right_ty)?;
1287                }
1288
1289                Ok((value, ty))
1290            },
1291            Self::Product(children) => {
1292                let (mut value, mut ty) = children[0].resolve_internal(leaf_to_output_fn)?;
1293
1294                for child in children.iter().skip(1) {
1295                    let (leaf, leaf_ty) = child.resolve_internal(leaf_to_output_fn)?;
1296
1297                    // When typed arithmetic is not enabled, at most one side of the multiplication
1298                    // operation can have a non-number type.
1299                    if !typed_arithmetic_enabled() && !ty.is_number() && !leaf_ty.is_number() {
1300                        return Err(());
1301                    }
1302
1303                    value *= leaf;
1304                    ty = NumericType::multiply_two_types(&ty, &leaf_ty)?;
1305                }
1306
1307                Ok((value, ty))
1308            },
1309            Self::MinMax(children, op) => {
1310                let (mut value, mut ty) = children[0].resolve_internal(leaf_to_output_fn)?;
1311
1312                if value.is_nan() {
1313                    return Ok((value, ty));
1314                }
1315
1316                for child in children.iter().skip(1) {
1317                    let (candidate, candidate_ty) = child.resolve_internal(leaf_to_output_fn)?;
1318
1319                    // Determine the consistent type (bailing out if the types are not consistent).
1320                    ty = NumericType::add_two_types(&ty, &candidate_ty)?;
1321
1322                    if candidate.is_nan() {
1323                        value = candidate;
1324                        break;
1325                    }
1326
1327                    value = match op {
1328                        MinMaxOp::Min => crate::values::calc_min(value, candidate),
1329                        MinMaxOp::Max => crate::values::calc_max(value, candidate),
1330                    };
1331                }
1332
1333                Ok((value, ty))
1334            },
1335            Self::Clamp { min, center, max } => {
1336                let (min, min_ty) = min.resolve_internal(leaf_to_output_fn)?;
1337                let (center, center_ty) = center.resolve_internal(leaf_to_output_fn)?;
1338                let (max, max_ty) = max.resolve_internal(leaf_to_output_fn)?;
1339
1340                let mut ty = NumericType::add_two_types(&min_ty, &center_ty)?;
1341                ty = NumericType::add_two_types(&ty, &max_ty)?;
1342
1343                if min.is_nan() {
1344                    return Ok((min, ty));
1345                }
1346
1347                if center.is_nan() {
1348                    return Ok((center, ty));
1349                }
1350
1351                if max.is_nan() {
1352                    return Ok((max, ty));
1353                }
1354
1355                // NOTE: clamp is max(min, min(center, max))
1356                let value = crate::values::calc_max(min, crate::values::calc_min(center, max));
1357                Ok((value, ty))
1358            },
1359            Self::Round {
1360                strategy,
1361                value,
1362                step,
1363            } => {
1364                let (mut value, value_ty) = value.resolve_internal(leaf_to_output_fn)?;
1365                let (step, step_ty) = step.resolve_internal(leaf_to_output_fn)?;
1366                let ty = NumericType::add_two_types(&value_ty, &step_ty)?;
1367
1368                let step = step.abs();
1369
1370                // TODO(emilio): Seems like at least a few of these
1371                // special-cases could be removed if we do the math in a
1372                // particular order.
1373                if step.is_zero() {
1374                    value = f32::NAN;
1375                } else if value.is_infinite() {
1376                    if step.is_infinite() {
1377                        value = f32::NAN
1378                    }
1379                } else if step.is_infinite() {
1380                    value = match strategy {
1381                        RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1382                            if value.is_sign_negative() {
1383                                -0.0
1384                            } else {
1385                                0.0
1386                            }
1387                        },
1388                        RoundingStrategy::Up => {
1389                            if !value.is_sign_negative() && !value.is_zero() {
1390                                f32::INFINITY
1391                            } else if !value.is_sign_negative() && value.is_zero() {
1392                                value
1393                            } else {
1394                                -0.0
1395                            }
1396                        },
1397                        RoundingStrategy::Down => {
1398                            if value.is_sign_negative() && !value.is_zero() {
1399                                -f32::INFINITY
1400                            } else if value.is_sign_negative() && value.is_zero() {
1401                                value
1402                            } else {
1403                                0.0
1404                            }
1405                        },
1406                    };
1407                } else {
1408                    let div = value / step;
1409                    let lower_bound = div.floor() * step;
1410                    let upper_bound = div.ceil() * step;
1411
1412                    value = match strategy {
1413                        RoundingStrategy::Nearest => {
1414                            // In case of a tie, use the upper bound
1415                            if value - lower_bound < upper_bound - value {
1416                                lower_bound
1417                            } else {
1418                                upper_bound
1419                            }
1420                        },
1421                        RoundingStrategy::Up => upper_bound,
1422                        RoundingStrategy::Down => lower_bound,
1423                        RoundingStrategy::ToZero => {
1424                            // In case of a tie, use the upper bound
1425                            if lower_bound.abs() < upper_bound.abs() {
1426                                lower_bound
1427                            } else {
1428                                upper_bound
1429                            }
1430                        },
1431                    }
1432                }
1433
1434                Ok((value, ty))
1435            },
1436            Self::ModRem {
1437                dividend,
1438                divisor,
1439                op,
1440            } => {
1441                let (dividend, dividend_ty) = dividend.resolve_internal(leaf_to_output_fn)?;
1442                let (divisor, divisor_ty) = divisor.resolve_internal(leaf_to_output_fn)?;
1443                let ty = NumericType::add_two_types(&dividend_ty, &divisor_ty)?;
1444                let value = op.apply(dividend, divisor);
1445                Ok((value, ty))
1446            },
1447            Self::Sin(c) => {
1448                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1449                let radians = match ty.as_calc_type()? {
1450                    CalcType::Number => value,
1451                    CalcType::Angle => value.to_radians(),
1452                    _ => return Err(()),
1453                };
1454                Ok((radians.sin(), NumericType::number()))
1455            },
1456            Self::Cos(c) => {
1457                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1458                let radians = match ty.as_calc_type()? {
1459                    CalcType::Number => value,
1460                    CalcType::Angle => value.to_radians(),
1461                    _ => return Err(()),
1462                };
1463                Ok((radians.cos(), NumericType::number()))
1464            },
1465            Self::Tan(c) => {
1466                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1467                let radians = match ty.as_calc_type()? {
1468                    CalcType::Number => value,
1469                    CalcType::Angle => value.to_radians(),
1470                    _ => return Err(()),
1471                };
1472                Ok((radians.tan(), NumericType::number()))
1473            },
1474            Self::Asin(c) => {
1475                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1476                if !ty.is_number() {
1477                    return Err(());
1478                }
1479                Ok((value.asin().to_degrees(), NumericType::angle()))
1480            },
1481            Self::Acos(c) => {
1482                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1483                if !ty.is_number() {
1484                    return Err(());
1485                }
1486                Ok((value.acos().to_degrees(), NumericType::angle()))
1487            },
1488            Self::Atan(c) => {
1489                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1490                if !ty.is_number() {
1491                    return Err(());
1492                }
1493                Ok((value.atan().to_degrees(), NumericType::angle()))
1494            },
1495            Self::Atan2(a, b) => {
1496                let (a, a_ty) = a.resolve_internal(leaf_to_output_fn)?;
1497                let (b, b_ty) = b.resolve_internal(leaf_to_output_fn)?;
1498                let _ = NumericType::add_two_types(&a_ty, &b_ty)?;
1499                Ok((a.atan2(b).to_degrees(), NumericType::angle()))
1500            },
1501            Self::Pow(a, b) => {
1502                let (a, a_ty) = a.resolve_internal(leaf_to_output_fn)?;
1503                let (b, b_ty) = b.resolve_internal(leaf_to_output_fn)?;
1504                if !a_ty.is_number() || !b_ty.is_number() {
1505                    return Err(());
1506                }
1507                Ok((a.powf(b), NumericType::number()))
1508            },
1509            Self::Sqrt(c) => {
1510                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1511                if !ty.is_number() {
1512                    return Err(());
1513                }
1514                Ok((value.sqrt(), NumericType::number()))
1515            },
1516            Self::Hypot(children) => {
1517                let (mut value, mut ty) = children[0].resolve_internal(leaf_to_output_fn)?;
1518                value = value.powi(2);
1519
1520                for child in children.iter().skip(1) {
1521                    let (child_value, child_ty) = child.resolve_internal(leaf_to_output_fn)?;
1522                    ty = NumericType::add_two_types(&ty, &child_ty)?;
1523                    value += child_value.powi(2);
1524                }
1525
1526                Ok((value.sqrt(), ty))
1527            },
1528            Self::Log(a, b) => {
1529                let (a, a_ty) = a.resolve_internal(leaf_to_output_fn)?;
1530                if !a_ty.is_number() {
1531                    return Err(());
1532                }
1533                let value = match b {
1534                    Optional::Some(b) => {
1535                        let (b, b_ty) = b.resolve_internal(leaf_to_output_fn)?;
1536                        if !b_ty.is_number() {
1537                            return Err(());
1538                        }
1539                        a.log(b)
1540                    },
1541                    Optional::None => a.ln(),
1542                };
1543                Ok((value, NumericType::number()))
1544            },
1545            Self::Exp(c) => {
1546                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1547                if !ty.is_number() {
1548                    return Err(());
1549                }
1550                Ok((value.exp(), NumericType::number()))
1551            },
1552            Self::Abs(c) => {
1553                let (value, ty) = c.resolve_internal(leaf_to_output_fn)?;
1554                Ok((value.abs(), ty))
1555            },
1556            Self::Sign(c) => {
1557                let (value, _) = c.resolve_internal(leaf_to_output_fn)?;
1558                let sign = crate::values::calc_sign(value);
1559                Ok((sign, NumericType::number()))
1560            },
1561            Self::Progress {
1562                clamping_mode,
1563                value,
1564                start,
1565                end,
1566            } => {
1567                let (value, value_ty) = value.resolve_internal(leaf_to_output_fn)?;
1568                let (start, start_ty) = start.resolve_internal(leaf_to_output_fn)?;
1569                let (end, end_ty) = end.resolve_internal(leaf_to_output_fn)?;
1570
1571                let _ = NumericType::add_two_types(&value_ty, &start_ty)?;
1572                let _ = NumericType::add_two_types(&value_ty, &end_ty)?;
1573                let _ = NumericType::add_two_types(&start_ty, &end_ty)?;
1574
1575                let progress = clamping_mode.evaluate(value, start, end);
1576                Ok((progress, NumericType::number()))
1577            },
1578            Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
1579        }
1580    }
1581
1582    /// Mutate nodes within this calc node tree using given the mapping function.
1583    pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
1584    where
1585        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1586    {
1587        self.map_node_internal(&mut mapping_fn)
1588    }
1589
1590    fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
1591    where
1592        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1593    {
1594        if let Some(node) = mapping_fn(self)? {
1595            *self = node;
1596            // Assume that any sub-nodes don't need to be mutated.
1597            return Ok(());
1598        }
1599        match self {
1600            Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
1601            Self::Negate(child)
1602            | Self::Invert(child)
1603            | Self::Abs(child)
1604            | Self::Sign(child)
1605            | Self::Sin(child)
1606            | Self::Cos(child)
1607            | Self::Tan(child)
1608            | Self::Asin(child)
1609            | Self::Acos(child)
1610            | Self::Atan(child)
1611            | Self::Sqrt(child)
1612            | Self::Exp(child) => {
1613                child.map_node_internal(mapping_fn)?;
1614            },
1615            Self::Atan2(a, b) => {
1616                a.map_node_internal(mapping_fn)?;
1617                b.map_node_internal(mapping_fn)?;
1618            },
1619            Self::Pow(a, b) => {
1620                a.map_node_internal(mapping_fn)?;
1621                b.map_node_internal(mapping_fn)?;
1622            },
1623            Self::Log(a, b) => {
1624                a.map_node_internal(mapping_fn)?;
1625                if let Optional::Some(b) = b {
1626                    b.map_node_internal(mapping_fn)?;
1627                }
1628            },
1629            Self::Sum(children)
1630            | Self::Product(children)
1631            | Self::Hypot(children)
1632            | Self::MinMax(children, _) => {
1633                for child in children.iter_mut() {
1634                    child.map_node_internal(mapping_fn)?;
1635                }
1636            },
1637            Self::Clamp { min, center, max } => {
1638                min.map_node_internal(mapping_fn)?;
1639                center.map_node_internal(mapping_fn)?;
1640                max.map_node_internal(mapping_fn)?;
1641            },
1642            Self::Round { value, step, .. } => {
1643                value.map_node_internal(mapping_fn)?;
1644                step.map_node_internal(mapping_fn)?;
1645            },
1646            Self::ModRem {
1647                dividend, divisor, ..
1648            } => {
1649                dividend.map_node_internal(mapping_fn)?;
1650                divisor.map_node_internal(mapping_fn)?;
1651            },
1652            Self::Progress {
1653                value, start, end, ..
1654            } => {
1655                value.map_node_internal(mapping_fn)?;
1656                start.map_node_internal(mapping_fn)?;
1657                end.map_node_internal(mapping_fn)?;
1658            },
1659        };
1660        Ok(())
1661    }
1662
1663    fn is_negative_leaf(&self) -> Result<bool, ()> {
1664        Ok(match *self {
1665            Self::Leaf(ref l) => l.is_negative()?,
1666            _ => false,
1667        })
1668    }
1669
1670    fn is_zero_leaf(&self) -> Result<bool, ()> {
1671        Ok(match *self {
1672            Self::Leaf(ref l) => l.is_zero()?,
1673            _ => false,
1674        })
1675    }
1676
1677    fn is_infinite_leaf(&self) -> Result<bool, ()> {
1678        Ok(match *self {
1679            Self::Leaf(ref l) => l.is_infinite()?,
1680            _ => false,
1681        })
1682    }
1683
1684    fn is_nan_leaf(&self) -> Result<bool, ()> {
1685        Ok(match *self {
1686            Self::Leaf(ref l) => l.is_nan()?,
1687            _ => false,
1688        })
1689    }
1690
1691    /// Visits all the nodes in this calculation tree recursively, starting by
1692    /// the leaves and bubbling all the way up.
1693    ///
1694    /// This is useful for simplification, but can also be used for validation
1695    /// and such.
1696    pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
1697        self.visit_depth_first_internal(&mut f)
1698    }
1699
1700    fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
1701        match *self {
1702            Self::Clamp {
1703                ref mut min,
1704                ref mut center,
1705                ref mut max,
1706            } => {
1707                min.visit_depth_first_internal(f);
1708                center.visit_depth_first_internal(f);
1709                max.visit_depth_first_internal(f);
1710            },
1711            Self::Round {
1712                ref mut value,
1713                ref mut step,
1714                ..
1715            } => {
1716                value.visit_depth_first_internal(f);
1717                step.visit_depth_first_internal(f);
1718            },
1719            Self::ModRem {
1720                ref mut dividend,
1721                ref mut divisor,
1722                ..
1723            } => {
1724                dividend.visit_depth_first_internal(f);
1725                divisor.visit_depth_first_internal(f);
1726            },
1727            Self::Sum(ref mut children)
1728            | Self::Product(ref mut children)
1729            | Self::MinMax(ref mut children, _)
1730            | Self::Hypot(ref mut children) => {
1731                for child in &mut **children {
1732                    child.visit_depth_first_internal(f);
1733                }
1734            },
1735            Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
1736                value.visit_depth_first_internal(f);
1737            },
1738            Self::Sin(ref mut value)
1739            | Self::Cos(ref mut value)
1740            | Self::Tan(ref mut value)
1741            | Self::Asin(ref mut value)
1742            | Self::Acos(ref mut value)
1743            | Self::Atan(ref mut value)
1744            | Self::Sqrt(ref mut value)
1745            | Self::Exp(ref mut value) => {
1746                value.visit_depth_first_internal(f);
1747            },
1748            Self::Atan2(ref mut a, ref mut b) => {
1749                a.visit_depth_first_internal(f);
1750                b.visit_depth_first_internal(f);
1751            },
1752            Self::Pow(ref mut a, ref mut b) => {
1753                a.visit_depth_first_internal(f);
1754                b.visit_depth_first_internal(f);
1755            },
1756            Self::Log(ref mut a, ref mut b) => {
1757                a.visit_depth_first_internal(f);
1758                if let Optional::Some(b) = b {
1759                    b.visit_depth_first_internal(f);
1760                }
1761            },
1762            Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
1763                value.visit_depth_first_internal(f);
1764            },
1765            Self::Progress {
1766                ref mut value,
1767                ref mut start,
1768                ref mut end,
1769                ..
1770            } => {
1771                value.visit_depth_first_internal(f);
1772                start.visit_depth_first_internal(f);
1773                end.visit_depth_first_internal(f);
1774            },
1775            Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
1776        }
1777        f(self);
1778    }
1779
1780    /// This function simplifies and sorts the calculation of the specified node. It simplifies
1781    /// directly nested nodes while assuming that all nodes below it have already been simplified.
1782    /// It is recommended to use this function in combination with `visit_depth_first()`.
1783    ///
1784    /// This function is necessary only if the node needs to be preserved after parsing,
1785    /// specifically for `<length-percentage>` cases where the calculation contains percentages or
1786    /// relative units. Otherwise, the node can be evaluated using `resolve()`, which will
1787    /// automatically provide a simplified value.
1788    ///
1789    /// <https://drafts.csswg.org/css-values-4/#calc-simplification>
1790    pub fn simplify_and_sort_direct_children(&mut self) -> SimplificationResult {
1791        macro_rules! replace_self_with {
1792            ($slot:expr) => {{
1793                let result = mem::replace($slot, Self::dummy());
1794                *self = result;
1795            }};
1796        }
1797
1798        macro_rules! value_or_stop {
1799            ($op:expr) => {{
1800                match $op {
1801                    Ok(value) => value,
1802                    Err(_) => return SimplificationResult::Unchanged,
1803                }
1804            }};
1805        }
1806
1807        match *self {
1808            Self::Clamp {
1809                ref mut min,
1810                ref mut center,
1811                ref mut max,
1812            } => {
1813                // NOTE: clamp() is max(min, min(center, max))
1814                let min_cmp_center = match min.compare(center) {
1815                    Some(o) => o,
1816                    None => return SimplificationResult::Unchanged,
1817                };
1818
1819                // So if we can prove that min is more than center, then we won,
1820                // as that's what we should always return.
1821                if matches!(min_cmp_center, cmp::Ordering::Greater) {
1822                    replace_self_with!(&mut **min);
1823                    return SimplificationResult::Simplified;
1824                }
1825
1826                // Otherwise try with max.
1827                let max_cmp_center = match max.compare(center) {
1828                    Some(o) => o,
1829                    None => return SimplificationResult::Unchanged,
1830                };
1831
1832                if matches!(max_cmp_center, cmp::Ordering::Less) {
1833                    // max is less than center, so we need to return effectively
1834                    // `max(min, max)`.
1835                    let max_cmp_min = match max.compare(min) {
1836                        Some(o) => o,
1837                        None => return SimplificationResult::Unchanged,
1838                    };
1839
1840                    if matches!(max_cmp_min, cmp::Ordering::Less) {
1841                        replace_self_with!(&mut **min);
1842                        return SimplificationResult::Simplified;
1843                    }
1844
1845                    replace_self_with!(&mut **max);
1846                    return SimplificationResult::Simplified;
1847                }
1848
1849                // Otherwise we're the center node.
1850                replace_self_with!(&mut **center);
1851                SimplificationResult::Simplified
1852            },
1853            Self::Round {
1854                strategy,
1855                ref mut value,
1856                ref mut step,
1857            } => {
1858                if value_or_stop!(step.is_zero_leaf()) {
1859                    value_or_stop!(value.coerce_to_value(f32::NAN));
1860                    replace_self_with!(&mut **value);
1861                    return SimplificationResult::Simplified;
1862                }
1863
1864                if value_or_stop!(value.is_infinite_leaf())
1865                    && value_or_stop!(step.is_infinite_leaf())
1866                {
1867                    value_or_stop!(value.coerce_to_value(f32::NAN));
1868                    replace_self_with!(&mut **value);
1869                    return SimplificationResult::Simplified;
1870                }
1871
1872                if value_or_stop!(value.is_infinite_leaf()) {
1873                    replace_self_with!(&mut **value);
1874                    return SimplificationResult::Simplified;
1875                }
1876
1877                if value_or_stop!(step.is_infinite_leaf()) {
1878                    match strategy {
1879                        RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1880                            value_or_stop!(value.coerce_to_value(0.0));
1881                            replace_self_with!(&mut **value);
1882                            return SimplificationResult::Simplified;
1883                        },
1884                        RoundingStrategy::Up => {
1885                            if !value_or_stop!(value.is_negative_leaf())
1886                                && !value_or_stop!(value.is_zero_leaf())
1887                            {
1888                                value_or_stop!(value.coerce_to_value(f32::INFINITY));
1889                                replace_self_with!(&mut **value);
1890                                return SimplificationResult::Simplified;
1891                            } else if !value_or_stop!(value.is_negative_leaf())
1892                                && value_or_stop!(value.is_zero_leaf())
1893                            {
1894                                replace_self_with!(&mut **value);
1895                                return SimplificationResult::Simplified;
1896                            } else {
1897                                value_or_stop!(value.coerce_to_value(0.0));
1898                                replace_self_with!(&mut **value);
1899                                return SimplificationResult::Simplified;
1900                            }
1901                        },
1902                        RoundingStrategy::Down => {
1903                            if value_or_stop!(value.is_negative_leaf())
1904                                && !value_or_stop!(value.is_zero_leaf())
1905                            {
1906                                value_or_stop!(value.coerce_to_value(-f32::INFINITY));
1907                                replace_self_with!(&mut **value);
1908                                return SimplificationResult::Simplified;
1909                            } else if value_or_stop!(value.is_negative_leaf())
1910                                && value_or_stop!(value.is_zero_leaf())
1911                            {
1912                                replace_self_with!(&mut **value);
1913                                return SimplificationResult::Simplified;
1914                            } else {
1915                                value_or_stop!(value.coerce_to_value(0.0));
1916                                replace_self_with!(&mut **value);
1917                                return SimplificationResult::Simplified;
1918                            }
1919                        },
1920                    }
1921                }
1922
1923                if value_or_stop!(step.is_negative_leaf()) {
1924                    step.negate();
1925                }
1926
1927                let remainder = value_or_stop!(value.try_op(step, Rem::rem));
1928                if value_or_stop!(remainder.is_zero_leaf()) {
1929                    replace_self_with!(&mut **value);
1930                    return SimplificationResult::Simplified;
1931                }
1932
1933                let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
1934                {
1935                    let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1936                    let lower_bound = value_or_stop!(upper_bound.try_op(step, Sub::sub));
1937
1938                    (lower_bound, upper_bound)
1939                } else {
1940                    let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1941                    let upper_bound = value_or_stop!(lower_bound.try_op(step, Add::add));
1942
1943                    (lower_bound, upper_bound)
1944                };
1945
1946                match strategy {
1947                    RoundingStrategy::Nearest => {
1948                        let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
1949                        let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
1950                        // In case of a tie, use the upper bound
1951                        if lower_diff.lt(&upper_diff) {
1952                            replace_self_with!(&mut lower_bound);
1953                        } else {
1954                            replace_self_with!(&mut upper_bound);
1955                        }
1956                    },
1957                    RoundingStrategy::Up => {
1958                        replace_self_with!(&mut upper_bound);
1959                    },
1960                    RoundingStrategy::Down => {
1961                        replace_self_with!(&mut lower_bound);
1962                    },
1963                    RoundingStrategy::ToZero => {
1964                        let mut lower_diff = lower_bound.clone();
1965                        let mut upper_diff = upper_bound.clone();
1966
1967                        if value_or_stop!(lower_diff.is_negative_leaf()) {
1968                            lower_diff.negate();
1969                        }
1970
1971                        if value_or_stop!(upper_diff.is_negative_leaf()) {
1972                            upper_diff.negate();
1973                        }
1974
1975                        // In case of a tie, use the upper bound
1976                        if lower_diff.lt(&upper_diff) {
1977                            replace_self_with!(&mut lower_bound);
1978                        } else {
1979                            replace_self_with!(&mut upper_bound);
1980                        }
1981                    },
1982                };
1983                SimplificationResult::Simplified
1984            },
1985            Self::ModRem {
1986                ref dividend,
1987                ref divisor,
1988                op,
1989            } => {
1990                let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
1991                replace_self_with!(&mut result);
1992                SimplificationResult::Simplified
1993            },
1994            Self::MinMax(ref mut children, op) => {
1995                let winning_order = match op {
1996                    MinMaxOp::Min => cmp::Ordering::Less,
1997                    MinMaxOp::Max => cmp::Ordering::Greater,
1998                };
1999
2000                if value_or_stop!(children[0].is_nan_leaf()) {
2001                    replace_self_with!(&mut children[0]);
2002                    return SimplificationResult::Simplified;
2003                }
2004
2005                let mut result = 0;
2006                for i in 1..children.len() {
2007                    if value_or_stop!(children[i].is_nan_leaf()) {
2008                        replace_self_with!(&mut children[i]);
2009                        return SimplificationResult::Simplified;
2010                    }
2011                    let o = match children[i].compare(&children[result]) {
2012                        // We can't compare all the children, so we can't
2013                        // know which one will actually win. Bail out and
2014                        // keep ourselves as a min / max function.
2015                        //
2016                        // TODO: Maybe we could simplify compatible children,
2017                        // see https://github.com/w3c/csswg-drafts/issues/4756
2018                        None => return SimplificationResult::Unchanged,
2019                        Some(o) => o,
2020                    };
2021
2022                    if o == winning_order {
2023                        result = i;
2024                    }
2025                }
2026
2027                replace_self_with!(&mut children[result]);
2028                SimplificationResult::Simplified
2029            },
2030            Self::Sum(ref mut children_slot) => {
2031                let mut sums_to_merge = SmallVec::<[_; 3]>::new();
2032                let mut extra_kids = 0;
2033                for (i, child) in children_slot.iter().enumerate() {
2034                    if let Self::Sum(ref children) = *child {
2035                        extra_kids += children.len();
2036                        sums_to_merge.push(i);
2037                    }
2038                }
2039
2040                // If we only have one kid, we've already simplified it, and it
2041                // doesn't really matter whether it's a sum already or not, so
2042                // lift it up and continue.
2043                if children_slot.len() == 1 {
2044                    replace_self_with!(&mut children_slot[0]);
2045                    return SimplificationResult::Simplified;
2046                }
2047
2048                let mut children = mem::take(children_slot).into_vec();
2049
2050                if !sums_to_merge.is_empty() {
2051                    children.reserve(extra_kids - sums_to_merge.len());
2052                    // Merge all our nested sums, in reverse order so that the
2053                    // list indices are not invalidated.
2054                    for i in sums_to_merge.drain(..).rev() {
2055                        let kid_children = match children.swap_remove(i) {
2056                            Self::Sum(c) => c,
2057                            _ => unreachable!(),
2058                        };
2059
2060                        // This would be nicer with
2061                        // https://github.com/rust-lang/rust/issues/59878 fixed.
2062                        children.extend(kid_children.into_vec());
2063                    }
2064                }
2065
2066                let children_len = children.len();
2067                debug_assert!(children_len >= 2, "Should still have multiple kids!");
2068
2069                // Sort by spec order.
2070                children.sort_unstable_by_key(|c| c.sort_key());
2071
2072                // NOTE: if the function returns true, by the docs of dedup_by,
2073                // a is removed.
2074                children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
2075
2076                let updated_children_len = children.len();
2077                if updated_children_len == 1 {
2078                    // If only one children remains, lift it up, and carry on.
2079                    replace_self_with!(&mut children[0]);
2080                } else {
2081                    // Else put our simplified children back.
2082                    *children_slot = children.into_boxed_slice().into();
2083                }
2084
2085                if updated_children_len != children_len {
2086                    SimplificationResult::Simplified
2087                } else {
2088                    SimplificationResult::Unchanged
2089                }
2090            },
2091            Self::Product(ref mut children_slot) => {
2092                let mut products_to_merge = SmallVec::<[_; 3]>::new();
2093                let mut extra_kids = 0;
2094                for (i, child) in children_slot.iter().enumerate() {
2095                    if let Self::Product(ref children) = *child {
2096                        extra_kids += children.len();
2097                        products_to_merge.push(i);
2098                    }
2099                }
2100
2101                // If we only have one kid, we've already simplified it, and it
2102                // doesn't really matter whether it's a product already or not,
2103                // so lift it up and continue.
2104                if children_slot.len() == 1 {
2105                    replace_self_with!(&mut children_slot[0]);
2106                    return SimplificationResult::Unchanged;
2107                }
2108
2109                let mut children = mem::take(children_slot).into_vec();
2110                if !products_to_merge.is_empty() {
2111                    children.reserve(extra_kids - products_to_merge.len());
2112                    // Merge all our nested sums, in reverse order so that the
2113                    // list indices are not invalidated.
2114                    for i in products_to_merge.drain(..).rev() {
2115                        let kid_children = match children.swap_remove(i) {
2116                            Self::Product(c) => c,
2117                            _ => unreachable!(),
2118                        };
2119
2120                        // This would be nicer with
2121                        // https://github.com/rust-lang/rust/issues/59878 fixed.
2122                        children.extend(kid_children.into_vec());
2123                    }
2124                }
2125
2126                debug_assert!(children.len() >= 2, "Should still have multiple kids!");
2127
2128                // Sort by spec order.
2129                children.sort_unstable_by_key(|c| c.sort_key());
2130
2131                // NOTE: if the function returns true, by the docs of dedup_by,
2132                // a is removed.
2133                children.dedup_by(|right, left| left.try_product_in_place(right));
2134
2135                if children.len() == 1 {
2136                    // If only one children remains, lift it up, and carry on.
2137                    replace_self_with!(&mut children[0]);
2138                    return SimplificationResult::Simplified;
2139                }
2140
2141                if typed_arithmetic_enabled() {
2142                    // "If root contains only numeric values and/or Invert nodes containing numeric values,
2143                    // and multiplying the types of all the children (noting that the type of an Invert
2144                    // node is the inverse of its child’s type) results in a type that matches any of the
2145                    // types that a math function can resolve to, return the result of multiplying all the
2146                    // values of the children (noting that the value of an Invert node is the reciprocal of
2147                    // its child’s value), expressed in the result’s canonical unit."
2148                    //
2149                    // https://drafts.csswg.org/css-values-4/#simplify-a-calculation-tree
2150                    let mut result = 1.0;
2151                    let mut ty = Ok(NumericType::number());
2152
2153                    for child in children.iter() {
2154                        let (leaf, is_inverted) = match child {
2155                            Self::Leaf(leaf) => (leaf, false),
2156                            Self::Invert(inner) if inner.as_leaf().is_some() => {
2157                                (inner.as_leaf().unwrap(), true)
2158                            },
2159                            _ => {
2160                                ty = Err(());
2161                                break;
2162                            },
2163                        };
2164
2165                        // Only multiply values that are in that type's canonical unit.
2166                        let Some(value) = leaf.canonical_value() else {
2167                            ty = Err(());
2168                            break;
2169                        };
2170                        let (multiplicand, child_ty) = if is_inverted {
2171                            let mut ty = leaf.numeric_type();
2172                            ty.invert();
2173                            (1.0 / value, ty)
2174                        } else {
2175                            (value, leaf.numeric_type())
2176                        };
2177
2178                        result *= multiplicand;
2179                        ty = ty.and_then(|ty| NumericType::multiply_two_types(&ty, &child_ty));
2180                    }
2181
2182                    if let Ok(leaf) = ty.and_then(|ty| L::new_from_typed_value(result, ty)) {
2183                        let mut result = Self::Leaf(leaf);
2184                        replace_self_with!(&mut result);
2185                        return SimplificationResult::Simplified;
2186                    }
2187                }
2188
2189                // Else put our simplified children back.
2190                *children_slot = children.into_boxed_slice().into();
2191                SimplificationResult::Unchanged
2192            },
2193            Self::Sin(ref mut child) => {
2194                if let CalcNode::Leaf(ref leaf) = **child {
2195                    if let Some(radians) = leaf.as_number_or_angle_radians() {
2196                        let mut result = Self::Leaf(L::new_number(radians.sin()));
2197                        replace_self_with!(&mut result);
2198                        return SimplificationResult::Simplified;
2199                    }
2200                }
2201                SimplificationResult::Unchanged
2202            },
2203            Self::Cos(ref mut child) => {
2204                if let CalcNode::Leaf(ref leaf) = **child {
2205                    if let Some(radians) = leaf.as_number_or_angle_radians() {
2206                        let mut result = Self::Leaf(L::new_number(radians.cos()));
2207                        replace_self_with!(&mut result);
2208                        return SimplificationResult::Simplified;
2209                    }
2210                }
2211                SimplificationResult::Unchanged
2212            },
2213            Self::Tan(ref mut child) => {
2214                if let CalcNode::Leaf(ref leaf) = **child {
2215                    if let Some(radians) = leaf.as_number_or_angle_radians() {
2216                        let mut result = Self::Leaf(L::new_number(radians.tan()));
2217                        replace_self_with!(&mut result);
2218                        return SimplificationResult::Simplified;
2219                    }
2220                }
2221                SimplificationResult::Unchanged
2222            },
2223            Self::Asin(ref mut child) => {
2224                if let CalcNode::Leaf(ref leaf) = **child {
2225                    if let Some(value) = leaf.as_number() {
2226                        let mut result = Self::Leaf(L::new_angle_from_radians(value.asin()));
2227                        replace_self_with!(&mut result);
2228                        return SimplificationResult::Simplified;
2229                    }
2230                }
2231                SimplificationResult::Unchanged
2232            },
2233            Self::Acos(ref mut child) => {
2234                if let CalcNode::Leaf(ref leaf) = **child {
2235                    if let Some(value) = leaf.as_number() {
2236                        let mut result = Self::Leaf(L::new_angle_from_radians(value.acos()));
2237                        replace_self_with!(&mut result);
2238                        return SimplificationResult::Simplified;
2239                    }
2240                }
2241                SimplificationResult::Unchanged
2242            },
2243            Self::Atan(ref mut child) => {
2244                if let CalcNode::Leaf(ref leaf) = **child {
2245                    if let Some(value) = leaf.as_number() {
2246                        let mut result = Self::Leaf(L::new_angle_from_radians(value.atan()));
2247                        replace_self_with!(&mut result);
2248                        return SimplificationResult::Simplified;
2249                    }
2250                }
2251                SimplificationResult::Unchanged
2252            },
2253            Self::Atan2(ref mut a, ref mut b) => {
2254                if let (CalcNode::Leaf(la), CalcNode::Leaf(lb)) = (&**a, &**b) {
2255                    if la.is_same_unit_as(lb) {
2256                        if let (Some(a_val), Some(b_val)) =
2257                            (la.unitless_value(), lb.unitless_value())
2258                        {
2259                            let mut result =
2260                                Self::Leaf(L::new_angle_from_radians(a_val.atan2(b_val)));
2261                            replace_self_with!(&mut result);
2262                            return SimplificationResult::Simplified;
2263                        }
2264                    }
2265                }
2266                SimplificationResult::Unchanged
2267            },
2268            Self::Pow(ref mut a, ref mut b) => {
2269                if let (CalcNode::Leaf(la), CalcNode::Leaf(lb)) = (&**a, &**b) {
2270                    if let (Some(a_val), Some(b_val)) = (la.as_number(), lb.as_number()) {
2271                        let mut result = Self::Leaf(L::new_number(a_val.powf(b_val)));
2272                        replace_self_with!(&mut result);
2273                        return SimplificationResult::Simplified;
2274                    }
2275                }
2276                SimplificationResult::Unchanged
2277            },
2278            Self::Sqrt(ref mut child) => {
2279                if let CalcNode::Leaf(ref leaf) = **child {
2280                    if let Some(value) = leaf.as_number() {
2281                        let mut result = Self::Leaf(L::new_number(value.sqrt()));
2282                        replace_self_with!(&mut result);
2283                        return SimplificationResult::Simplified;
2284                    }
2285                }
2286                SimplificationResult::Unchanged
2287            },
2288            Self::Hypot(ref children) => {
2289                let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
2290
2291                for child in children.iter().skip(1) {
2292                    let square = value_or_stop!(child.try_op(child, Mul::mul));
2293                    result = value_or_stop!(result.try_op(&square, Add::add));
2294                }
2295
2296                result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
2297
2298                replace_self_with!(&mut result);
2299                SimplificationResult::Simplified
2300            },
2301            Self::Log(ref mut a, ref mut b) => {
2302                if let CalcNode::Leaf(ref la) = **a {
2303                    if let Some(a_val) = la.as_number() {
2304                        let folded = match b {
2305                            &mut Optional::Some(ref b) => {
2306                                if let CalcNode::Leaf(ref lb) = **b {
2307                                    lb.as_number().map(|b_val| a_val.log(b_val))
2308                                } else {
2309                                    None
2310                                }
2311                            },
2312                            Optional::None => Some(a_val.ln()),
2313                        };
2314                        if let Some(number) = folded {
2315                            let mut result = Self::Leaf(L::new_number(number));
2316                            replace_self_with!(&mut result);
2317                            return SimplificationResult::Simplified;
2318                        }
2319                    }
2320                }
2321                SimplificationResult::Unchanged
2322            },
2323            Self::Exp(ref mut child) => {
2324                if let CalcNode::Leaf(ref leaf) = **child {
2325                    if let Some(value) = leaf.as_number() {
2326                        let mut result = Self::Leaf(L::new_number(value.exp()));
2327                        replace_self_with!(&mut result);
2328                        return SimplificationResult::Simplified;
2329                    }
2330                }
2331                SimplificationResult::Unchanged
2332            },
2333            Self::Abs(ref mut child) => {
2334                if let CalcNode::Leaf(leaf) = child.as_mut() {
2335                    value_or_stop!(leaf.map(|v| v.abs()));
2336                    replace_self_with!(&mut **child);
2337                    return SimplificationResult::Simplified;
2338                }
2339                SimplificationResult::Unchanged
2340            },
2341            Self::Sign(ref mut child) => {
2342                if let CalcNode::Leaf(leaf) = child.as_mut() {
2343                    let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
2344                    replace_self_with!(&mut result);
2345                    return SimplificationResult::Simplified;
2346                }
2347                SimplificationResult::Unchanged
2348            },
2349            Self::Negate(ref mut child) => {
2350                // Step 6.
2351                match &mut **child {
2352                    CalcNode::Leaf(_) => {
2353                        // 1. If root’s child is a numeric value, return an equivalent numeric value, but
2354                        // with the value negated (0 - value).
2355                        child.negate();
2356                        replace_self_with!(&mut **child);
2357                        SimplificationResult::Simplified
2358                    },
2359                    CalcNode::Negate(value) => {
2360                        // 2. If root’s child is a Negate node, return the child’s child.
2361                        replace_self_with!(&mut **value);
2362                        SimplificationResult::Simplified
2363                    },
2364                    _ => {
2365                        // 3. Return root.
2366                        SimplificationResult::Unchanged
2367                    },
2368                }
2369            },
2370            Self::Invert(ref mut child) => {
2371                // Step 7.
2372                match &mut **child {
2373                    CalcNode::Leaf(leaf) => {
2374                        // 1. If root’s child is a number (not a percentage or dimension) return the
2375                        // reciprocal of the child’s value.
2376                        if leaf.numeric_type().is_number() {
2377                            value_or_stop!(child.map(|v| 1.0 / v));
2378                            replace_self_with!(&mut **child);
2379                            return SimplificationResult::Simplified;
2380                        }
2381                        SimplificationResult::Unchanged
2382                    },
2383                    CalcNode::Invert(value) => {
2384                        // 2. If root’s child is an Invert node, return the child’s child.
2385                        replace_self_with!(&mut **value);
2386                        SimplificationResult::Simplified
2387                    },
2388                    _ => {
2389                        // 3. Return root.
2390                        SimplificationResult::Unchanged
2391                    },
2392                }
2393            },
2394            Self::Progress {
2395                clamping_mode,
2396                ref mut value,
2397                ref mut start,
2398                ref mut end,
2399            } => {
2400                if let (CalcNode::Leaf(value), CalcNode::Leaf(start), CalcNode::Leaf(end)) =
2401                    (&**value, &**start, &**end)
2402                {
2403                    if value.is_same_unit_as(start) && value.is_same_unit_as(end) {
2404                        if let (Some(value), Some(start), Some(end)) = (
2405                            value.unitless_value(),
2406                            start.unitless_value(),
2407                            end.unitless_value(),
2408                        ) {
2409                            let mut result = Self::Leaf(L::new_number(
2410                                clamping_mode.evaluate(value, start, end),
2411                            ));
2412                            replace_self_with!(&mut result);
2413                            return SimplificationResult::Simplified;
2414                        }
2415                    }
2416                }
2417                SimplificationResult::Unchanged
2418            },
2419            Self::Leaf(ref mut l) => l.simplify(),
2420            Self::Anchor(ref mut f) => {
2421                if let GenericAnchorSide::Percentage(ref mut n) = f.side {
2422                    n.simplify_and_sort();
2423                    return SimplificationResult::Simplified;
2424                }
2425                if let Some(fallback) = f.fallback.as_mut() {
2426                    return fallback.node.simplify_and_sort();
2427                }
2428                SimplificationResult::Unchanged
2429            },
2430            Self::AnchorSize(ref mut f) => {
2431                if let Some(fallback) = f.fallback.as_mut() {
2432                    return fallback.node.simplify_and_sort();
2433                }
2434                SimplificationResult::Unchanged
2435            },
2436        }
2437    }
2438
2439    /// Simplifies and sorts the kids in the whole calculation subtree.
2440    pub fn simplify_and_sort(&mut self) -> SimplificationResult {
2441        let mut res = SimplificationResult::Unchanged;
2442        self.visit_depth_first(|node| {
2443            if let SimplificationResult::Simplified = node.simplify_and_sort_direct_children() {
2444                res = SimplificationResult::Simplified;
2445            }
2446        });
2447        res
2448    }
2449
2450    fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
2451    where
2452        W: Write,
2453    {
2454        let write_closing_paren = match self {
2455            Self::MinMax(_, op) => {
2456                dest.write_str(match op {
2457                    MinMaxOp::Max => "max(",
2458                    MinMaxOp::Min => "min(",
2459                })?;
2460                true
2461            },
2462            Self::Clamp { .. } => {
2463                dest.write_str("clamp(")?;
2464                true
2465            },
2466            Self::Round { strategy, .. } => {
2467                match strategy {
2468                    RoundingStrategy::Nearest => dest.write_str("round("),
2469                    RoundingStrategy::Up => dest.write_str("round(up, "),
2470                    RoundingStrategy::Down => dest.write_str("round(down, "),
2471                    RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
2472                }?;
2473
2474                true
2475            },
2476            Self::ModRem { op, .. } => {
2477                dest.write_str(match op {
2478                    ModRemOp::Mod => "mod(",
2479                    ModRemOp::Rem => "rem(",
2480                })?;
2481
2482                true
2483            },
2484            Self::Sin(_) => {
2485                dest.write_str("sin(")?;
2486                true
2487            },
2488            Self::Cos(_) => {
2489                dest.write_str("cos(")?;
2490                true
2491            },
2492            Self::Tan(_) => {
2493                dest.write_str("tan(")?;
2494                true
2495            },
2496            Self::Asin(_) => {
2497                dest.write_str("asin(")?;
2498                true
2499            },
2500            Self::Acos(_) => {
2501                dest.write_str("acos(")?;
2502                true
2503            },
2504            Self::Atan(_) => {
2505                dest.write_str("atan(")?;
2506                true
2507            },
2508            Self::Atan2(..) => {
2509                dest.write_str("atan2(")?;
2510                true
2511            },
2512            Self::Pow(..) => {
2513                dest.write_str("pow(")?;
2514                true
2515            },
2516            Self::Sqrt(_) => {
2517                dest.write_str("sqrt(")?;
2518                true
2519            },
2520            Self::Hypot(_) => {
2521                dest.write_str("hypot(")?;
2522                true
2523            },
2524            Self::Log(..) => {
2525                dest.write_str("log(")?;
2526                true
2527            },
2528            Self::Exp(_) => {
2529                dest.write_str("exp(")?;
2530                true
2531            },
2532            Self::Abs(_) => {
2533                dest.write_str("abs(")?;
2534                true
2535            },
2536            Self::Sign(_) => {
2537                dest.write_str("sign(")?;
2538                true
2539            },
2540            Self::Progress { .. } => {
2541                dest.write_str("progress(")?;
2542                true
2543            },
2544            Self::Negate(_) => {
2545                // We never generate a [`Negate`] node as the root of a calculation, only inside
2546                // [`Sum`] nodes as a child. Because negate nodes are handled by the [`Sum`] node
2547                // directly (see below), this node will never be serialized.
2548                debug_assert!(
2549                    false,
2550                    "We never serialize Negate nodes as they are handled inside Sum nodes."
2551                );
2552                dest.write_str("(-1 * ")?;
2553                true
2554            },
2555            Self::Invert(_) => {
2556                if matches!(level, ArgumentLevel::CalculationRoot) {
2557                    dest.write_str("calc")?;
2558                }
2559                dest.write_str("(1 / ")?;
2560                true
2561            },
2562            Self::Sum(_) | Self::Product(_) => match level {
2563                ArgumentLevel::CalculationRoot => {
2564                    dest.write_str("calc(")?;
2565                    true
2566                },
2567                ArgumentLevel::ArgumentRoot => false,
2568                ArgumentLevel::Nested => {
2569                    dest.write_str("(")?;
2570                    true
2571                },
2572            },
2573            Self::Leaf(leaf) => match level {
2574                ArgumentLevel::CalculationRoot => {
2575                    if leaf.should_serialize_with_root_calc_wrapper() {
2576                        dest.write_str("calc(")?;
2577                        true
2578                    } else {
2579                        false
2580                    }
2581                },
2582                ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
2583            },
2584            Self::Anchor(_) | Self::AnchorSize(_) => false,
2585        };
2586
2587        match *self {
2588            Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
2589                let mut first = true;
2590                for child in &**children {
2591                    if !first {
2592                        dest.write_str(", ")?;
2593                    }
2594                    first = false;
2595                    child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2596                }
2597            },
2598            Self::Negate(ref value) | Self::Invert(ref value) => {
2599                value.to_css_impl(dest, ArgumentLevel::Nested)?
2600            },
2601            Self::Sum(ref children) => {
2602                let mut first = true;
2603                for child in &**children {
2604                    if !first {
2605                        match child {
2606                            Self::Leaf(l) => {
2607                                if let Ok(true) = l.is_negative() {
2608                                    dest.write_str(" - ")?;
2609                                    let mut negated = l.clone();
2610                                    // We can unwrap here, because we already
2611                                    // checked if the value inside is negative.
2612                                    negated.map(std::ops::Neg::neg).unwrap();
2613                                    negated.to_css(dest)?;
2614                                } else {
2615                                    dest.write_str(" + ")?;
2616                                    l.to_css(dest)?;
2617                                }
2618                            },
2619                            Self::Negate(n) => {
2620                                dest.write_str(" - ")?;
2621                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
2622                            },
2623                            _ => {
2624                                dest.write_str(" + ")?;
2625                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
2626                            },
2627                        }
2628                    } else {
2629                        first = false;
2630                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
2631                    }
2632                }
2633            },
2634            Self::Product(ref children) => {
2635                let mut first = true;
2636                for child in &**children {
2637                    if !first {
2638                        match child {
2639                            Self::Invert(n) => {
2640                                dest.write_str(" / ")?;
2641                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
2642                            },
2643                            _ => {
2644                                dest.write_str(" * ")?;
2645                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
2646                            },
2647                        }
2648                    } else {
2649                        first = false;
2650                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
2651                    }
2652                }
2653            },
2654            Self::Clamp {
2655                ref min,
2656                ref center,
2657                ref max,
2658            } => {
2659                min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2660                dest.write_str(", ")?;
2661                center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2662                dest.write_str(", ")?;
2663                max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2664            },
2665            Self::Round {
2666                ref value,
2667                ref step,
2668                ..
2669            } => {
2670                value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2671                dest.write_str(", ")?;
2672                step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2673            },
2674            Self::ModRem {
2675                ref dividend,
2676                ref divisor,
2677                ..
2678            } => {
2679                dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2680                dest.write_str(", ")?;
2681                divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2682            },
2683            Self::Sin(ref v)
2684            | Self::Cos(ref v)
2685            | Self::Tan(ref v)
2686            | Self::Asin(ref v)
2687            | Self::Acos(ref v)
2688            | Self::Atan(ref v) => v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?,
2689            Self::Atan2(ref a, ref b) => {
2690                a.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2691                dest.write_str(", ")?;
2692                b.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2693            },
2694            Self::Pow(ref a, ref b) => {
2695                a.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2696                dest.write_str(", ")?;
2697                b.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2698            },
2699            Self::Sqrt(ref v) | Self::Exp(ref v) => {
2700                v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
2701            },
2702            Self::Log(ref a, ref b) => {
2703                a.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2704                if let Optional::Some(b) = b {
2705                    dest.write_str(", ")?;
2706                    b.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2707                }
2708            },
2709            Self::Abs(ref v) | Self::Sign(ref v) => {
2710                v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
2711            },
2712            Self::Progress {
2713                clamping_mode,
2714                ref value,
2715                ref start,
2716                ref end,
2717            } => {
2718                if clamping_mode == ProgressClampingMode::NoClamp {
2719                    clamping_mode.to_css(dest)?;
2720                    dest.write_char(' ')?;
2721                }
2722                value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2723                dest.write_str(", ")?;
2724                start.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2725                dest.write_str(", ")?;
2726                end.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
2727            },
2728            Self::Leaf(ref l) => l.to_css(dest)?,
2729            Self::Anchor(ref f) => f.to_css(dest)?,
2730            Self::AnchorSize(ref f) => f.to_css(dest)?,
2731        }
2732
2733        if write_closing_paren {
2734            dest.write_char(')')?;
2735        }
2736        Ok(())
2737    }
2738
2739    fn to_typed_impl(
2740        &self,
2741        dest: &mut ThinVec<TypedValue>,
2742        level: ArgumentLevel,
2743    ) -> Result<(), ()> {
2744        // Note: Naturally, only nodes that can be reified into CSSUnitValue
2745        // and CSSMathValue objects are supported here:
2746        // Leaf, Negate, Invert, Sum, Product, MinMax, and Clamp.
2747        match *self {
2748            Self::Leaf(ref l) => match l.to_typed_value() {
2749                Some(TypedValue::Numeric(inner)) => {
2750                    match level {
2751                        ArgumentLevel::CalculationRoot => {
2752                            dest.push(TypedValue::Numeric(NumericValue::Math(MathValue::Sum(
2753                                MathSum::try_from_numeric_values(ThinVec::from([inner]))?,
2754                            ))));
2755                        },
2756                        ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => {
2757                            dest.push(TypedValue::Numeric(inner));
2758                        },
2759                    }
2760                    Ok(())
2761                },
2762                _ => Err(()),
2763            },
2764            Self::Negate(_) => {
2765                // We never generate a [`Negate`] node as the root of a calculation, only inside
2766                // [`Sum`] nodes as a child. Because negate nodes are handled by the [`Sum`] node
2767                // directly (see below), this node will never be reified.
2768                debug_assert!(
2769                    false,
2770                    "We never reify Negate nodes as they are handled inside Sum nodes."
2771                );
2772
2773                Err(())
2774            },
2775            Self::Invert(ref value) => {
2776                let inner = CalcNodeWithLevel::nested(value)
2777                    .to_numeric_value()
2778                    .ok_or(())?;
2779
2780                dest.push(TypedValue::Numeric(NumericValue::Math(MathValue::Invert(
2781                    MathInvert::from_numeric_value(inner),
2782                ))));
2783                Ok(())
2784            },
2785            Self::Sum(ref children) => {
2786                let mut values = ThinVec::new();
2787                let mut first = true;
2788
2789                for child in &**children {
2790                    if !first {
2791                        match child {
2792                            Self::Leaf(l) => {
2793                                if let Ok(true) = l.is_negative() {
2794                                    let mut negated = l.clone();
2795
2796                                    // We can unwrap here, because we already
2797                                    // checked if the value inside is negative.
2798                                    negated.map(std::ops::Neg::neg).unwrap();
2799
2800                                    let inner = negated.to_numeric_value().ok_or(())?;
2801
2802                                    values.push(NumericValue::Math(MathValue::Negate(
2803                                        MathNegate::from_numeric_value(inner),
2804                                    )));
2805                                } else {
2806                                    let inner = l.to_numeric_value().ok_or(())?;
2807
2808                                    values.push(inner);
2809                                }
2810                            },
2811                            Self::Negate(n) => {
2812                                let inner = CalcNodeWithLevel::nested(n.as_ref())
2813                                    .to_numeric_value()
2814                                    .ok_or(())?;
2815
2816                                values.push(NumericValue::Math(MathValue::Negate(
2817                                    MathNegate::from_numeric_value(inner),
2818                                )));
2819                            },
2820                            _ => {
2821                                let inner = CalcNodeWithLevel::nested(child)
2822                                    .to_numeric_value()
2823                                    .ok_or(())?;
2824
2825                                values.push(inner);
2826                            },
2827                        }
2828                    } else {
2829                        first = false;
2830
2831                        let inner = CalcNodeWithLevel::nested(child)
2832                            .to_numeric_value()
2833                            .ok_or(())?;
2834
2835                        values.push(inner);
2836                    }
2837                }
2838
2839                dest.push(TypedValue::Numeric(NumericValue::Math(MathValue::Sum(
2840                    MathSum::try_from_numeric_values(values)?,
2841                ))));
2842                Ok(())
2843            },
2844            Self::Product(ref children) => {
2845                let mut values = ThinVec::new();
2846                let mut first = true;
2847
2848                for child in &**children {
2849                    if !first {
2850                        match child {
2851                            Self::Invert(n) => {
2852                                let inner = CalcNodeWithLevel::nested(n.as_ref())
2853                                    .to_numeric_value()
2854                                    .ok_or(())?;
2855
2856                                values.push(NumericValue::Math(MathValue::Invert(
2857                                    MathInvert::from_numeric_value(inner),
2858                                )));
2859                            },
2860                            _ => {
2861                                let inner = CalcNodeWithLevel::nested(child)
2862                                    .to_numeric_value()
2863                                    .ok_or(())?;
2864
2865                                values.push(inner);
2866                            },
2867                        }
2868                    } else {
2869                        first = false;
2870
2871                        let inner = CalcNodeWithLevel::nested(child)
2872                            .to_numeric_value()
2873                            .ok_or(())?;
2874
2875                        values.push(inner);
2876                    }
2877                }
2878
2879                dest.push(TypedValue::Numeric(NumericValue::Math(MathValue::Product(
2880                    MathProduct::try_from_numeric_values(values)?,
2881                ))));
2882                Ok(())
2883            },
2884            Self::MinMax(ref children, op) => {
2885                let mut values = ThinVec::new();
2886
2887                for child in &**children {
2888                    let inner = CalcNodeWithLevel::argument_root(child)
2889                        .to_numeric_value()
2890                        .ok_or(())?;
2891
2892                    values.push(inner);
2893                }
2894
2895                let math_value = match op {
2896                    MinMaxOp::Min => MathValue::Min(MathMin::try_from_numeric_values(values)?),
2897                    MinMaxOp::Max => MathValue::Max(MathMax::try_from_numeric_values(values)?),
2898                };
2899
2900                dest.push(TypedValue::Numeric(NumericValue::Math(math_value)));
2901                Ok(())
2902            },
2903            Self::Clamp {
2904                ref min,
2905                ref center,
2906                ref max,
2907            } => {
2908                let lower = CalcNodeWithLevel::argument_root(min)
2909                    .to_numeric_value()
2910                    .ok_or(())?;
2911
2912                let value = CalcNodeWithLevel::argument_root(center)
2913                    .to_numeric_value()
2914                    .ok_or(())?;
2915
2916                let upper = CalcNodeWithLevel::argument_root(max)
2917                    .to_numeric_value()
2918                    .ok_or(())?;
2919
2920                dest.push(TypedValue::Numeric(NumericValue::Math(MathValue::Clamp(
2921                    MathClamp::try_from_numeric_values([lower, value, upper].into())?,
2922                ))));
2923                Ok(())
2924            },
2925            _ => Err(()),
2926        }
2927    }
2928
2929    fn compare(&self, other: &Self) -> Option<cmp::Ordering> {
2930        match (self, other) {
2931            (CalcNode::Leaf(one), CalcNode::Leaf(other)) => one.compare(other),
2932            _ => None,
2933        }
2934    }
2935
2936    compare_helpers!();
2937}
2938
2939impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
2940    /// <https://drafts.csswg.org/css-values/#calc-serialize>
2941    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2942    where
2943        W: Write,
2944    {
2945        self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
2946    }
2947}
2948
2949impl<L: CalcNodeLeaf> ToTyped for CalcNode<L> {
2950    fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
2951        CalcNodeWithLevel::calculation_root(self).to_typed(dest)
2952    }
2953}
2954
2955struct CalcNodeWithLevel<'a, L> {
2956    node: &'a CalcNode<L>,
2957    level: ArgumentLevel,
2958}
2959
2960impl<'a, L> CalcNodeWithLevel<'a, L> {
2961    #[inline]
2962    fn new(node: &'a CalcNode<L>, level: ArgumentLevel) -> Self {
2963        Self { node, level }
2964    }
2965
2966    #[inline]
2967    fn calculation_root(node: &'a CalcNode<L>) -> Self {
2968        Self::new(node, ArgumentLevel::CalculationRoot)
2969    }
2970
2971    #[inline]
2972    fn argument_root(node: &'a CalcNode<L>) -> Self {
2973        Self::new(node, ArgumentLevel::ArgumentRoot)
2974    }
2975
2976    #[inline]
2977    fn nested(node: &'a CalcNode<L>) -> Self {
2978        Self::new(node, ArgumentLevel::Nested)
2979    }
2980}
2981
2982impl<'a, L: CalcNodeLeaf> ToTyped for CalcNodeWithLevel<'a, L> {
2983    fn to_typed(&self, dest: &mut ThinVec<TypedValue>) -> Result<(), ()> {
2984        self.node.to_typed_impl(dest, self.level.clone())
2985    }
2986}