style/values/generics/
calc.rs

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