1use crate::derives::*;
10use crate::values::generics::length::GenericAnchorSizeFunction;
11use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide};
12use num_traits::Zero;
13use smallvec::SmallVec;
14use std::fmt::{self, Write};
15use std::ops::{Add, Mul, Neg, Rem, Sub};
16use std::{cmp, mem};
17use style_traits::{CssWriter, NumericValue, ToCss, ToTyped, TypedValue};
18
19use thin_vec::ThinVec;
20
21#[derive(
23 Clone,
24 Copy,
25 Debug,
26 Deserialize,
27 MallocSizeOf,
28 PartialEq,
29 Serialize,
30 ToAnimatedZero,
31 ToResolvedValue,
32 ToShmem,
33)]
34#[repr(u8)]
35pub enum MinMaxOp {
36 Min,
38 Max,
40}
41
42#[derive(
44 Clone,
45 Copy,
46 Debug,
47 Deserialize,
48 MallocSizeOf,
49 PartialEq,
50 Serialize,
51 ToAnimatedZero,
52 ToResolvedValue,
53 ToShmem,
54)]
55#[repr(u8)]
56pub enum ModRemOp {
57 Mod,
59 Rem,
61}
62
63impl ModRemOp {
64 fn apply(self, dividend: f32, divisor: f32) -> f32 {
65 if matches!(self, Self::Mod)
69 && divisor.is_infinite()
70 && dividend.is_sign_negative() != divisor.is_sign_negative()
71 {
72 return f32::NAN;
73 }
74
75 let (r, same_sign_as) = match self {
76 Self::Mod => (dividend - divisor * (dividend / divisor).floor(), divisor),
77 Self::Rem => (dividend - divisor * (dividend / divisor).trunc(), dividend),
78 };
79 if r == 0.0 && same_sign_as.is_sign_negative() {
80 -0.0
81 } else {
82 r
83 }
84 }
85}
86
87#[derive(
89 Clone,
90 Copy,
91 Debug,
92 Deserialize,
93 MallocSizeOf,
94 PartialEq,
95 Serialize,
96 ToAnimatedZero,
97 ToResolvedValue,
98 ToShmem,
99)]
100#[repr(u8)]
101pub enum RoundingStrategy {
102 Nearest,
105 Up,
108 Down,
111 ToZero,
114}
115
116#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
120#[allow(missing_docs)]
121pub enum SortKey {
122 Number,
123 Percentage,
124 Cap,
125 Ch,
126 Cqb,
127 Cqh,
128 Cqi,
129 Cqmax,
130 Cqmin,
131 Cqw,
132 Deg,
133 Dppx,
134 Dvb,
135 Dvh,
136 Dvi,
137 Dvmax,
138 Dvmin,
139 Dvw,
140 Em,
141 Ex,
142 Ic,
143 Lh,
144 Lvb,
145 Lvh,
146 Lvi,
147 Lvmax,
148 Lvmin,
149 Lvw,
150 Px,
151 Rcap,
152 Rch,
153 Rem,
154 Rex,
155 Ric,
156 Rlh,
157 Sec,
158 Svb,
159 Svh,
160 Svi,
161 Svmax,
162 Svmin,
163 Svw,
164 Vb,
165 Vh,
166 Vi,
167 Vmax,
168 Vmin,
169 Vw,
170 ColorComponent,
171 Other,
172}
173
174pub type GenericCalcAnchorFunction<L> =
176 GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericCalcNode<L>>>;
177pub type GenericCalcAnchorSizeFunction<L> = GenericAnchorSizeFunction<Box<GenericCalcNode<L>>>;
179
180#[repr(u8)]
192#[derive(
193 Clone,
194 Debug,
195 Deserialize,
196 MallocSizeOf,
197 PartialEq,
198 Serialize,
199 ToAnimatedZero,
200 ToResolvedValue,
201 ToShmem,
202)]
203pub enum GenericCalcNode<L> {
204 Leaf(L),
206 Negate(Box<GenericCalcNode<L>>),
208 Invert(Box<GenericCalcNode<L>>),
211 Sum(crate::OwnedSlice<GenericCalcNode<L>>),
214 Product(crate::OwnedSlice<GenericCalcNode<L>>),
217 MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp),
219 Clamp {
221 min: Box<GenericCalcNode<L>>,
223 center: Box<GenericCalcNode<L>>,
225 max: Box<GenericCalcNode<L>>,
227 },
228 Round {
230 strategy: RoundingStrategy,
232 value: Box<GenericCalcNode<L>>,
234 step: Box<GenericCalcNode<L>>,
236 },
237 ModRem {
239 dividend: Box<GenericCalcNode<L>>,
241 divisor: Box<GenericCalcNode<L>>,
243 op: ModRemOp,
245 },
246 Hypot(crate::OwnedSlice<GenericCalcNode<L>>),
248 Abs(Box<GenericCalcNode<L>>),
250 Sign(Box<GenericCalcNode<L>>),
252 Anchor(Box<GenericCalcAnchorFunction<L>>),
254 AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>),
256}
257
258pub use self::GenericCalcNode as CalcNode;
259
260bitflags! {
261 #[derive(Clone, Copy, PartialEq, Eq)]
267 pub struct CalcUnits: u8 {
268 const LENGTH = 1 << 0;
270 const PERCENTAGE = 1 << 1;
272 const ANGLE = 1 << 2;
274 const TIME = 1 << 3;
276 const RESOLUTION = 1 << 4;
278 const COLOR_COMPONENT = 1 << 5;
280
281 const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits();
283 const ALL = Self::LENGTH.bits() | Self::PERCENTAGE.bits() | Self::ANGLE.bits() |
286 Self::TIME.bits() | Self::RESOLUTION.bits() | Self::COLOR_COMPONENT.bits();
287 }
288}
289
290impl CalcUnits {
291 #[inline]
294 fn is_single_unit(&self) -> bool {
295 self.bits() == 0 || self.bits() & (self.bits() - 1) == 0
296 }
297
298 #[inline]
300 fn can_sum_with(&self, other: Self) -> bool {
301 match *self {
302 Self::LENGTH => other.intersects(Self::LENGTH | Self::PERCENTAGE),
303 Self::PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
304 Self::LENGTH_PERCENTAGE => other.intersects(Self::LENGTH | Self::PERCENTAGE),
305 u => u.is_single_unit() && other == u,
306 }
307 }
308}
309
310pub enum PositivePercentageBasis {
313 Unknown,
315 Yes,
317}
318
319macro_rules! compare_helpers {
320 () => {
321 #[allow(unused)]
323 fn gt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
324 self.compare(other, basis_positive) == Some(cmp::Ordering::Greater)
325 }
326
327 fn lt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
329 self.compare(other, basis_positive) == Some(cmp::Ordering::Less)
330 }
331
332 fn lte(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
334 match self.compare(other, basis_positive) {
335 Some(cmp::Ordering::Less) => true,
336 Some(cmp::Ordering::Equal) => true,
337 Some(cmp::Ordering::Greater) => false,
338 None => false,
339 }
340 }
341 };
342}
343
344pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss + ToTyped {
346 fn unit(&self) -> CalcUnits;
348
349 fn unitless_value(&self) -> Option<f32>;
351
352 fn is_same_unit_as(&self, other: &Self) -> bool {
355 std::mem::discriminant(self) == std::mem::discriminant(other)
356 }
357
358 fn compare(
360 &self,
361 other: &Self,
362 base_is_positive: PositivePercentageBasis,
363 ) -> Option<cmp::Ordering>;
364 compare_helpers!();
365
366 fn new_number(value: f32) -> Self;
368
369 fn as_number(&self) -> Option<f32>;
371
372 fn is_negative(&self) -> Result<bool, ()> {
374 self.unitless_value()
375 .map(|v| Ok(v.is_sign_negative()))
376 .unwrap_or_else(|| Err(()))
377 }
378
379 fn is_infinite(&self) -> Result<bool, ()> {
381 self.unitless_value()
382 .map(|v| Ok(v.is_infinite()))
383 .unwrap_or_else(|| Err(()))
384 }
385
386 fn is_zero(&self) -> Result<bool, ()> {
388 self.unitless_value()
389 .map(|v| Ok(v.is_zero()))
390 .unwrap_or_else(|| Err(()))
391 }
392
393 fn is_nan(&self) -> Result<bool, ()> {
395 self.unitless_value()
396 .map(|v| Ok(v.is_nan()))
397 .unwrap_or_else(|| Err(()))
398 }
399
400 fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
402
403 fn try_product_in_place(&mut self, other: &mut Self) -> bool;
406
407 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
409 where
410 O: Fn(f32, f32) -> f32;
411
412 fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>;
414
415 fn simplify(&mut self);
417
418 fn sort_key(&self) -> SortKey;
420
421 fn sign_from(leaf: &impl CalcNodeLeaf) -> Result<Self, ()> {
423 let Some(value) = leaf.unitless_value() else {
424 return Err(());
425 };
426
427 Ok(Self::new_number(if value.is_nan() {
428 f32::NAN
429 } else if value.is_zero() {
430 value
431 } else if value.is_sign_negative() {
432 -1.0
433 } else {
434 1.0
435 }))
436 }
437}
438
439enum ArgumentLevel {
441 CalculationRoot,
443 ArgumentRoot,
446 Nested,
448}
449
450impl<L: CalcNodeLeaf> CalcNode<L> {
451 fn dummy() -> Self {
453 Self::MinMax(Default::default(), MinMaxOp::Max)
454 }
455
456 fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
460 self.map(|_| value)
461 }
462
463 #[inline]
467 pub fn is_product_distributive(&self) -> bool {
468 match self {
469 Self::Leaf(l) => l.unit() != CalcUnits::COLOR_COMPONENT,
470 Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()),
471 _ => false,
472 }
473 }
474
475 pub fn unit(&self) -> Result<CalcUnits, ()> {
477 Ok(match self {
478 CalcNode::Leaf(l) => l.unit(),
479 CalcNode::Negate(child) | CalcNode::Invert(child) | CalcNode::Abs(child) => {
480 child.unit()?
481 },
482 CalcNode::Sum(children) => {
483 let mut unit = children.first().unwrap().unit()?;
484 for child in children.iter().skip(1) {
485 let child_unit = child.unit()?;
486 if !child_unit.can_sum_with(unit) {
487 return Err(());
488 }
489 unit |= child_unit;
490 }
491 unit
492 },
493 CalcNode::Product(children) => {
494 let mut unit = None;
496 for child in children.iter() {
497 let child_unit = child.unit()?;
498 if child_unit.is_empty() {
499 continue;
501 }
502
503 if unit.is_some() {
504 return Err(());
506 }
507
508 unit = Some(child_unit);
510 }
511 unit.unwrap_or(CalcUnits::empty())
514 },
515 CalcNode::MinMax(children, _) | CalcNode::Hypot(children) => {
516 let mut unit = children.first().unwrap().unit()?;
517 for child in children.iter().skip(1) {
518 let child_unit = child.unit()?;
519 if !child_unit.can_sum_with(unit) {
520 return Err(());
521 }
522 unit |= child_unit;
523 }
524 unit
525 },
526 CalcNode::Clamp { min, center, max } => {
527 let min_unit = min.unit()?;
528 let center_unit = center.unit()?;
529
530 if !min_unit.can_sum_with(center_unit) {
531 return Err(());
532 }
533
534 let max_unit = max.unit()?;
535
536 if !center_unit.can_sum_with(max_unit) {
537 return Err(());
538 }
539
540 min_unit | center_unit | max_unit
541 },
542 CalcNode::Round { value, step, .. } => {
543 let value_unit = value.unit()?;
544 let step_unit = step.unit()?;
545 if !step_unit.can_sum_with(value_unit) {
546 return Err(());
547 }
548 value_unit | step_unit
549 },
550 CalcNode::ModRem {
551 dividend, divisor, ..
552 } => {
553 let dividend_unit = dividend.unit()?;
554 let divisor_unit = divisor.unit()?;
555 if !divisor_unit.can_sum_with(dividend_unit) {
556 return Err(());
557 }
558 dividend_unit | divisor_unit
559 },
560 CalcNode::Sign(ref child) => {
561 let _ = child.unit()?;
564 CalcUnits::empty()
565 },
566 CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
567 })
568 }
569
570 pub fn negate(&mut self) {
573 fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
575 let result = mem::replace(s, CalcNode::dummy());
576 *s = CalcNode::Negate(Box::new(result));
577 }
578
579 match *self {
580 CalcNode::Leaf(ref mut leaf) => {
581 if leaf.map(std::ops::Neg::neg).is_err() {
582 wrap_self_in_negate(self)
583 }
584 },
585 CalcNode::Negate(ref mut value) => {
586 let result = mem::replace(value.as_mut(), Self::dummy());
588 *self = result;
589 },
590 CalcNode::Invert(_) => {
591 wrap_self_in_negate(self)
593 },
594 CalcNode::Sum(ref mut children) => {
595 for child in children.iter_mut() {
596 child.negate();
597 }
598 },
599 CalcNode::Product(_) => {
600 wrap_self_in_negate(self);
602 },
603 CalcNode::MinMax(ref mut children, ref mut op) => {
604 for child in children.iter_mut() {
605 child.negate();
606 }
607
608 *op = match *op {
610 MinMaxOp::Min => MinMaxOp::Max,
611 MinMaxOp::Max => MinMaxOp::Min,
612 };
613 },
614 CalcNode::Clamp {
615 ref mut min,
616 ref mut center,
617 ref mut max,
618 } => {
619 if min.lte(max, PositivePercentageBasis::Unknown) {
620 min.negate();
621 center.negate();
622 max.negate();
623
624 mem::swap(min, max);
625 } else {
626 wrap_self_in_negate(self);
627 }
628 },
629 CalcNode::Round {
630 ref mut strategy,
631 ref mut value,
632 ref mut step,
633 } => {
634 match *strategy {
635 RoundingStrategy::Nearest => {
636 wrap_self_in_negate(self);
641 return;
642 },
643 RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
644 RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
645 RoundingStrategy::ToZero => (),
646 }
647 value.negate();
648 step.negate();
649 },
650 CalcNode::ModRem {
651 ref mut dividend,
652 ref mut divisor,
653 ..
654 } => {
655 dividend.negate();
656 divisor.negate();
657 },
658 CalcNode::Hypot(ref mut children) => {
659 for child in children.iter_mut() {
660 child.negate();
661 }
662 },
663 CalcNode::Abs(_) => {
664 wrap_self_in_negate(self);
665 },
666 CalcNode::Sign(ref mut child) => {
667 child.negate();
668 },
669 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => {
670 wrap_self_in_negate(self);
671 },
672 }
673 }
674
675 fn sort_key(&self) -> SortKey {
676 match *self {
677 Self::Leaf(ref l) => l.sort_key(),
678 Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
679 _ => SortKey::Other,
680 }
681 }
682
683 pub fn as_leaf(&self) -> Option<&L> {
685 match *self {
686 Self::Leaf(ref l) => Some(l),
687 _ => None,
688 }
689 }
690
691 pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
693 match (self, other) {
694 (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
695 one.try_sum_in_place(other)
696 },
697 _ => Err(()),
698 }
699 }
700
701 pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
703 if let Ok(resolved) = other.resolve() {
704 if let Some(number) = resolved.as_number() {
705 if number == 1.0 {
706 return true;
707 }
708
709 if self.is_product_distributive() {
710 if self.map(|v| v * number).is_err() {
711 return false;
712 }
713 return true;
714 }
715 }
716 }
717
718 if let Ok(resolved) = self.resolve() {
719 if let Some(number) = resolved.as_number() {
720 if number == 1.0 {
721 std::mem::swap(self, other);
722 return true;
723 }
724
725 if other.is_product_distributive() {
726 if other.map(|v| v * number).is_err() {
727 return false;
728 }
729 std::mem::swap(self, other);
730 return true;
731 }
732 }
733 }
734
735 false
736 }
737
738 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
740 where
741 O: Fn(f32, f32) -> f32,
742 {
743 match (self, other) {
744 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
745 Ok(CalcNode::Leaf(one.try_op(other, op)?))
746 },
747 _ => Err(()),
748 }
749 }
750
751 pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
753 fn map_internal<L: CalcNodeLeaf>(
754 node: &mut CalcNode<L>,
755 op: &mut impl FnMut(f32) -> f32,
756 ) -> Result<(), ()> {
757 match node {
758 CalcNode::Leaf(l) => l.map(op),
759 CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
760 CalcNode::Sum(children) | CalcNode::Product(children) => {
761 for node in &mut **children {
762 map_internal(node, op)?;
763 }
764 Ok(())
765 },
766 CalcNode::MinMax(children, _) => {
767 for node in &mut **children {
768 map_internal(node, op)?;
769 }
770 Ok(())
771 },
772 CalcNode::Clamp { min, center, max } => {
773 map_internal(min, op)?;
774 map_internal(center, op)?;
775 map_internal(max, op)
776 },
777 CalcNode::Round { value, step, .. } => {
778 map_internal(value, op)?;
779 map_internal(step, op)
780 },
781 CalcNode::ModRem {
782 dividend, divisor, ..
783 } => {
784 map_internal(dividend, op)?;
785 map_internal(divisor, op)
786 },
787 CalcNode::Hypot(children) => {
788 for node in &mut **children {
789 map_internal(node, op)?;
790 }
791 Ok(())
792 },
793 CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
794 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
797 }
798 }
799
800 map_internal(self, &mut op)
801 }
802
803 pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
805 where
806 O: CalcNodeLeaf,
807 F: FnMut(&L) -> O,
808 {
809 self.map_leaves_internal(&mut map)
810 }
811
812 fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
813 where
814 O: CalcNodeLeaf,
815 F: FnMut(&L) -> O,
816 {
817 fn map_children<L, O, F>(
818 children: &[CalcNode<L>],
819 map: &mut F,
820 ) -> crate::OwnedSlice<CalcNode<O>>
821 where
822 L: CalcNodeLeaf,
823 O: CalcNodeLeaf,
824 F: FnMut(&L) -> O,
825 {
826 children
827 .iter()
828 .map(|c| c.map_leaves_internal(map))
829 .collect()
830 }
831
832 match *self {
833 Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
834 Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
835 Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
836 Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
837 Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
838 Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
839 Self::Clamp {
840 ref min,
841 ref center,
842 ref max,
843 } => {
844 let min = Box::new(min.map_leaves_internal(map));
845 let center = Box::new(center.map_leaves_internal(map));
846 let max = Box::new(max.map_leaves_internal(map));
847 CalcNode::Clamp { min, center, max }
848 },
849 Self::Round {
850 strategy,
851 ref value,
852 ref step,
853 } => {
854 let value = Box::new(value.map_leaves_internal(map));
855 let step = Box::new(step.map_leaves_internal(map));
856 CalcNode::Round {
857 strategy,
858 value,
859 step,
860 }
861 },
862 Self::ModRem {
863 ref dividend,
864 ref divisor,
865 op,
866 } => {
867 let dividend = Box::new(dividend.map_leaves_internal(map));
868 let divisor = Box::new(divisor.map_leaves_internal(map));
869 CalcNode::ModRem {
870 dividend,
871 divisor,
872 op,
873 }
874 },
875 Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
876 Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
877 Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
878 Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
879 target_element: f.target_element.clone(),
880 side: match &f.side {
881 GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
882 GenericAnchorSide::Percentage(p) => {
883 GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
884 },
885 },
886 fallback: f
887 .fallback
888 .as_ref()
889 .map(|fb| Box::new(fb.map_leaves_internal(map)))
890 .into(),
891 })),
892 Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
893 target_element: f.target_element.clone(),
894 size: f.size,
895 fallback: f
896 .fallback
897 .as_ref()
898 .map(|fb| Box::new(fb.map_leaves_internal(map)))
899 .into(),
900 })),
901 }
902 }
903
904 pub fn resolve(&self) -> Result<L, ()> {
906 self.resolve_map(|l| Ok(l.clone()))
907 }
908
909 pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
911 where
912 F: FnMut(&L) -> Result<L, ()>,
913 {
914 self.resolve_internal(&mut leaf_to_output_fn)
915 }
916
917 fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<L, ()>
918 where
919 F: FnMut(&L) -> Result<L, ()>,
920 {
921 match self {
922 Self::Leaf(l) => leaf_to_output_fn(l),
923 Self::Negate(child) => {
924 let mut result = child.resolve_internal(leaf_to_output_fn)?;
925 result.map(|v| v.neg())?;
926 Ok(result)
927 },
928 Self::Invert(child) => {
929 let mut result = child.resolve_internal(leaf_to_output_fn)?;
930 result.map(|v| 1.0 / v)?;
931 Ok(result)
932 },
933 Self::Sum(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 result = result.try_op(&right, |left, right| left + right)?;
940 }
941
942 Ok(result)
943 },
944 Self::Product(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 match result.as_number() {
951 Some(left) => {
952 result = right;
954 result.map(|v| v * left)?;
955 },
956 None => {
957 match right.as_number() {
959 Some(right) => {
960 result.map(|v| v * right)?;
961 },
962 None => {
963 return Err(());
965 },
966 }
967 },
968 }
969 }
970
971 Ok(result)
972 },
973 Self::MinMax(children, op) => {
974 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
975
976 if result.is_nan()? {
977 return Ok(result);
978 }
979
980 for child in children.iter().skip(1) {
981 let candidate = child.resolve_internal(leaf_to_output_fn)?;
982
983 if !result.is_same_unit_as(&candidate) {
985 return Err(());
986 }
987
988 if candidate.is_nan()? {
989 result = candidate;
990 break;
991 }
992
993 let candidate_wins = match op {
994 MinMaxOp::Min => candidate.lt(&result, PositivePercentageBasis::Yes),
995 MinMaxOp::Max => candidate.gt(&result, PositivePercentageBasis::Yes),
996 };
997
998 if candidate_wins {
999 result = candidate;
1000 }
1001 }
1002
1003 Ok(result)
1004 },
1005 Self::Clamp { min, center, max } => {
1006 let min = min.resolve_internal(leaf_to_output_fn)?;
1007 let center = center.resolve_internal(leaf_to_output_fn)?;
1008 let max = max.resolve_internal(leaf_to_output_fn)?;
1009
1010 if !min.is_same_unit_as(¢er) || !max.is_same_unit_as(¢er) {
1011 return Err(());
1012 }
1013
1014 if min.is_nan()? {
1015 return Ok(min);
1016 }
1017
1018 if center.is_nan()? {
1019 return Ok(center);
1020 }
1021
1022 if max.is_nan()? {
1023 return Ok(max);
1024 }
1025
1026 let mut result = center;
1027 if result.gt(&max, PositivePercentageBasis::Yes) {
1028 result = max;
1029 }
1030 if result.lt(&min, PositivePercentageBasis::Yes) {
1031 result = min
1032 }
1033
1034 Ok(result)
1035 },
1036 Self::Round {
1037 strategy,
1038 value,
1039 step,
1040 } => {
1041 let mut value = value.resolve_internal(leaf_to_output_fn)?;
1042 let step = step.resolve_internal(leaf_to_output_fn)?;
1043
1044 if !value.is_same_unit_as(&step) {
1045 return Err(());
1046 }
1047
1048 let Some(step) = step.unitless_value() else {
1049 return Err(());
1050 };
1051 let step = step.abs();
1052
1053 value.map(|value| {
1054 if step.is_zero() {
1058 return f32::NAN;
1059 }
1060
1061 if value.is_infinite() {
1062 if step.is_infinite() {
1063 return f32::NAN;
1064 }
1065 return value;
1066 }
1067
1068 if step.is_infinite() {
1069 match strategy {
1070 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1071 return if value.is_sign_negative() { -0.0 } else { 0.0 }
1072 },
1073 RoundingStrategy::Up => {
1074 return if !value.is_sign_negative() && !value.is_zero() {
1075 f32::INFINITY
1076 } else if !value.is_sign_negative() && value.is_zero() {
1077 value
1078 } else {
1079 -0.0
1080 }
1081 },
1082 RoundingStrategy::Down => {
1083 return if value.is_sign_negative() && !value.is_zero() {
1084 -f32::INFINITY
1085 } else if value.is_sign_negative() && value.is_zero() {
1086 value
1087 } else {
1088 0.0
1089 }
1090 },
1091 }
1092 }
1093
1094 let div = value / step;
1095 let lower_bound = div.floor() * step;
1096 let upper_bound = div.ceil() * step;
1097
1098 match strategy {
1099 RoundingStrategy::Nearest => {
1100 if value - lower_bound < upper_bound - value {
1102 lower_bound
1103 } else {
1104 upper_bound
1105 }
1106 },
1107 RoundingStrategy::Up => upper_bound,
1108 RoundingStrategy::Down => lower_bound,
1109 RoundingStrategy::ToZero => {
1110 if lower_bound.abs() < upper_bound.abs() {
1112 lower_bound
1113 } else {
1114 upper_bound
1115 }
1116 },
1117 }
1118 })?;
1119
1120 Ok(value)
1121 },
1122 Self::ModRem {
1123 dividend,
1124 divisor,
1125 op,
1126 } => {
1127 let mut dividend = dividend.resolve_internal(leaf_to_output_fn)?;
1128 let divisor = divisor.resolve_internal(leaf_to_output_fn)?;
1129
1130 if !dividend.is_same_unit_as(&divisor) {
1131 return Err(());
1132 }
1133
1134 let Some(divisor) = divisor.unitless_value() else {
1135 return Err(());
1136 };
1137 dividend.map(|dividend| op.apply(dividend, divisor))?;
1138 Ok(dividend)
1139 },
1140 Self::Hypot(children) => {
1141 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1142 result.map(|v| v.powi(2))?;
1143
1144 for child in children.iter().skip(1) {
1145 let child_value = child.resolve_internal(leaf_to_output_fn)?;
1146
1147 if !result.is_same_unit_as(&child_value) {
1148 return Err(());
1149 }
1150
1151 let Some(child_value) = child_value.unitless_value() else {
1152 return Err(());
1153 };
1154 result.map(|v| v + child_value.powi(2))?;
1155 }
1156
1157 result.map(|v| v.sqrt())?;
1158 Ok(result)
1159 },
1160 Self::Abs(ref c) => {
1161 let mut result = c.resolve_internal(leaf_to_output_fn)?;
1162
1163 result.map(|v| v.abs())?;
1164
1165 Ok(result)
1166 },
1167 Self::Sign(ref c) => {
1168 let result = c.resolve_internal(leaf_to_output_fn)?;
1169 Ok(L::sign_from(&result)?)
1170 },
1171 Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
1172 }
1173 }
1174
1175 pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
1177 where
1178 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1179 {
1180 self.map_node_internal(&mut mapping_fn)
1181 }
1182
1183 fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
1184 where
1185 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1186 {
1187 if let Some(node) = mapping_fn(self)? {
1188 *self = node;
1189 return Ok(());
1191 }
1192 match self {
1193 Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
1194 Self::Negate(child) | Self::Invert(child) | Self::Abs(child) | Self::Sign(child) => {
1195 child.map_node_internal(mapping_fn)?;
1196 },
1197 Self::Sum(children)
1198 | Self::Product(children)
1199 | Self::Hypot(children)
1200 | Self::MinMax(children, _) => {
1201 for child in children.iter_mut() {
1202 child.map_node_internal(mapping_fn)?;
1203 }
1204 },
1205 Self::Clamp { min, center, max } => {
1206 min.map_node_internal(mapping_fn)?;
1207 center.map_node_internal(mapping_fn)?;
1208 max.map_node_internal(mapping_fn)?;
1209 },
1210 Self::Round { value, step, .. } => {
1211 value.map_node_internal(mapping_fn)?;
1212 step.map_node_internal(mapping_fn)?;
1213 },
1214 Self::ModRem {
1215 dividend, divisor, ..
1216 } => {
1217 dividend.map_node_internal(mapping_fn)?;
1218 divisor.map_node_internal(mapping_fn)?;
1219 },
1220 };
1221 Ok(())
1222 }
1223
1224 fn is_negative_leaf(&self) -> Result<bool, ()> {
1225 Ok(match *self {
1226 Self::Leaf(ref l) => l.is_negative()?,
1227 _ => false,
1228 })
1229 }
1230
1231 fn is_zero_leaf(&self) -> Result<bool, ()> {
1232 Ok(match *self {
1233 Self::Leaf(ref l) => l.is_zero()?,
1234 _ => false,
1235 })
1236 }
1237
1238 fn is_infinite_leaf(&self) -> Result<bool, ()> {
1239 Ok(match *self {
1240 Self::Leaf(ref l) => l.is_infinite()?,
1241 _ => false,
1242 })
1243 }
1244
1245 fn is_nan_leaf(&self) -> Result<bool, ()> {
1246 Ok(match *self {
1247 Self::Leaf(ref l) => l.is_nan()?,
1248 _ => false,
1249 })
1250 }
1251
1252 pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
1258 self.visit_depth_first_internal(&mut f)
1259 }
1260
1261 fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
1262 match *self {
1263 Self::Clamp {
1264 ref mut min,
1265 ref mut center,
1266 ref mut max,
1267 } => {
1268 min.visit_depth_first_internal(f);
1269 center.visit_depth_first_internal(f);
1270 max.visit_depth_first_internal(f);
1271 },
1272 Self::Round {
1273 ref mut value,
1274 ref mut step,
1275 ..
1276 } => {
1277 value.visit_depth_first_internal(f);
1278 step.visit_depth_first_internal(f);
1279 },
1280 Self::ModRem {
1281 ref mut dividend,
1282 ref mut divisor,
1283 ..
1284 } => {
1285 dividend.visit_depth_first_internal(f);
1286 divisor.visit_depth_first_internal(f);
1287 },
1288 Self::Sum(ref mut children)
1289 | Self::Product(ref mut children)
1290 | Self::MinMax(ref mut children, _)
1291 | Self::Hypot(ref mut children) => {
1292 for child in &mut **children {
1293 child.visit_depth_first_internal(f);
1294 }
1295 },
1296 Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
1297 value.visit_depth_first_internal(f);
1298 },
1299 Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
1300 value.visit_depth_first_internal(f);
1301 },
1302 Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
1303 }
1304 f(self);
1305 }
1306
1307 pub fn simplify_and_sort_direct_children(&mut self) {
1318 macro_rules! replace_self_with {
1319 ($slot:expr) => {{
1320 let result = mem::replace($slot, Self::dummy());
1321 *self = result;
1322 }};
1323 }
1324
1325 macro_rules! value_or_stop {
1326 ($op:expr) => {{
1327 match $op {
1328 Ok(value) => value,
1329 Err(_) => return,
1330 }
1331 }};
1332 }
1333
1334 match *self {
1335 Self::Clamp {
1336 ref mut min,
1337 ref mut center,
1338 ref mut max,
1339 } => {
1340 let min_cmp_center = match min.compare(¢er, PositivePercentageBasis::Unknown) {
1342 Some(o) => o,
1343 None => return,
1344 };
1345
1346 if matches!(min_cmp_center, cmp::Ordering::Greater) {
1349 replace_self_with!(&mut **min);
1350 return;
1351 }
1352
1353 let max_cmp_center = match max.compare(¢er, PositivePercentageBasis::Unknown) {
1355 Some(o) => o,
1356 None => return,
1357 };
1358
1359 if matches!(max_cmp_center, cmp::Ordering::Less) {
1360 let max_cmp_min = match max.compare(&min, PositivePercentageBasis::Unknown) {
1363 Some(o) => o,
1364 None => return,
1365 };
1366
1367 if matches!(max_cmp_min, cmp::Ordering::Less) {
1368 replace_self_with!(&mut **min);
1369 return;
1370 }
1371
1372 replace_self_with!(&mut **max);
1373 return;
1374 }
1375
1376 replace_self_with!(&mut **center);
1378 },
1379 Self::Round {
1380 strategy,
1381 ref mut value,
1382 ref mut step,
1383 } => {
1384 if value_or_stop!(step.is_zero_leaf()) {
1385 value_or_stop!(value.coerce_to_value(f32::NAN));
1386 replace_self_with!(&mut **value);
1387 return;
1388 }
1389
1390 if value_or_stop!(value.is_infinite_leaf())
1391 && value_or_stop!(step.is_infinite_leaf())
1392 {
1393 value_or_stop!(value.coerce_to_value(f32::NAN));
1394 replace_self_with!(&mut **value);
1395 return;
1396 }
1397
1398 if value_or_stop!(value.is_infinite_leaf()) {
1399 replace_self_with!(&mut **value);
1400 return;
1401 }
1402
1403 if value_or_stop!(step.is_infinite_leaf()) {
1404 match strategy {
1405 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1406 value_or_stop!(value.coerce_to_value(0.0));
1407 replace_self_with!(&mut **value);
1408 return;
1409 },
1410 RoundingStrategy::Up => {
1411 if !value_or_stop!(value.is_negative_leaf())
1412 && !value_or_stop!(value.is_zero_leaf())
1413 {
1414 value_or_stop!(value.coerce_to_value(f32::INFINITY));
1415 replace_self_with!(&mut **value);
1416 return;
1417 } else if !value_or_stop!(value.is_negative_leaf())
1418 && value_or_stop!(value.is_zero_leaf())
1419 {
1420 replace_self_with!(&mut **value);
1421 return;
1422 } else {
1423 value_or_stop!(value.coerce_to_value(0.0));
1424 replace_self_with!(&mut **value);
1425 return;
1426 }
1427 },
1428 RoundingStrategy::Down => {
1429 if value_or_stop!(value.is_negative_leaf())
1430 && !value_or_stop!(value.is_zero_leaf())
1431 {
1432 value_or_stop!(value.coerce_to_value(f32::INFINITY));
1433 replace_self_with!(&mut **value);
1434 return;
1435 } else if value_or_stop!(value.is_negative_leaf())
1436 && value_or_stop!(value.is_zero_leaf())
1437 {
1438 replace_self_with!(&mut **value);
1439 return;
1440 } else {
1441 value_or_stop!(value.coerce_to_value(0.0));
1442 replace_self_with!(&mut **value);
1443 return;
1444 }
1445 },
1446 }
1447 }
1448
1449 if value_or_stop!(step.is_negative_leaf()) {
1450 step.negate();
1451 }
1452
1453 let remainder = value_or_stop!(value.try_op(step, Rem::rem));
1454 if value_or_stop!(remainder.is_zero_leaf()) {
1455 replace_self_with!(&mut **value);
1456 return;
1457 }
1458
1459 let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
1460 {
1461 let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1462 let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub));
1463
1464 (lower_bound, upper_bound)
1465 } else {
1466 let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1467 let upper_bound = value_or_stop!(lower_bound.try_op(&step, Add::add));
1468
1469 (lower_bound, upper_bound)
1470 };
1471
1472 match strategy {
1473 RoundingStrategy::Nearest => {
1474 let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
1475 let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
1476 if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1478 replace_self_with!(&mut lower_bound);
1479 } else {
1480 replace_self_with!(&mut upper_bound);
1481 }
1482 },
1483 RoundingStrategy::Up => {
1484 replace_self_with!(&mut upper_bound);
1485 },
1486 RoundingStrategy::Down => {
1487 replace_self_with!(&mut lower_bound);
1488 },
1489 RoundingStrategy::ToZero => {
1490 let mut lower_diff = lower_bound.clone();
1491 let mut upper_diff = upper_bound.clone();
1492
1493 if value_or_stop!(lower_diff.is_negative_leaf()) {
1494 lower_diff.negate();
1495 }
1496
1497 if value_or_stop!(upper_diff.is_negative_leaf()) {
1498 upper_diff.negate();
1499 }
1500
1501 if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1503 replace_self_with!(&mut lower_bound);
1504 } else {
1505 replace_self_with!(&mut upper_bound);
1506 }
1507 },
1508 };
1509 },
1510 Self::ModRem {
1511 ref dividend,
1512 ref divisor,
1513 op,
1514 } => {
1515 let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
1516 replace_self_with!(&mut result);
1517 },
1518 Self::MinMax(ref mut children, op) => {
1519 let winning_order = match op {
1520 MinMaxOp::Min => cmp::Ordering::Less,
1521 MinMaxOp::Max => cmp::Ordering::Greater,
1522 };
1523
1524 if value_or_stop!(children[0].is_nan_leaf()) {
1525 replace_self_with!(&mut children[0]);
1526 return;
1527 }
1528
1529 let mut result = 0;
1530 for i in 1..children.len() {
1531 if value_or_stop!(children[i].is_nan_leaf()) {
1532 replace_self_with!(&mut children[i]);
1533 return;
1534 }
1535 let o = match children[i]
1536 .compare(&children[result], PositivePercentageBasis::Unknown)
1537 {
1538 None => return,
1545 Some(o) => o,
1546 };
1547
1548 if o == winning_order {
1549 result = i;
1550 }
1551 }
1552
1553 replace_self_with!(&mut children[result]);
1554 },
1555 Self::Sum(ref mut children_slot) => {
1556 let mut sums_to_merge = SmallVec::<[_; 3]>::new();
1557 let mut extra_kids = 0;
1558 for (i, child) in children_slot.iter().enumerate() {
1559 if let Self::Sum(ref children) = *child {
1560 extra_kids += children.len();
1561 sums_to_merge.push(i);
1562 }
1563 }
1564
1565 if children_slot.len() == 1 {
1569 replace_self_with!(&mut children_slot[0]);
1570 return;
1571 }
1572
1573 let mut children = mem::take(children_slot).into_vec();
1574
1575 if !sums_to_merge.is_empty() {
1576 children.reserve(extra_kids - sums_to_merge.len());
1577 for i in sums_to_merge.drain(..).rev() {
1580 let kid_children = match children.swap_remove(i) {
1581 Self::Sum(c) => c,
1582 _ => unreachable!(),
1583 };
1584
1585 children.extend(kid_children.into_vec());
1588 }
1589 }
1590
1591 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1592
1593 children.sort_unstable_by_key(|c| c.sort_key());
1595
1596 children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1599
1600 if children.len() == 1 {
1601 replace_self_with!(&mut children[0]);
1603 } else {
1604 *children_slot = children.into_boxed_slice().into();
1606 }
1607 },
1608 Self::Product(ref mut children_slot) => {
1609 let mut products_to_merge = SmallVec::<[_; 3]>::new();
1610 let mut extra_kids = 0;
1611 for (i, child) in children_slot.iter().enumerate() {
1612 if let Self::Product(ref children) = *child {
1613 extra_kids += children.len();
1614 products_to_merge.push(i);
1615 }
1616 }
1617
1618 if children_slot.len() == 1 {
1622 replace_self_with!(&mut children_slot[0]);
1623 return;
1624 }
1625
1626 let mut children = mem::take(children_slot).into_vec();
1627
1628 if !products_to_merge.is_empty() {
1629 children.reserve(extra_kids - products_to_merge.len());
1630 for i in products_to_merge.drain(..).rev() {
1633 let kid_children = match children.swap_remove(i) {
1634 Self::Product(c) => c,
1635 _ => unreachable!(),
1636 };
1637
1638 children.extend(kid_children.into_vec());
1641 }
1642 }
1643
1644 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1645
1646 children.sort_unstable_by_key(|c| c.sort_key());
1648
1649 children.dedup_by(|right, left| left.try_product_in_place(right));
1652
1653 if children.len() == 1 {
1654 replace_self_with!(&mut children[0]);
1656 } else {
1657 *children_slot = children.into_boxed_slice().into();
1659 }
1660 },
1661 Self::Hypot(ref children) => {
1662 let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
1663
1664 for child in children.iter().skip(1) {
1665 let square = value_or_stop!(child.try_op(&child, Mul::mul));
1666 result = value_or_stop!(result.try_op(&square, Add::add));
1667 }
1668
1669 result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
1670
1671 replace_self_with!(&mut result);
1672 },
1673 Self::Abs(ref mut child) => {
1674 if let CalcNode::Leaf(leaf) = child.as_mut() {
1675 value_or_stop!(leaf.map(|v| v.abs()));
1676 replace_self_with!(&mut **child);
1677 }
1678 },
1679 Self::Sign(ref mut child) => {
1680 if let CalcNode::Leaf(leaf) = child.as_mut() {
1681 let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
1682 replace_self_with!(&mut result);
1683 }
1684 },
1685 Self::Negate(ref mut child) => {
1686 match &mut **child {
1688 CalcNode::Leaf(_) => {
1689 child.negate();
1692 replace_self_with!(&mut **child);
1693 },
1694 CalcNode::Negate(value) => {
1695 replace_self_with!(&mut **value);
1697 },
1698 _ => {
1699 },
1701 }
1702 },
1703 Self::Invert(ref mut child) => {
1704 match &mut **child {
1706 CalcNode::Leaf(leaf) => {
1707 if leaf.unit().is_empty() {
1710 value_or_stop!(child.map(|v| 1.0 / v));
1711 replace_self_with!(&mut **child);
1712 }
1713 },
1714 CalcNode::Invert(value) => {
1715 replace_self_with!(&mut **value);
1717 },
1718 _ => {
1719 },
1721 }
1722 },
1723 Self::Leaf(ref mut l) => {
1724 l.simplify();
1725 },
1726 Self::Anchor(ref mut f) => {
1727 if let GenericAnchorSide::Percentage(ref mut n) = f.side {
1728 n.simplify_and_sort();
1729 }
1730 if let Some(fallback) = f.fallback.as_mut() {
1731 fallback.simplify_and_sort();
1732 }
1733 },
1734 Self::AnchorSize(ref mut f) => {
1735 if let Some(fallback) = f.fallback.as_mut() {
1736 fallback.simplify_and_sort();
1737 }
1738 },
1739 }
1740 }
1741
1742 pub fn simplify_and_sort(&mut self) {
1744 self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
1745 }
1746
1747 fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
1748 where
1749 W: Write,
1750 {
1751 let write_closing_paren = match *self {
1752 Self::MinMax(_, op) => {
1753 dest.write_str(match op {
1754 MinMaxOp::Max => "max(",
1755 MinMaxOp::Min => "min(",
1756 })?;
1757 true
1758 },
1759 Self::Clamp { .. } => {
1760 dest.write_str("clamp(")?;
1761 true
1762 },
1763 Self::Round { strategy, .. } => {
1764 match strategy {
1765 RoundingStrategy::Nearest => dest.write_str("round("),
1766 RoundingStrategy::Up => dest.write_str("round(up, "),
1767 RoundingStrategy::Down => dest.write_str("round(down, "),
1768 RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
1769 }?;
1770
1771 true
1772 },
1773 Self::ModRem { op, .. } => {
1774 dest.write_str(match op {
1775 ModRemOp::Mod => "mod(",
1776 ModRemOp::Rem => "rem(",
1777 })?;
1778
1779 true
1780 },
1781 Self::Hypot(_) => {
1782 dest.write_str("hypot(")?;
1783 true
1784 },
1785 Self::Abs(_) => {
1786 dest.write_str("abs(")?;
1787 true
1788 },
1789 Self::Sign(_) => {
1790 dest.write_str("sign(")?;
1791 true
1792 },
1793 Self::Negate(_) => {
1794 debug_assert!(
1798 false,
1799 "We never serialize Negate nodes as they are handled inside Sum nodes."
1800 );
1801 dest.write_str("(-1 * ")?;
1802 true
1803 },
1804 Self::Invert(_) => {
1805 if matches!(level, ArgumentLevel::CalculationRoot) {
1806 dest.write_str("calc")?;
1807 }
1808 dest.write_str("(1 / ")?;
1809 true
1810 },
1811 Self::Sum(_) | Self::Product(_) => match level {
1812 ArgumentLevel::CalculationRoot => {
1813 dest.write_str("calc(")?;
1814 true
1815 },
1816 ArgumentLevel::ArgumentRoot => false,
1817 ArgumentLevel::Nested => {
1818 dest.write_str("(")?;
1819 true
1820 },
1821 },
1822 Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => match level {
1823 ArgumentLevel::CalculationRoot => {
1824 dest.write_str("calc(")?;
1825 true
1826 },
1827 ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
1828 },
1829 };
1830
1831 match *self {
1832 Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
1833 let mut first = true;
1834 for child in &**children {
1835 if !first {
1836 dest.write_str(", ")?;
1837 }
1838 first = false;
1839 child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1840 }
1841 },
1842 Self::Negate(ref value) | Self::Invert(ref value) => {
1843 value.to_css_impl(dest, ArgumentLevel::Nested)?
1844 },
1845 Self::Sum(ref children) => {
1846 let mut first = true;
1847 for child in &**children {
1848 if !first {
1849 match child {
1850 Self::Leaf(l) => {
1851 if let Ok(true) = l.is_negative() {
1852 dest.write_str(" - ")?;
1853 let mut negated = l.clone();
1854 negated.map(std::ops::Neg::neg).unwrap();
1857 negated.to_css(dest)?;
1858 } else {
1859 dest.write_str(" + ")?;
1860 l.to_css(dest)?;
1861 }
1862 },
1863 Self::Negate(n) => {
1864 dest.write_str(" - ")?;
1865 n.to_css_impl(dest, ArgumentLevel::Nested)?;
1866 },
1867 _ => {
1868 dest.write_str(" + ")?;
1869 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1870 },
1871 }
1872 } else {
1873 first = false;
1874 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1875 }
1876 }
1877 },
1878 Self::Product(ref children) => {
1879 let mut first = true;
1880 for child in &**children {
1881 if !first {
1882 match child {
1883 Self::Invert(n) => {
1884 dest.write_str(" / ")?;
1885 n.to_css_impl(dest, ArgumentLevel::Nested)?;
1886 },
1887 _ => {
1888 dest.write_str(" * ")?;
1889 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1890 },
1891 }
1892 } else {
1893 first = false;
1894 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1895 }
1896 }
1897 },
1898 Self::Clamp {
1899 ref min,
1900 ref center,
1901 ref max,
1902 } => {
1903 min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1904 dest.write_str(", ")?;
1905 center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1906 dest.write_str(", ")?;
1907 max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1908 },
1909 Self::Round {
1910 ref value,
1911 ref step,
1912 ..
1913 } => {
1914 value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1915 dest.write_str(", ")?;
1916 step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1917 },
1918 Self::ModRem {
1919 ref dividend,
1920 ref divisor,
1921 ..
1922 } => {
1923 dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1924 dest.write_str(", ")?;
1925 divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1926 },
1927 Self::Abs(ref v) | Self::Sign(ref v) => {
1928 v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
1929 },
1930 Self::Leaf(ref l) => l.to_css(dest)?,
1931 Self::Anchor(ref f) => f.to_css(dest)?,
1932 Self::AnchorSize(ref f) => f.to_css(dest)?,
1933 }
1934
1935 if write_closing_paren {
1936 dest.write_char(')')?;
1937 }
1938 Ok(())
1939 }
1940
1941 fn to_typed_impl(&self, level: ArgumentLevel) -> Option<TypedValue> {
1942 match *self {
1944 Self::Sum(ref children) => {
1945 let mut values = ThinVec::new();
1946 for child in &**children {
1947 if let Some(TypedValue::Numeric(inner)) =
1948 child.to_typed_impl(ArgumentLevel::Nested)
1949 {
1950 values.push(inner);
1951 }
1952 }
1953 Some(TypedValue::Numeric(NumericValue::Sum { values }))
1954 },
1955 Self::Leaf(ref l) => match l.to_typed() {
1956 Some(TypedValue::Numeric(inner)) => match level {
1957 ArgumentLevel::CalculationRoot => {
1958 Some(TypedValue::Numeric(NumericValue::Sum {
1959 values: ThinVec::from([inner]),
1960 }))
1961 },
1962 ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => {
1963 Some(TypedValue::Numeric(inner))
1964 },
1965 },
1966 _ => None,
1967 },
1968 _ => None,
1969 }
1970 }
1971
1972 fn compare(
1973 &self,
1974 other: &Self,
1975 basis_positive: PositivePercentageBasis,
1976 ) -> Option<cmp::Ordering> {
1977 match (self, other) {
1978 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
1979 one.compare(other, basis_positive)
1980 },
1981 _ => None,
1982 }
1983 }
1984
1985 compare_helpers!();
1986}
1987
1988impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
1989 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1991 where
1992 W: Write,
1993 {
1994 self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
1995 }
1996}
1997
1998impl<L: CalcNodeLeaf> ToTyped for CalcNode<L> {
1999 fn to_typed(&self) -> Option<TypedValue> {
2000 self.to_typed_impl(ArgumentLevel::CalculationRoot)
2001 }
2002}
2003
2004#[cfg(test)]
2005mod tests {
2006 use super::*;
2007
2008 #[test]
2009 fn can_sum_with_checks() {
2010 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH));
2011 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::PERCENTAGE));
2012 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2013
2014 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2015 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2016 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2017
2018 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2019 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2020 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2021
2022 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::TIME));
2023 assert!(CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE));
2024
2025 assert!(!(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE));
2026 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME));
2027 assert!(
2028 !(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME)
2029 );
2030 }
2031}