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