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