Skip to main content

style/values/generics/
calc.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5//! [Calc expressions][calc].
6//!
7//! [calc]: https://drafts.csswg.org/css-values/#calc-notation
8
9use crate::derives::*;
10use crate::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, 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`.
451enum ArgumentLevel {
452    /// The root of a calculation tree.
453    CalculationRoot,
454    /// The root of an operand node's argument, e.g. `min(10, 20)`, `10` and `20` will have this
455    /// level, but min in this case will have `TopMost`.
456    ArgumentRoot,
457    /// Any other values serialized in the tree.
458    Nested,
459}
460
461impl<L: CalcNodeLeaf> CalcNode<L> {
462    /// Create a dummy CalcNode that can be used to do replacements of other nodes.
463    fn dummy() -> Self {
464        Self::MinMax(Default::default(), MinMaxOp::Max)
465    }
466
467    /// Change all the leaf nodes to have the given value. This is useful when
468    /// you have `calc(1px * nan)` and you want to replace the product node with
469    /// `calc(nan)`, in which case the unit will be retained.
470    fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
471        self.map(|_| value)
472    }
473
474    /// Return true if a product is distributive over this node.
475    /// Is distributive: (2 + 3) * 4 = 8 + 12
476    /// Not distributive: sign(2 + 3) * 4 != sign(8 + 12)
477    #[inline]
478    pub fn is_product_distributive(&self) -> bool {
479        match self {
480            Self::Leaf(l) => l.unit() != CalcUnits::COLOR_COMPONENT,
481            Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()),
482            _ => false,
483        }
484    }
485
486    /// If the node has a valid unit outcome, then return it, otherwise fail.
487    pub fn unit(&self) -> Result<CalcUnits, ()> {
488        Ok(match self {
489            CalcNode::Leaf(l) => l.unit(),
490            CalcNode::Negate(child) | CalcNode::Invert(child) | CalcNode::Abs(child) => {
491                child.unit()?
492            },
493            CalcNode::Sum(children) => {
494                let mut unit = children.first().unwrap().unit()?;
495                for child in children.iter().skip(1) {
496                    let child_unit = child.unit()?;
497                    if !child_unit.can_sum_with(unit) {
498                        return Err(());
499                    }
500                    unit |= child_unit;
501                }
502                unit
503            },
504            CalcNode::Product(children) => {
505                // Only one node is allowed to have a unit, the rest must be numbers.
506                let mut unit = None;
507                for child in children.iter() {
508                    let child_unit = child.unit()?;
509                    if child_unit.is_empty() {
510                        // Numbers are always allowed in a product, so continue with the next.
511                        continue;
512                    }
513
514                    if unit.is_some() {
515                        // We already have a unit for the node, so another unit node is invalid.
516                        return Err(());
517                    }
518
519                    // We have the unit for the node.
520                    unit = Some(child_unit);
521                }
522                // We only keep track of specified units, so if we end up with a None and no failure
523                // so far, then we have a number.
524                unit.unwrap_or(CalcUnits::empty())
525            },
526            CalcNode::MinMax(children, _) | CalcNode::Hypot(children) => {
527                let mut unit = children.first().unwrap().unit()?;
528                for child in children.iter().skip(1) {
529                    let child_unit = child.unit()?;
530                    if !child_unit.can_sum_with(unit) {
531                        return Err(());
532                    }
533                    unit |= child_unit;
534                }
535                unit
536            },
537            CalcNode::Clamp { min, center, max } => {
538                let min_unit = min.unit()?;
539                let center_unit = center.unit()?;
540
541                if !min_unit.can_sum_with(center_unit) {
542                    return Err(());
543                }
544
545                let max_unit = max.unit()?;
546
547                if !center_unit.can_sum_with(max_unit) {
548                    return Err(());
549                }
550
551                min_unit | center_unit | max_unit
552            },
553            CalcNode::Round { value, step, .. } => {
554                let value_unit = value.unit()?;
555                let step_unit = step.unit()?;
556                if !step_unit.can_sum_with(value_unit) {
557                    return Err(());
558                }
559                value_unit | step_unit
560            },
561            CalcNode::ModRem {
562                dividend, divisor, ..
563            } => {
564                let dividend_unit = dividend.unit()?;
565                let divisor_unit = divisor.unit()?;
566                if !divisor_unit.can_sum_with(dividend_unit) {
567                    return Err(());
568                }
569                dividend_unit | divisor_unit
570            },
571            CalcNode::Sign(ref child) => {
572                // sign() always resolves to a number, but we still need to make sure that the
573                // child units make sense.
574                let _ = child.unit()?;
575                CalcUnits::empty()
576            },
577            CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
578        })
579    }
580
581    /// Negate the node inline.  If the node is distributive, it is replaced by the result,
582    /// otherwise the node is wrapped in a [`Negate`] node.
583    pub fn negate(&mut self) {
584        /// Node(params) -> Negate(Node(params))
585        fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
586            let result = mem::replace(s, CalcNode::dummy());
587            *s = CalcNode::Negate(Box::new(result));
588        }
589
590        match *self {
591            CalcNode::Leaf(ref mut leaf) => {
592                if leaf.map(std::ops::Neg::neg).is_err() {
593                    wrap_self_in_negate(self)
594                }
595            },
596            CalcNode::Negate(ref mut value) => {
597                // Don't negate the value here.  Replace `self` with it's child.
598                let result = mem::replace(value.as_mut(), Self::dummy());
599                *self = result;
600            },
601            CalcNode::Invert(_) => {
602                // -(1 / -10) == -(-0.1) == 0.1
603                wrap_self_in_negate(self)
604            },
605            CalcNode::Sum(ref mut children) => {
606                for child in children.iter_mut() {
607                    child.negate();
608                }
609            },
610            CalcNode::Product(_) => {
611                // -(2 * 3 / 4) == -(1.5)
612                wrap_self_in_negate(self);
613            },
614            CalcNode::MinMax(ref mut children, ref mut op) => {
615                for child in children.iter_mut() {
616                    child.negate();
617                }
618
619                // Negating min-max means the operation is swapped.
620                *op = match *op {
621                    MinMaxOp::Min => MinMaxOp::Max,
622                    MinMaxOp::Max => MinMaxOp::Min,
623                };
624            },
625            CalcNode::Clamp {
626                ref mut min,
627                ref mut center,
628                ref mut max,
629            } => {
630                if min.lte(max, PositivePercentageBasis::Unknown) {
631                    min.negate();
632                    center.negate();
633                    max.negate();
634
635                    mem::swap(min, max);
636                } else {
637                    wrap_self_in_negate(self);
638                }
639            },
640            CalcNode::Round {
641                ref mut strategy,
642                ref mut value,
643                ref mut step,
644            } => {
645                match *strategy {
646                    RoundingStrategy::Nearest => {
647                        // Nearest is tricky because we'd have to swap the
648                        // behavior at the half-way point from using the upper
649                        // to lower bound.
650                        // Simpler to just wrap self in a negate node.
651                        wrap_self_in_negate(self);
652                        return;
653                    },
654                    RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
655                    RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
656                    RoundingStrategy::ToZero => (),
657                }
658                value.negate();
659                step.negate();
660            },
661            CalcNode::ModRem {
662                ref mut dividend,
663                ref mut divisor,
664                ..
665            } => {
666                dividend.negate();
667                divisor.negate();
668            },
669            CalcNode::Hypot(ref mut children) => {
670                for child in children.iter_mut() {
671                    child.negate();
672                }
673            },
674            CalcNode::Abs(_) => {
675                wrap_self_in_negate(self);
676            },
677            CalcNode::Sign(ref mut child) => {
678                child.negate();
679            },
680            CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => {
681                wrap_self_in_negate(self);
682            },
683        }
684    }
685
686    fn sort_key(&self) -> SortKey {
687        match *self {
688            Self::Leaf(ref l) => l.sort_key(),
689            Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
690            _ => SortKey::Other,
691        }
692    }
693
694    /// Returns the leaf if we can (if simplification has allowed it).
695    pub fn as_leaf(&self) -> Option<&L> {
696        match *self {
697            Self::Leaf(ref l) => Some(l),
698            _ => None,
699        }
700    }
701
702    /// Tries to merge one node into another using the sum, that is, perform `x` + `y`.
703    pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
704        match (self, other) {
705            (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
706                one.try_sum_in_place(other)
707            },
708            _ => Err(()),
709        }
710    }
711
712    /// Tries to merge one node into another using the product, that is, perform `x` * `y`.
713    pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
714        if let Ok(resolved) = other.resolve() {
715            if let Some(number) = resolved.as_number() {
716                if number == 1.0 {
717                    return true;
718                }
719
720                if self.is_product_distributive() {
721                    if self.map(|v| v * number).is_err() {
722                        return false;
723                    }
724                    return true;
725                }
726            }
727        }
728
729        if let Ok(resolved) = self.resolve() {
730            if let Some(number) = resolved.as_number() {
731                if number == 1.0 {
732                    std::mem::swap(self, other);
733                    return true;
734                }
735
736                if other.is_product_distributive() {
737                    if other.map(|v| v * number).is_err() {
738                        return false;
739                    }
740                    std::mem::swap(self, other);
741                    return true;
742                }
743            }
744        }
745
746        false
747    }
748
749    /// Tries to apply a generic arithmetic operator
750    fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
751    where
752        O: Fn(f32, f32) -> f32,
753    {
754        match (self, other) {
755            (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
756                Ok(CalcNode::Leaf(one.try_op(other, op)?))
757            },
758            _ => Err(()),
759        }
760    }
761
762    /// Map the value of this node with the given operation.
763    pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
764        fn map_internal<L: CalcNodeLeaf>(
765            node: &mut CalcNode<L>,
766            op: &mut impl FnMut(f32) -> f32,
767        ) -> Result<(), ()> {
768            match node {
769                CalcNode::Leaf(l) => l.map(op),
770                CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
771                CalcNode::Sum(children) | CalcNode::Product(children) => {
772                    for node in &mut **children {
773                        map_internal(node, op)?;
774                    }
775                    Ok(())
776                },
777                CalcNode::MinMax(children, _) => {
778                    for node in &mut **children {
779                        map_internal(node, op)?;
780                    }
781                    Ok(())
782                },
783                CalcNode::Clamp { min, center, max } => {
784                    map_internal(min, op)?;
785                    map_internal(center, op)?;
786                    map_internal(max, op)
787                },
788                CalcNode::Round { value, step, .. } => {
789                    map_internal(value, op)?;
790                    map_internal(step, op)
791                },
792                CalcNode::ModRem {
793                    dividend, divisor, ..
794                } => {
795                    map_internal(dividend, op)?;
796                    map_internal(divisor, op)
797                },
798                CalcNode::Hypot(children) => {
799                    for node in &mut **children {
800                        map_internal(node, op)?;
801                    }
802                    Ok(())
803                },
804                CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
805                // It is invalid to treat inner `CalcNode`s here - `anchor(--foo 50%) / 2` != `anchor(--foo 25%)`.
806                // Same applies to fallback, as we don't know if it will be used. Similar reasoning applies to `anchor-size()`.
807                CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
808            }
809        }
810
811        map_internal(self, &mut op)
812    }
813
814    /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind.
815    pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
816    where
817        O: CalcNodeLeaf,
818        F: FnMut(&L) -> O,
819    {
820        self.map_leaves_internal(&mut map)
821    }
822
823    fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
824    where
825        O: CalcNodeLeaf,
826        F: FnMut(&L) -> O,
827    {
828        fn map_children<L, O, F>(
829            children: &[CalcNode<L>],
830            map: &mut F,
831        ) -> crate::OwnedSlice<CalcNode<O>>
832        where
833            L: CalcNodeLeaf,
834            O: CalcNodeLeaf,
835            F: FnMut(&L) -> O,
836        {
837            children
838                .iter()
839                .map(|c| c.map_leaves_internal(map))
840                .collect()
841        }
842
843        match *self {
844            Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
845            Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
846            Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
847            Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
848            Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
849            Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
850            Self::Clamp {
851                ref min,
852                ref center,
853                ref max,
854            } => {
855                let min = Box::new(min.map_leaves_internal(map));
856                let center = Box::new(center.map_leaves_internal(map));
857                let max = Box::new(max.map_leaves_internal(map));
858                CalcNode::Clamp { min, center, max }
859            },
860            Self::Round {
861                strategy,
862                ref value,
863                ref step,
864            } => {
865                let value = Box::new(value.map_leaves_internal(map));
866                let step = Box::new(step.map_leaves_internal(map));
867                CalcNode::Round {
868                    strategy,
869                    value,
870                    step,
871                }
872            },
873            Self::ModRem {
874                ref dividend,
875                ref divisor,
876                op,
877            } => {
878                let dividend = Box::new(dividend.map_leaves_internal(map));
879                let divisor = Box::new(divisor.map_leaves_internal(map));
880                CalcNode::ModRem {
881                    dividend,
882                    divisor,
883                    op,
884                }
885            },
886            Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
887            Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
888            Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
889            Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
890                target_element: f.target_element.clone(),
891                side: match &f.side {
892                    GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
893                    GenericAnchorSide::Percentage(p) => {
894                        GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
895                    },
896                },
897                fallback: f
898                    .fallback
899                    .as_ref()
900                    .map(|fb| Box::new(fb.map_leaves_internal(map)))
901                    .into(),
902            })),
903            Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
904                target_element: f.target_element.clone(),
905                size: f.size,
906                fallback: f
907                    .fallback
908                    .as_ref()
909                    .map(|fb| Box::new(fb.map_leaves_internal(map)))
910                    .into(),
911            })),
912        }
913    }
914
915    /// Resolve this node into a value.
916    pub fn resolve(&self) -> Result<L, ()> {
917        self.resolve_map(|l| Ok(l.clone()))
918    }
919
920    /// Resolve this node into a value, given a function that maps the leaf values.
921    pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
922    where
923        F: FnMut(&L) -> Result<L, ()>,
924    {
925        self.resolve_internal(&mut leaf_to_output_fn)
926    }
927
928    fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<L, ()>
929    where
930        F: FnMut(&L) -> Result<L, ()>,
931    {
932        match self {
933            Self::Leaf(l) => leaf_to_output_fn(l),
934            Self::Negate(child) => {
935                let mut result = child.resolve_internal(leaf_to_output_fn)?;
936                result.map(|v| v.neg())?;
937                Ok(result)
938            },
939            Self::Invert(child) => {
940                let mut result = child.resolve_internal(leaf_to_output_fn)?;
941                result.map(|v| 1.0 / v)?;
942                Ok(result)
943            },
944            Self::Sum(children) => {
945                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
946
947                for child in children.iter().skip(1) {
948                    let right = child.resolve_internal(leaf_to_output_fn)?;
949                    // try_op will make sure we only sum leaves with the same type.
950                    result = result.try_op(&right, |left, right| left + right)?;
951                }
952
953                Ok(result)
954            },
955            Self::Product(children) => {
956                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
957
958                for child in children.iter().skip(1) {
959                    let right = child.resolve_internal(leaf_to_output_fn)?;
960                    // Mutliply only allowed when either side is a number.
961                    match result.as_number() {
962                        Some(left) => {
963                            // Left side is a number, so we use the right node as the result.
964                            result = right;
965                            result.map(|v| v * left)?;
966                        },
967                        None => {
968                            // Left side is not a number, so check if the right side is.
969                            match right.as_number() {
970                                Some(right) => {
971                                    result.map(|v| v * right)?;
972                                },
973                                None => {
974                                    // Multiplying with both sides having units.
975                                    return Err(());
976                                },
977                            }
978                        },
979                    }
980                }
981
982                Ok(result)
983            },
984            Self::MinMax(children, op) => {
985                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
986
987                if result.is_nan()? {
988                    return Ok(result);
989                }
990
991                for child in children.iter().skip(1) {
992                    let candidate = child.resolve_internal(leaf_to_output_fn)?;
993
994                    // Leaf types must match for each child.
995                    if !result.is_same_unit_as(&candidate) {
996                        return Err(());
997                    }
998
999                    if candidate.is_nan()? {
1000                        result = candidate;
1001                        break;
1002                    }
1003
1004                    let candidate_wins = match op {
1005                        MinMaxOp::Min => candidate.lt(&result, PositivePercentageBasis::Yes),
1006                        MinMaxOp::Max => candidate.gt(&result, PositivePercentageBasis::Yes),
1007                    };
1008
1009                    if candidate_wins {
1010                        result = candidate;
1011                    }
1012                }
1013
1014                Ok(result)
1015            },
1016            Self::Clamp { min, center, max } => {
1017                let min = min.resolve_internal(leaf_to_output_fn)?;
1018                let center = center.resolve_internal(leaf_to_output_fn)?;
1019                let max = max.resolve_internal(leaf_to_output_fn)?;
1020
1021                if !min.is_same_unit_as(&center) || !max.is_same_unit_as(&center) {
1022                    return Err(());
1023                }
1024
1025                if min.is_nan()? {
1026                    return Ok(min);
1027                }
1028
1029                if center.is_nan()? {
1030                    return Ok(center);
1031                }
1032
1033                if max.is_nan()? {
1034                    return Ok(max);
1035                }
1036
1037                let mut result = center;
1038                if result.gt(&max, PositivePercentageBasis::Yes) {
1039                    result = max;
1040                }
1041                if result.lt(&min, PositivePercentageBasis::Yes) {
1042                    result = min
1043                }
1044
1045                Ok(result)
1046            },
1047            Self::Round {
1048                strategy,
1049                value,
1050                step,
1051            } => {
1052                let mut value = value.resolve_internal(leaf_to_output_fn)?;
1053                let step = step.resolve_internal(leaf_to_output_fn)?;
1054
1055                if !value.is_same_unit_as(&step) {
1056                    return Err(());
1057                }
1058
1059                let Some(step) = step.unitless_value() else {
1060                    return Err(());
1061                };
1062                let step = step.abs();
1063
1064                value.map(|value| {
1065                    // TODO(emilio): Seems like at least a few of these
1066                    // special-cases could be removed if we do the math in a
1067                    // particular order.
1068                    if step.is_zero() {
1069                        return f32::NAN;
1070                    }
1071
1072                    if value.is_infinite() {
1073                        if step.is_infinite() {
1074                            return f32::NAN;
1075                        }
1076                        return value;
1077                    }
1078
1079                    if step.is_infinite() {
1080                        match strategy {
1081                            RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1082                                return if value.is_sign_negative() { -0.0 } else { 0.0 }
1083                            },
1084                            RoundingStrategy::Up => {
1085                                return if !value.is_sign_negative() && !value.is_zero() {
1086                                    f32::INFINITY
1087                                } else if !value.is_sign_negative() && value.is_zero() {
1088                                    value
1089                                } else {
1090                                    -0.0
1091                                }
1092                            },
1093                            RoundingStrategy::Down => {
1094                                return if value.is_sign_negative() && !value.is_zero() {
1095                                    -f32::INFINITY
1096                                } else if value.is_sign_negative() && value.is_zero() {
1097                                    value
1098                                } else {
1099                                    0.0
1100                                }
1101                            },
1102                        }
1103                    }
1104
1105                    let div = value / step;
1106                    let lower_bound = div.floor() * step;
1107                    let upper_bound = div.ceil() * step;
1108
1109                    match strategy {
1110                        RoundingStrategy::Nearest => {
1111                            // In case of a tie, use the upper bound
1112                            if value - lower_bound < upper_bound - value {
1113                                lower_bound
1114                            } else {
1115                                upper_bound
1116                            }
1117                        },
1118                        RoundingStrategy::Up => upper_bound,
1119                        RoundingStrategy::Down => lower_bound,
1120                        RoundingStrategy::ToZero => {
1121                            // In case of a tie, use the upper bound
1122                            if lower_bound.abs() < upper_bound.abs() {
1123                                lower_bound
1124                            } else {
1125                                upper_bound
1126                            }
1127                        },
1128                    }
1129                })?;
1130
1131                Ok(value)
1132            },
1133            Self::ModRem {
1134                dividend,
1135                divisor,
1136                op,
1137            } => {
1138                let mut dividend = dividend.resolve_internal(leaf_to_output_fn)?;
1139                let divisor = divisor.resolve_internal(leaf_to_output_fn)?;
1140
1141                if !dividend.is_same_unit_as(&divisor) {
1142                    return Err(());
1143                }
1144
1145                let Some(divisor) = divisor.unitless_value() else {
1146                    return Err(());
1147                };
1148                dividend.map(|dividend| op.apply(dividend, divisor))?;
1149                Ok(dividend)
1150            },
1151            Self::Hypot(children) => {
1152                let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1153                result.map(|v| v.powi(2))?;
1154
1155                for child in children.iter().skip(1) {
1156                    let child_value = child.resolve_internal(leaf_to_output_fn)?;
1157
1158                    if !result.is_same_unit_as(&child_value) {
1159                        return Err(());
1160                    }
1161
1162                    let Some(child_value) = child_value.unitless_value() else {
1163                        return Err(());
1164                    };
1165                    result.map(|v| v + child_value.powi(2))?;
1166                }
1167
1168                result.map(|v| v.sqrt())?;
1169                Ok(result)
1170            },
1171            Self::Abs(ref c) => {
1172                let mut result = c.resolve_internal(leaf_to_output_fn)?;
1173
1174                result.map(|v| v.abs())?;
1175
1176                Ok(result)
1177            },
1178            Self::Sign(ref c) => {
1179                let result = c.resolve_internal(leaf_to_output_fn)?;
1180                Ok(L::sign_from(&result)?)
1181            },
1182            Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
1183        }
1184    }
1185
1186    /// Mutate nodes within this calc node tree using given the mapping function.
1187    pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
1188    where
1189        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1190    {
1191        self.map_node_internal(&mut mapping_fn)
1192    }
1193
1194    fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
1195    where
1196        F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1197    {
1198        if let Some(node) = mapping_fn(self)? {
1199            *self = node;
1200            // Assume that any sub-nodes don't need to be mutated.
1201            return Ok(());
1202        }
1203        match self {
1204            Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
1205            Self::Negate(child) | Self::Invert(child) | Self::Abs(child) | Self::Sign(child) => {
1206                child.map_node_internal(mapping_fn)?;
1207            },
1208            Self::Sum(children)
1209            | Self::Product(children)
1210            | Self::Hypot(children)
1211            | Self::MinMax(children, _) => {
1212                for child in children.iter_mut() {
1213                    child.map_node_internal(mapping_fn)?;
1214                }
1215            },
1216            Self::Clamp { min, center, max } => {
1217                min.map_node_internal(mapping_fn)?;
1218                center.map_node_internal(mapping_fn)?;
1219                max.map_node_internal(mapping_fn)?;
1220            },
1221            Self::Round { value, step, .. } => {
1222                value.map_node_internal(mapping_fn)?;
1223                step.map_node_internal(mapping_fn)?;
1224            },
1225            Self::ModRem {
1226                dividend, divisor, ..
1227            } => {
1228                dividend.map_node_internal(mapping_fn)?;
1229                divisor.map_node_internal(mapping_fn)?;
1230            },
1231        };
1232        Ok(())
1233    }
1234
1235    fn is_negative_leaf(&self) -> Result<bool, ()> {
1236        Ok(match *self {
1237            Self::Leaf(ref l) => l.is_negative()?,
1238            _ => false,
1239        })
1240    }
1241
1242    fn is_zero_leaf(&self) -> Result<bool, ()> {
1243        Ok(match *self {
1244            Self::Leaf(ref l) => l.is_zero()?,
1245            _ => false,
1246        })
1247    }
1248
1249    fn is_infinite_leaf(&self) -> Result<bool, ()> {
1250        Ok(match *self {
1251            Self::Leaf(ref l) => l.is_infinite()?,
1252            _ => false,
1253        })
1254    }
1255
1256    fn is_nan_leaf(&self) -> Result<bool, ()> {
1257        Ok(match *self {
1258            Self::Leaf(ref l) => l.is_nan()?,
1259            _ => false,
1260        })
1261    }
1262
1263    /// Visits all the nodes in this calculation tree recursively, starting by
1264    /// the leaves and bubbling all the way up.
1265    ///
1266    /// This is useful for simplification, but can also be used for validation
1267    /// and such.
1268    pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
1269        self.visit_depth_first_internal(&mut f)
1270    }
1271
1272    fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
1273        match *self {
1274            Self::Clamp {
1275                ref mut min,
1276                ref mut center,
1277                ref mut max,
1278            } => {
1279                min.visit_depth_first_internal(f);
1280                center.visit_depth_first_internal(f);
1281                max.visit_depth_first_internal(f);
1282            },
1283            Self::Round {
1284                ref mut value,
1285                ref mut step,
1286                ..
1287            } => {
1288                value.visit_depth_first_internal(f);
1289                step.visit_depth_first_internal(f);
1290            },
1291            Self::ModRem {
1292                ref mut dividend,
1293                ref mut divisor,
1294                ..
1295            } => {
1296                dividend.visit_depth_first_internal(f);
1297                divisor.visit_depth_first_internal(f);
1298            },
1299            Self::Sum(ref mut children)
1300            | Self::Product(ref mut children)
1301            | Self::MinMax(ref mut children, _)
1302            | Self::Hypot(ref mut children) => {
1303                for child in &mut **children {
1304                    child.visit_depth_first_internal(f);
1305                }
1306            },
1307            Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
1308                value.visit_depth_first_internal(f);
1309            },
1310            Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
1311                value.visit_depth_first_internal(f);
1312            },
1313            Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
1314        }
1315        f(self);
1316    }
1317
1318    /// This function simplifies and sorts the calculation of the specified node. It simplifies
1319    /// directly nested nodes while assuming that all nodes below it have already been simplified.
1320    /// It is recommended to use this function in combination with `visit_depth_first()`.
1321    ///
1322    /// This function is necessary only if the node needs to be preserved after parsing,
1323    /// specifically for `<length-percentage>` cases where the calculation contains percentages or
1324    /// relative units. Otherwise, the node can be evaluated using `resolve()`, which will
1325    /// automatically provide a simplified value.
1326    ///
1327    /// <https://drafts.csswg.org/css-values-4/#calc-simplification>
1328    pub fn simplify_and_sort_direct_children(&mut self) {
1329        macro_rules! replace_self_with {
1330            ($slot:expr) => {{
1331                let result = mem::replace($slot, Self::dummy());
1332                *self = result;
1333            }};
1334        }
1335
1336        macro_rules! value_or_stop {
1337            ($op:expr) => {{
1338                match $op {
1339                    Ok(value) => value,
1340                    Err(_) => return,
1341                }
1342            }};
1343        }
1344
1345        match *self {
1346            Self::Clamp {
1347                ref mut min,
1348                ref mut center,
1349                ref mut max,
1350            } => {
1351                // NOTE: clamp() is max(min, min(center, max))
1352                let min_cmp_center = match min.compare(&center, PositivePercentageBasis::Unknown) {
1353                    Some(o) => o,
1354                    None => return,
1355                };
1356
1357                // So if we can prove that min is more than center, then we won,
1358                // as that's what we should always return.
1359                if matches!(min_cmp_center, cmp::Ordering::Greater) {
1360                    replace_self_with!(&mut **min);
1361                    return;
1362                }
1363
1364                // Otherwise try with max.
1365                let max_cmp_center = match max.compare(&center, PositivePercentageBasis::Unknown) {
1366                    Some(o) => o,
1367                    None => return,
1368                };
1369
1370                if matches!(max_cmp_center, cmp::Ordering::Less) {
1371                    // max is less than center, so we need to return effectively
1372                    // `max(min, max)`.
1373                    let max_cmp_min = match max.compare(&min, PositivePercentageBasis::Unknown) {
1374                        Some(o) => o,
1375                        None => return,
1376                    };
1377
1378                    if matches!(max_cmp_min, cmp::Ordering::Less) {
1379                        replace_self_with!(&mut **min);
1380                        return;
1381                    }
1382
1383                    replace_self_with!(&mut **max);
1384                    return;
1385                }
1386
1387                // Otherwise we're the center node.
1388                replace_self_with!(&mut **center);
1389            },
1390            Self::Round {
1391                strategy,
1392                ref mut value,
1393                ref mut step,
1394            } => {
1395                if value_or_stop!(step.is_zero_leaf()) {
1396                    value_or_stop!(value.coerce_to_value(f32::NAN));
1397                    replace_self_with!(&mut **value);
1398                    return;
1399                }
1400
1401                if value_or_stop!(value.is_infinite_leaf())
1402                    && value_or_stop!(step.is_infinite_leaf())
1403                {
1404                    value_or_stop!(value.coerce_to_value(f32::NAN));
1405                    replace_self_with!(&mut **value);
1406                    return;
1407                }
1408
1409                if value_or_stop!(value.is_infinite_leaf()) {
1410                    replace_self_with!(&mut **value);
1411                    return;
1412                }
1413
1414                if value_or_stop!(step.is_infinite_leaf()) {
1415                    match strategy {
1416                        RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1417                            value_or_stop!(value.coerce_to_value(0.0));
1418                            replace_self_with!(&mut **value);
1419                            return;
1420                        },
1421                        RoundingStrategy::Up => {
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                        RoundingStrategy::Down => {
1440                            if value_or_stop!(value.is_negative_leaf())
1441                                && !value_or_stop!(value.is_zero_leaf())
1442                            {
1443                                value_or_stop!(value.coerce_to_value(f32::INFINITY));
1444                                replace_self_with!(&mut **value);
1445                                return;
1446                            } else if value_or_stop!(value.is_negative_leaf())
1447                                && value_or_stop!(value.is_zero_leaf())
1448                            {
1449                                replace_self_with!(&mut **value);
1450                                return;
1451                            } else {
1452                                value_or_stop!(value.coerce_to_value(0.0));
1453                                replace_self_with!(&mut **value);
1454                                return;
1455                            }
1456                        },
1457                    }
1458                }
1459
1460                if value_or_stop!(step.is_negative_leaf()) {
1461                    step.negate();
1462                }
1463
1464                let remainder = value_or_stop!(value.try_op(step, Rem::rem));
1465                if value_or_stop!(remainder.is_zero_leaf()) {
1466                    replace_self_with!(&mut **value);
1467                    return;
1468                }
1469
1470                let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
1471                {
1472                    let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1473                    let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub));
1474
1475                    (lower_bound, upper_bound)
1476                } else {
1477                    let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1478                    let upper_bound = value_or_stop!(lower_bound.try_op(&step, Add::add));
1479
1480                    (lower_bound, upper_bound)
1481                };
1482
1483                match strategy {
1484                    RoundingStrategy::Nearest => {
1485                        let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
1486                        let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
1487                        // In case of a tie, use the upper bound
1488                        if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1489                            replace_self_with!(&mut lower_bound);
1490                        } else {
1491                            replace_self_with!(&mut upper_bound);
1492                        }
1493                    },
1494                    RoundingStrategy::Up => {
1495                        replace_self_with!(&mut upper_bound);
1496                    },
1497                    RoundingStrategy::Down => {
1498                        replace_self_with!(&mut lower_bound);
1499                    },
1500                    RoundingStrategy::ToZero => {
1501                        let mut lower_diff = lower_bound.clone();
1502                        let mut upper_diff = upper_bound.clone();
1503
1504                        if value_or_stop!(lower_diff.is_negative_leaf()) {
1505                            lower_diff.negate();
1506                        }
1507
1508                        if value_or_stop!(upper_diff.is_negative_leaf()) {
1509                            upper_diff.negate();
1510                        }
1511
1512                        // In case of a tie, use the upper bound
1513                        if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1514                            replace_self_with!(&mut lower_bound);
1515                        } else {
1516                            replace_self_with!(&mut upper_bound);
1517                        }
1518                    },
1519                };
1520            },
1521            Self::ModRem {
1522                ref dividend,
1523                ref divisor,
1524                op,
1525            } => {
1526                let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
1527                replace_self_with!(&mut result);
1528            },
1529            Self::MinMax(ref mut children, op) => {
1530                let winning_order = match op {
1531                    MinMaxOp::Min => cmp::Ordering::Less,
1532                    MinMaxOp::Max => cmp::Ordering::Greater,
1533                };
1534
1535                if value_or_stop!(children[0].is_nan_leaf()) {
1536                    replace_self_with!(&mut children[0]);
1537                    return;
1538                }
1539
1540                let mut result = 0;
1541                for i in 1..children.len() {
1542                    if value_or_stop!(children[i].is_nan_leaf()) {
1543                        replace_self_with!(&mut children[i]);
1544                        return;
1545                    }
1546                    let o = match children[i]
1547                        .compare(&children[result], PositivePercentageBasis::Unknown)
1548                    {
1549                        // We can't compare all the children, so we can't
1550                        // know which one will actually win. Bail out and
1551                        // keep ourselves as a min / max function.
1552                        //
1553                        // TODO: Maybe we could simplify compatible children,
1554                        // see https://github.com/w3c/csswg-drafts/issues/4756
1555                        None => return,
1556                        Some(o) => o,
1557                    };
1558
1559                    if o == winning_order {
1560                        result = i;
1561                    }
1562                }
1563
1564                replace_self_with!(&mut children[result]);
1565            },
1566            Self::Sum(ref mut children_slot) => {
1567                let mut sums_to_merge = SmallVec::<[_; 3]>::new();
1568                let mut extra_kids = 0;
1569                for (i, child) in children_slot.iter().enumerate() {
1570                    if let Self::Sum(ref children) = *child {
1571                        extra_kids += children.len();
1572                        sums_to_merge.push(i);
1573                    }
1574                }
1575
1576                // If we only have one kid, we've already simplified it, and it
1577                // doesn't really matter whether it's a sum already or not, so
1578                // lift it up and continue.
1579                if children_slot.len() == 1 {
1580                    replace_self_with!(&mut children_slot[0]);
1581                    return;
1582                }
1583
1584                let mut children = mem::take(children_slot).into_vec();
1585
1586                if !sums_to_merge.is_empty() {
1587                    children.reserve(extra_kids - sums_to_merge.len());
1588                    // Merge all our nested sums, in reverse order so that the
1589                    // list indices are not invalidated.
1590                    for i in sums_to_merge.drain(..).rev() {
1591                        let kid_children = match children.swap_remove(i) {
1592                            Self::Sum(c) => c,
1593                            _ => unreachable!(),
1594                        };
1595
1596                        // This would be nicer with
1597                        // https://github.com/rust-lang/rust/issues/59878 fixed.
1598                        children.extend(kid_children.into_vec());
1599                    }
1600                }
1601
1602                debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1603
1604                // Sort by spec order.
1605                children.sort_unstable_by_key(|c| c.sort_key());
1606
1607                // NOTE: if the function returns true, by the docs of dedup_by,
1608                // a is removed.
1609                children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1610
1611                if children.len() == 1 {
1612                    // If only one children remains, lift it up, and carry on.
1613                    replace_self_with!(&mut children[0]);
1614                } else {
1615                    // Else put our simplified children back.
1616                    *children_slot = children.into_boxed_slice().into();
1617                }
1618            },
1619            Self::Product(ref mut children_slot) => {
1620                let mut products_to_merge = SmallVec::<[_; 3]>::new();
1621                let mut extra_kids = 0;
1622                for (i, child) in children_slot.iter().enumerate() {
1623                    if let Self::Product(ref children) = *child {
1624                        extra_kids += children.len();
1625                        products_to_merge.push(i);
1626                    }
1627                }
1628
1629                // If we only have one kid, we've already simplified it, and it
1630                // doesn't really matter whether it's a product already or not,
1631                // so lift it up and continue.
1632                if children_slot.len() == 1 {
1633                    replace_self_with!(&mut children_slot[0]);
1634                    return;
1635                }
1636
1637                let mut children = mem::take(children_slot).into_vec();
1638
1639                if !products_to_merge.is_empty() {
1640                    children.reserve(extra_kids - products_to_merge.len());
1641                    // Merge all our nested sums, in reverse order so that the
1642                    // list indices are not invalidated.
1643                    for i in products_to_merge.drain(..).rev() {
1644                        let kid_children = match children.swap_remove(i) {
1645                            Self::Product(c) => c,
1646                            _ => unreachable!(),
1647                        };
1648
1649                        // This would be nicer with
1650                        // https://github.com/rust-lang/rust/issues/59878 fixed.
1651                        children.extend(kid_children.into_vec());
1652                    }
1653                }
1654
1655                debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1656
1657                // Sort by spec order.
1658                children.sort_unstable_by_key(|c| c.sort_key());
1659
1660                // NOTE: if the function returns true, by the docs of dedup_by,
1661                // a is removed.
1662                children.dedup_by(|right, left| left.try_product_in_place(right));
1663
1664                if children.len() == 1 {
1665                    // If only one children remains, lift it up, and carry on.
1666                    replace_self_with!(&mut children[0]);
1667                } else {
1668                    // Else put our simplified children back.
1669                    *children_slot = children.into_boxed_slice().into();
1670                }
1671            },
1672            Self::Hypot(ref children) => {
1673                let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
1674
1675                for child in children.iter().skip(1) {
1676                    let square = value_or_stop!(child.try_op(&child, Mul::mul));
1677                    result = value_or_stop!(result.try_op(&square, Add::add));
1678                }
1679
1680                result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
1681
1682                replace_self_with!(&mut result);
1683            },
1684            Self::Abs(ref mut child) => {
1685                if let CalcNode::Leaf(leaf) = child.as_mut() {
1686                    value_or_stop!(leaf.map(|v| v.abs()));
1687                    replace_self_with!(&mut **child);
1688                }
1689            },
1690            Self::Sign(ref mut child) => {
1691                if let CalcNode::Leaf(leaf) = child.as_mut() {
1692                    let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
1693                    replace_self_with!(&mut result);
1694                }
1695            },
1696            Self::Negate(ref mut child) => {
1697                // Step 6.
1698                match &mut **child {
1699                    CalcNode::Leaf(_) => {
1700                        // 1. If root’s child is a numeric value, return an equivalent numeric value, but
1701                        // with the value negated (0 - value).
1702                        child.negate();
1703                        replace_self_with!(&mut **child);
1704                    },
1705                    CalcNode::Negate(value) => {
1706                        // 2. If root’s child is a Negate node, return the child’s child.
1707                        replace_self_with!(&mut **value);
1708                    },
1709                    _ => {
1710                        // 3. Return root.
1711                    },
1712                }
1713            },
1714            Self::Invert(ref mut child) => {
1715                // Step 7.
1716                match &mut **child {
1717                    CalcNode::Leaf(leaf) => {
1718                        // 1. If root’s child is a number (not a percentage or dimension) return the
1719                        // reciprocal of the child’s value.
1720                        if leaf.unit().is_empty() {
1721                            value_or_stop!(child.map(|v| 1.0 / v));
1722                            replace_self_with!(&mut **child);
1723                        }
1724                    },
1725                    CalcNode::Invert(value) => {
1726                        // 2. If root’s child is an Invert node, return the child’s child.
1727                        replace_self_with!(&mut **value);
1728                    },
1729                    _ => {
1730                        // 3. Return root.
1731                    },
1732                }
1733            },
1734            Self::Leaf(ref mut l) => {
1735                l.simplify();
1736            },
1737            Self::Anchor(ref mut f) => {
1738                if let GenericAnchorSide::Percentage(ref mut n) = f.side {
1739                    n.simplify_and_sort();
1740                }
1741                if let Some(fallback) = f.fallback.as_mut() {
1742                    fallback.simplify_and_sort();
1743                }
1744            },
1745            Self::AnchorSize(ref mut f) => {
1746                if let Some(fallback) = f.fallback.as_mut() {
1747                    fallback.simplify_and_sort();
1748                }
1749            },
1750        }
1751    }
1752
1753    /// Simplifies and sorts the kids in the whole calculation subtree.
1754    pub fn simplify_and_sort(&mut self) {
1755        self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
1756    }
1757
1758    fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
1759    where
1760        W: Write,
1761    {
1762        let write_closing_paren = match *self {
1763            Self::MinMax(_, op) => {
1764                dest.write_str(match op {
1765                    MinMaxOp::Max => "max(",
1766                    MinMaxOp::Min => "min(",
1767                })?;
1768                true
1769            },
1770            Self::Clamp { .. } => {
1771                dest.write_str("clamp(")?;
1772                true
1773            },
1774            Self::Round { strategy, .. } => {
1775                match strategy {
1776                    RoundingStrategy::Nearest => dest.write_str("round("),
1777                    RoundingStrategy::Up => dest.write_str("round(up, "),
1778                    RoundingStrategy::Down => dest.write_str("round(down, "),
1779                    RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
1780                }?;
1781
1782                true
1783            },
1784            Self::ModRem { op, .. } => {
1785                dest.write_str(match op {
1786                    ModRemOp::Mod => "mod(",
1787                    ModRemOp::Rem => "rem(",
1788                })?;
1789
1790                true
1791            },
1792            Self::Hypot(_) => {
1793                dest.write_str("hypot(")?;
1794                true
1795            },
1796            Self::Abs(_) => {
1797                dest.write_str("abs(")?;
1798                true
1799            },
1800            Self::Sign(_) => {
1801                dest.write_str("sign(")?;
1802                true
1803            },
1804            Self::Negate(_) => {
1805                // We never generate a [`Negate`] node as the root of a calculation, only inside
1806                // [`Sum`] nodes as a child. Because negate nodes are handled by the [`Sum`] node
1807                // directly (see below), this node will never be serialized.
1808                debug_assert!(
1809                    false,
1810                    "We never serialize Negate nodes as they are handled inside Sum nodes."
1811                );
1812                dest.write_str("(-1 * ")?;
1813                true
1814            },
1815            Self::Invert(_) => {
1816                if matches!(level, ArgumentLevel::CalculationRoot) {
1817                    dest.write_str("calc")?;
1818                }
1819                dest.write_str("(1 / ")?;
1820                true
1821            },
1822            Self::Sum(_) | Self::Product(_) => match level {
1823                ArgumentLevel::CalculationRoot => {
1824                    dest.write_str("calc(")?;
1825                    true
1826                },
1827                ArgumentLevel::ArgumentRoot => false,
1828                ArgumentLevel::Nested => {
1829                    dest.write_str("(")?;
1830                    true
1831                },
1832            },
1833            Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => match level {
1834                ArgumentLevel::CalculationRoot => {
1835                    dest.write_str("calc(")?;
1836                    true
1837                },
1838                ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
1839            },
1840        };
1841
1842        match *self {
1843            Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
1844                let mut first = true;
1845                for child in &**children {
1846                    if !first {
1847                        dest.write_str(", ")?;
1848                    }
1849                    first = false;
1850                    child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1851                }
1852            },
1853            Self::Negate(ref value) | Self::Invert(ref value) => {
1854                value.to_css_impl(dest, ArgumentLevel::Nested)?
1855            },
1856            Self::Sum(ref children) => {
1857                let mut first = true;
1858                for child in &**children {
1859                    if !first {
1860                        match child {
1861                            Self::Leaf(l) => {
1862                                if let Ok(true) = l.is_negative() {
1863                                    dest.write_str(" - ")?;
1864                                    let mut negated = l.clone();
1865                                    // We can unwrap here, because we already
1866                                    // checked if the value inside is negative.
1867                                    negated.map(std::ops::Neg::neg).unwrap();
1868                                    negated.to_css(dest)?;
1869                                } else {
1870                                    dest.write_str(" + ")?;
1871                                    l.to_css(dest)?;
1872                                }
1873                            },
1874                            Self::Negate(n) => {
1875                                dest.write_str(" - ")?;
1876                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
1877                            },
1878                            _ => {
1879                                dest.write_str(" + ")?;
1880                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
1881                            },
1882                        }
1883                    } else {
1884                        first = false;
1885                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
1886                    }
1887                }
1888            },
1889            Self::Product(ref children) => {
1890                let mut first = true;
1891                for child in &**children {
1892                    if !first {
1893                        match child {
1894                            Self::Invert(n) => {
1895                                dest.write_str(" / ")?;
1896                                n.to_css_impl(dest, ArgumentLevel::Nested)?;
1897                            },
1898                            _ => {
1899                                dest.write_str(" * ")?;
1900                                child.to_css_impl(dest, ArgumentLevel::Nested)?;
1901                            },
1902                        }
1903                    } else {
1904                        first = false;
1905                        child.to_css_impl(dest, ArgumentLevel::Nested)?;
1906                    }
1907                }
1908            },
1909            Self::Clamp {
1910                ref min,
1911                ref center,
1912                ref max,
1913            } => {
1914                min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1915                dest.write_str(", ")?;
1916                center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1917                dest.write_str(", ")?;
1918                max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1919            },
1920            Self::Round {
1921                ref value,
1922                ref step,
1923                ..
1924            } => {
1925                value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1926                dest.write_str(", ")?;
1927                step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1928            },
1929            Self::ModRem {
1930                ref dividend,
1931                ref divisor,
1932                ..
1933            } => {
1934                dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1935                dest.write_str(", ")?;
1936                divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1937            },
1938            Self::Abs(ref v) | Self::Sign(ref v) => {
1939                v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
1940            },
1941            Self::Leaf(ref l) => l.to_css(dest)?,
1942            Self::Anchor(ref f) => f.to_css(dest)?,
1943            Self::AnchorSize(ref f) => f.to_css(dest)?,
1944        }
1945
1946        if write_closing_paren {
1947            dest.write_char(')')?;
1948        }
1949        Ok(())
1950    }
1951
1952    fn to_typed_impl(&self, level: ArgumentLevel) -> Option<TypedValue> {
1953        // XXX Only supporting Sum and Leaf for now
1954        match *self {
1955            Self::Sum(ref children) => {
1956                let mut values = ThinVec::new();
1957                for child in &**children {
1958                    if let Some(TypedValue::Numeric(inner)) =
1959                        child.to_typed_impl(ArgumentLevel::Nested)
1960                    {
1961                        values.push(inner);
1962                    }
1963                }
1964                Some(TypedValue::Numeric(NumericValue::Sum { values }))
1965            },
1966            Self::Leaf(ref l) => match l.to_typed() {
1967                Some(TypedValue::Numeric(inner)) => match level {
1968                    ArgumentLevel::CalculationRoot => {
1969                        Some(TypedValue::Numeric(NumericValue::Sum {
1970                            values: ThinVec::from([inner]),
1971                        }))
1972                    },
1973                    ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => {
1974                        Some(TypedValue::Numeric(inner))
1975                    },
1976                },
1977                _ => None,
1978            },
1979            _ => None,
1980        }
1981    }
1982
1983    fn compare(
1984        &self,
1985        other: &Self,
1986        basis_positive: PositivePercentageBasis,
1987    ) -> Option<cmp::Ordering> {
1988        match (self, other) {
1989            (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
1990                one.compare(other, basis_positive)
1991            },
1992            _ => None,
1993        }
1994    }
1995
1996    compare_helpers!();
1997}
1998
1999impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
2000    /// <https://drafts.csswg.org/css-values/#calc-serialize>
2001    fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2002    where
2003        W: Write,
2004    {
2005        self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
2006    }
2007}
2008
2009impl<L: CalcNodeLeaf> ToTyped for CalcNode<L> {
2010    fn to_typed(&self) -> Option<TypedValue> {
2011        self.to_typed_impl(ArgumentLevel::CalculationRoot)
2012    }
2013}
2014
2015#[cfg(test)]
2016mod tests {
2017    use super::*;
2018
2019    #[test]
2020    fn can_sum_with_checks() {
2021        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH));
2022        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::PERCENTAGE));
2023        assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2024
2025        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2026        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2027        assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2028
2029        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2030        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2031        assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2032
2033        assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::TIME));
2034        assert!(CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE));
2035
2036        assert!(!(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE));
2037        assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME));
2038        assert!(
2039            !(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME)
2040        );
2041    }
2042}