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