1use crate::values::generics::length::GenericAnchorSizeFunction;
10use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide};
11use num_traits::Zero;
12use smallvec::SmallVec;
13use std::fmt::{self, Write};
14use std::ops::{Add, Mul, Neg, Rem, Sub};
15use std::{cmp, mem};
16use style_traits::{CssWriter, ToCss};
17
18#[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,
35 Max,
37}
38
39#[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,
56 Rem,
58}
59
60impl ModRemOp {
61 fn apply(self, dividend: f32, divisor: f32) -> f32 {
62 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#[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 Nearest,
102 Up,
105 Down,
108 ToZero,
111}
112
113#[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
167pub type GenericCalcAnchorFunction<L> =
169 GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericCalcNode<L>>>;
170pub type GenericCalcAnchorSizeFunction<L> = GenericAnchorSizeFunction<Box<GenericCalcNode<L>>>;
172
173#[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 Leaf(L),
199 Negate(Box<GenericCalcNode<L>>),
201 Invert(Box<GenericCalcNode<L>>),
204 Sum(crate::OwnedSlice<GenericCalcNode<L>>),
207 Product(crate::OwnedSlice<GenericCalcNode<L>>),
210 MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp),
212 Clamp {
214 min: Box<GenericCalcNode<L>>,
216 center: Box<GenericCalcNode<L>>,
218 max: Box<GenericCalcNode<L>>,
220 },
221 Round {
223 strategy: RoundingStrategy,
225 value: Box<GenericCalcNode<L>>,
227 step: Box<GenericCalcNode<L>>,
229 },
230 ModRem {
232 dividend: Box<GenericCalcNode<L>>,
234 divisor: Box<GenericCalcNode<L>>,
236 op: ModRemOp,
238 },
239 Hypot(crate::OwnedSlice<GenericCalcNode<L>>),
241 Abs(Box<GenericCalcNode<L>>),
243 Sign(Box<GenericCalcNode<L>>),
245 Anchor(Box<GenericCalcAnchorFunction<L>>),
247 AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>),
249}
250
251pub use self::GenericCalcNode as CalcNode;
252
253bitflags! {
254 #[derive(Clone, Copy, PartialEq, Eq)]
260 pub struct CalcUnits: u8 {
261 const LENGTH = 1 << 0;
263 const PERCENTAGE = 1 << 1;
265 const ANGLE = 1 << 2;
267 const TIME = 1 << 3;
269 const RESOLUTION = 1 << 4;
271 const COLOR_COMPONENT = 1 << 5;
273
274 const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits();
276 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 #[inline]
287 fn is_single_unit(&self) -> bool {
288 self.bits() == 0 || self.bits() & (self.bits() - 1) == 0
289 }
290
291 #[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
303pub enum PositivePercentageBasis {
306 Unknown,
308 Yes,
310}
311
312macro_rules! compare_helpers {
313 () => {
314 #[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 fn lt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool {
322 self.compare(other, basis_positive) == Some(cmp::Ordering::Less)
323 }
324
325 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
337pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss {
339 fn unit(&self) -> CalcUnits;
341
342 fn unitless_value(&self) -> Option<f32>;
344
345 fn is_same_unit_as(&self, other: &Self) -> bool {
348 std::mem::discriminant(self) == std::mem::discriminant(other)
349 }
350
351 fn compare(
353 &self,
354 other: &Self,
355 base_is_positive: PositivePercentageBasis,
356 ) -> Option<cmp::Ordering>;
357 compare_helpers!();
358
359 fn new_number(value: f32) -> Self;
361
362 fn as_number(&self) -> Option<f32>;
364
365 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 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 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 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 fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>;
395
396 fn try_product_in_place(&mut self, other: &mut Self) -> bool;
399
400 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
402 where
403 O: Fn(f32, f32) -> f32;
404
405 fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>;
407
408 fn simplify(&mut self);
410
411 fn sort_key(&self) -> SortKey;
413
414 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
432enum ArgumentLevel {
434 CalculationRoot,
436 ArgumentRoot,
439 Nested,
441}
442
443impl<L: CalcNodeLeaf> CalcNode<L> {
444 fn dummy() -> Self {
446 Self::MinMax(Default::default(), MinMaxOp::Max)
447 }
448
449 fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
453 self.map(|_| value)
454 }
455
456 #[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 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 let mut unit = None;
489 for child in children.iter() {
490 let child_unit = child.unit()?;
491 if child_unit.is_empty() {
492 continue;
494 }
495
496 if unit.is_some() {
497 return Err(());
499 }
500
501 unit = Some(child_unit);
503 }
504 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 let _ = child.unit()?;
557 CalcUnits::empty()
558 },
559 CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
560 })
561 }
562
563 pub fn negate(&mut self) {
566 fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
568 let result = mem::replace(s, CalcNode::dummy());
569 *s = CalcNode::Negate(Box::new(result));
570 }
571
572 match *self {
573 CalcNode::Leaf(ref mut leaf) => {
574 if leaf.map(std::ops::Neg::neg).is_err() {
575 wrap_self_in_negate(self)
576 }
577 },
578 CalcNode::Negate(ref mut value) => {
579 let result = mem::replace(value.as_mut(), Self::dummy());
581 *self = result;
582 },
583 CalcNode::Invert(_) => {
584 wrap_self_in_negate(self)
586 },
587 CalcNode::Sum(ref mut children) => {
588 for child in children.iter_mut() {
589 child.negate();
590 }
591 },
592 CalcNode::Product(_) => {
593 wrap_self_in_negate(self);
595 },
596 CalcNode::MinMax(ref mut children, ref mut op) => {
597 for child in children.iter_mut() {
598 child.negate();
599 }
600
601 *op = match *op {
603 MinMaxOp::Min => MinMaxOp::Max,
604 MinMaxOp::Max => MinMaxOp::Min,
605 };
606 },
607 CalcNode::Clamp {
608 ref mut min,
609 ref mut center,
610 ref mut max,
611 } => {
612 if min.lte(max, PositivePercentageBasis::Unknown) {
613 min.negate();
614 center.negate();
615 max.negate();
616
617 mem::swap(min, max);
618 } else {
619 wrap_self_in_negate(self);
620 }
621 },
622 CalcNode::Round {
623 ref mut strategy,
624 ref mut value,
625 ref mut step,
626 } => {
627 match *strategy {
628 RoundingStrategy::Nearest => {
629 wrap_self_in_negate(self);
634 return;
635 },
636 RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
637 RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
638 RoundingStrategy::ToZero => (),
639 }
640 value.negate();
641 step.negate();
642 },
643 CalcNode::ModRem {
644 ref mut dividend,
645 ref mut divisor,
646 ..
647 } => {
648 dividend.negate();
649 divisor.negate();
650 },
651 CalcNode::Hypot(ref mut children) => {
652 for child in children.iter_mut() {
653 child.negate();
654 }
655 },
656 CalcNode::Abs(_) => {
657 wrap_self_in_negate(self);
658 },
659 CalcNode::Sign(ref mut child) => {
660 child.negate();
661 },
662 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => {
663 wrap_self_in_negate(self);
664 },
665 }
666 }
667
668 fn sort_key(&self) -> SortKey {
669 match *self {
670 Self::Leaf(ref l) => l.sort_key(),
671 Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
672 _ => SortKey::Other,
673 }
674 }
675
676 pub fn as_leaf(&self) -> Option<&L> {
678 match *self {
679 Self::Leaf(ref l) => Some(l),
680 _ => None,
681 }
682 }
683
684 pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
686 match (self, other) {
687 (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
688 one.try_sum_in_place(other)
689 },
690 _ => Err(()),
691 }
692 }
693
694 pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
696 if let Ok(resolved) = other.resolve() {
697 if let Some(number) = resolved.as_number() {
698 if number == 1.0 {
699 return true;
700 }
701
702 if self.is_product_distributive() {
703 if self.map(|v| v * number).is_err() {
704 return false;
705 }
706 return true;
707 }
708 }
709 }
710
711 if let Ok(resolved) = self.resolve() {
712 if let Some(number) = resolved.as_number() {
713 if number == 1.0 {
714 std::mem::swap(self, other);
715 return true;
716 }
717
718 if other.is_product_distributive() {
719 if other.map(|v| v * number).is_err() {
720 return false;
721 }
722 std::mem::swap(self, other);
723 return true;
724 }
725 }
726 }
727
728 false
729 }
730
731 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
733 where
734 O: Fn(f32, f32) -> f32,
735 {
736 match (self, other) {
737 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
738 Ok(CalcNode::Leaf(one.try_op(other, op)?))
739 },
740 _ => Err(()),
741 }
742 }
743
744 pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
746 fn map_internal<L: CalcNodeLeaf>(
747 node: &mut CalcNode<L>,
748 op: &mut impl FnMut(f32) -> f32,
749 ) -> Result<(), ()> {
750 match node {
751 CalcNode::Leaf(l) => l.map(op),
752 CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
753 CalcNode::Sum(children) | CalcNode::Product(children) => {
754 for node in &mut **children {
755 map_internal(node, op)?;
756 }
757 Ok(())
758 },
759 CalcNode::MinMax(children, _) => {
760 for node in &mut **children {
761 map_internal(node, op)?;
762 }
763 Ok(())
764 },
765 CalcNode::Clamp { min, center, max } => {
766 map_internal(min, op)?;
767 map_internal(center, op)?;
768 map_internal(max, op)
769 },
770 CalcNode::Round { value, step, .. } => {
771 map_internal(value, op)?;
772 map_internal(step, op)
773 },
774 CalcNode::ModRem {
775 dividend, divisor, ..
776 } => {
777 map_internal(dividend, op)?;
778 map_internal(divisor, op)
779 },
780 CalcNode::Hypot(children) => {
781 for node in &mut **children {
782 map_internal(node, op)?;
783 }
784 Ok(())
785 },
786 CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
787 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
790 }
791 }
792
793 map_internal(self, &mut op)
794 }
795
796 pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
798 where
799 O: CalcNodeLeaf,
800 F: FnMut(&L) -> O,
801 {
802 self.map_leaves_internal(&mut map)
803 }
804
805 fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
806 where
807 O: CalcNodeLeaf,
808 F: FnMut(&L) -> O,
809 {
810 fn map_children<L, O, F>(
811 children: &[CalcNode<L>],
812 map: &mut F,
813 ) -> crate::OwnedSlice<CalcNode<O>>
814 where
815 L: CalcNodeLeaf,
816 O: CalcNodeLeaf,
817 F: FnMut(&L) -> O,
818 {
819 children
820 .iter()
821 .map(|c| c.map_leaves_internal(map))
822 .collect()
823 }
824
825 match *self {
826 Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
827 Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
828 Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
829 Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
830 Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
831 Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
832 Self::Clamp {
833 ref min,
834 ref center,
835 ref max,
836 } => {
837 let min = Box::new(min.map_leaves_internal(map));
838 let center = Box::new(center.map_leaves_internal(map));
839 let max = Box::new(max.map_leaves_internal(map));
840 CalcNode::Clamp { min, center, max }
841 },
842 Self::Round {
843 strategy,
844 ref value,
845 ref step,
846 } => {
847 let value = Box::new(value.map_leaves_internal(map));
848 let step = Box::new(step.map_leaves_internal(map));
849 CalcNode::Round {
850 strategy,
851 value,
852 step,
853 }
854 },
855 Self::ModRem {
856 ref dividend,
857 ref divisor,
858 op,
859 } => {
860 let dividend = Box::new(dividend.map_leaves_internal(map));
861 let divisor = Box::new(divisor.map_leaves_internal(map));
862 CalcNode::ModRem {
863 dividend,
864 divisor,
865 op,
866 }
867 },
868 Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
869 Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
870 Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
871 Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
872 target_element: f.target_element.clone(),
873 side: match &f.side {
874 GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
875 GenericAnchorSide::Percentage(p) => {
876 GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
877 },
878 },
879 fallback: f
880 .fallback
881 .as_ref()
882 .map(|fb| Box::new(fb.map_leaves_internal(map)))
883 .into(),
884 })),
885 Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
886 target_element: f.target_element.clone(),
887 size: f.size,
888 fallback: f
889 .fallback
890 .as_ref()
891 .map(|fb| Box::new(fb.map_leaves_internal(map)))
892 .into(),
893 })),
894 }
895 }
896
897 pub fn resolve(&self) -> Result<L, ()> {
899 self.resolve_map(|l| Ok(l.clone()))
900 }
901
902 pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
904 where
905 F: FnMut(&L) -> Result<L, ()>,
906 {
907 self.resolve_internal(&mut leaf_to_output_fn)
908 }
909
910 fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<L, ()>
911 where
912 F: FnMut(&L) -> Result<L, ()>,
913 {
914 match self {
915 Self::Leaf(l) => leaf_to_output_fn(l),
916 Self::Negate(child) => {
917 let mut result = child.resolve_internal(leaf_to_output_fn)?;
918 result.map(|v| v.neg())?;
919 Ok(result)
920 },
921 Self::Invert(child) => {
922 let mut result = child.resolve_internal(leaf_to_output_fn)?;
923 result.map(|v| 1.0 / v)?;
924 Ok(result)
925 },
926 Self::Sum(children) => {
927 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
928
929 for child in children.iter().skip(1) {
930 let right = child.resolve_internal(leaf_to_output_fn)?;
931 result = result.try_op(&right, |left, right| left + right)?;
933 }
934
935 Ok(result)
936 },
937 Self::Product(children) => {
938 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
939
940 for child in children.iter().skip(1) {
941 let right = child.resolve_internal(leaf_to_output_fn)?;
942 match result.as_number() {
944 Some(left) => {
945 result = right;
947 result.map(|v| v * left)?;
948 },
949 None => {
950 match right.as_number() {
952 Some(right) => {
953 result.map(|v| v * right)?;
954 },
955 None => {
956 return Err(());
958 },
959 }
960 },
961 }
962 }
963
964 Ok(result)
965 },
966 Self::MinMax(children, op) => {
967 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
968
969 if result.is_nan()? {
970 return Ok(result);
971 }
972
973 for child in children.iter().skip(1) {
974 let candidate = child.resolve_internal(leaf_to_output_fn)?;
975
976 if !result.is_same_unit_as(&candidate) {
978 return Err(());
979 }
980
981 if candidate.is_nan()? {
982 result = candidate;
983 break;
984 }
985
986 let candidate_wins = match op {
987 MinMaxOp::Min => candidate.lt(&result, PositivePercentageBasis::Yes),
988 MinMaxOp::Max => candidate.gt(&result, PositivePercentageBasis::Yes),
989 };
990
991 if candidate_wins {
992 result = candidate;
993 }
994 }
995
996 Ok(result)
997 },
998 Self::Clamp { min, center, max } => {
999 let min = min.resolve_internal(leaf_to_output_fn)?;
1000 let center = center.resolve_internal(leaf_to_output_fn)?;
1001 let max = max.resolve_internal(leaf_to_output_fn)?;
1002
1003 if !min.is_same_unit_as(¢er) || !max.is_same_unit_as(¢er) {
1004 return Err(());
1005 }
1006
1007 if min.is_nan()? {
1008 return Ok(min);
1009 }
1010
1011 if center.is_nan()? {
1012 return Ok(center);
1013 }
1014
1015 if max.is_nan()? {
1016 return Ok(max);
1017 }
1018
1019 let mut result = center;
1020 if result.gt(&max, PositivePercentageBasis::Yes) {
1021 result = max;
1022 }
1023 if result.lt(&min, PositivePercentageBasis::Yes) {
1024 result = min
1025 }
1026
1027 Ok(result)
1028 },
1029 Self::Round {
1030 strategy,
1031 value,
1032 step,
1033 } => {
1034 let mut value = value.resolve_internal(leaf_to_output_fn)?;
1035 let step = step.resolve_internal(leaf_to_output_fn)?;
1036
1037 if !value.is_same_unit_as(&step) {
1038 return Err(());
1039 }
1040
1041 let Some(step) = step.unitless_value() else {
1042 return Err(());
1043 };
1044 let step = step.abs();
1045
1046 value.map(|value| {
1047 if step.is_zero() {
1051 return f32::NAN;
1052 }
1053
1054 if value.is_infinite() {
1055 if step.is_infinite() {
1056 return f32::NAN;
1057 }
1058 return value;
1059 }
1060
1061 if step.is_infinite() {
1062 match strategy {
1063 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1064 return if value.is_sign_negative() { -0.0 } else { 0.0 }
1065 },
1066 RoundingStrategy::Up => {
1067 return if !value.is_sign_negative() && !value.is_zero() {
1068 f32::INFINITY
1069 } else if !value.is_sign_negative() && value.is_zero() {
1070 value
1071 } else {
1072 -0.0
1073 }
1074 },
1075 RoundingStrategy::Down => {
1076 return if value.is_sign_negative() && !value.is_zero() {
1077 -f32::INFINITY
1078 } else if value.is_sign_negative() && value.is_zero() {
1079 value
1080 } else {
1081 0.0
1082 }
1083 },
1084 }
1085 }
1086
1087 let div = value / step;
1088 let lower_bound = div.floor() * step;
1089 let upper_bound = div.ceil() * step;
1090
1091 match strategy {
1092 RoundingStrategy::Nearest => {
1093 if value - lower_bound < upper_bound - value {
1095 lower_bound
1096 } else {
1097 upper_bound
1098 }
1099 },
1100 RoundingStrategy::Up => upper_bound,
1101 RoundingStrategy::Down => lower_bound,
1102 RoundingStrategy::ToZero => {
1103 if lower_bound.abs() < upper_bound.abs() {
1105 lower_bound
1106 } else {
1107 upper_bound
1108 }
1109 },
1110 }
1111 })?;
1112
1113 Ok(value)
1114 },
1115 Self::ModRem {
1116 dividend,
1117 divisor,
1118 op,
1119 } => {
1120 let mut dividend = dividend.resolve_internal(leaf_to_output_fn)?;
1121 let divisor = divisor.resolve_internal(leaf_to_output_fn)?;
1122
1123 if !dividend.is_same_unit_as(&divisor) {
1124 return Err(());
1125 }
1126
1127 let Some(divisor) = divisor.unitless_value() else {
1128 return Err(());
1129 };
1130 dividend.map(|dividend| op.apply(dividend, divisor))?;
1131 Ok(dividend)
1132 },
1133 Self::Hypot(children) => {
1134 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1135 result.map(|v| v.powi(2))?;
1136
1137 for child in children.iter().skip(1) {
1138 let child_value = child.resolve_internal(leaf_to_output_fn)?;
1139
1140 if !result.is_same_unit_as(&child_value) {
1141 return Err(());
1142 }
1143
1144 let Some(child_value) = child_value.unitless_value() else {
1145 return Err(());
1146 };
1147 result.map(|v| v + child_value.powi(2))?;
1148 }
1149
1150 result.map(|v| v.sqrt())?;
1151 Ok(result)
1152 },
1153 Self::Abs(ref c) => {
1154 let mut result = c.resolve_internal(leaf_to_output_fn)?;
1155
1156 result.map(|v| v.abs())?;
1157
1158 Ok(result)
1159 },
1160 Self::Sign(ref c) => {
1161 let result = c.resolve_internal(leaf_to_output_fn)?;
1162 Ok(L::sign_from(&result)?)
1163 },
1164 Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
1165 }
1166 }
1167
1168 pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
1170 where
1171 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1172 {
1173 self.map_node_internal(&mut mapping_fn)
1174 }
1175
1176 fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
1177 where
1178 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1179 {
1180 if let Some(node) = mapping_fn(self)? {
1181 *self = node;
1182 return Ok(());
1184 }
1185 match self {
1186 Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
1187 Self::Negate(child) | Self::Invert(child) | Self::Abs(child) | Self::Sign(child) => {
1188 child.map_node_internal(mapping_fn)?;
1189 },
1190 Self::Sum(children)
1191 | Self::Product(children)
1192 | Self::Hypot(children)
1193 | Self::MinMax(children, _) => {
1194 for child in children.iter_mut() {
1195 child.map_node_internal(mapping_fn)?;
1196 }
1197 },
1198 Self::Clamp { min, center, max } => {
1199 min.map_node_internal(mapping_fn)?;
1200 center.map_node_internal(mapping_fn)?;
1201 max.map_node_internal(mapping_fn)?;
1202 },
1203 Self::Round { value, step, .. } => {
1204 value.map_node_internal(mapping_fn)?;
1205 step.map_node_internal(mapping_fn)?;
1206 },
1207 Self::ModRem {
1208 dividend, divisor, ..
1209 } => {
1210 dividend.map_node_internal(mapping_fn)?;
1211 divisor.map_node_internal(mapping_fn)?;
1212 },
1213 };
1214 Ok(())
1215 }
1216
1217 fn is_negative_leaf(&self) -> Result<bool, ()> {
1218 Ok(match *self {
1219 Self::Leaf(ref l) => l.is_negative()?,
1220 _ => false,
1221 })
1222 }
1223
1224 fn is_zero_leaf(&self) -> Result<bool, ()> {
1225 Ok(match *self {
1226 Self::Leaf(ref l) => l.is_zero()?,
1227 _ => false,
1228 })
1229 }
1230
1231 fn is_infinite_leaf(&self) -> Result<bool, ()> {
1232 Ok(match *self {
1233 Self::Leaf(ref l) => l.is_infinite()?,
1234 _ => false,
1235 })
1236 }
1237
1238 fn is_nan_leaf(&self) -> Result<bool, ()> {
1239 Ok(match *self {
1240 Self::Leaf(ref l) => l.is_nan()?,
1241 _ => false,
1242 })
1243 }
1244
1245 pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
1251 self.visit_depth_first_internal(&mut f)
1252 }
1253
1254 fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
1255 match *self {
1256 Self::Clamp {
1257 ref mut min,
1258 ref mut center,
1259 ref mut max,
1260 } => {
1261 min.visit_depth_first_internal(f);
1262 center.visit_depth_first_internal(f);
1263 max.visit_depth_first_internal(f);
1264 },
1265 Self::Round {
1266 ref mut value,
1267 ref mut step,
1268 ..
1269 } => {
1270 value.visit_depth_first_internal(f);
1271 step.visit_depth_first_internal(f);
1272 },
1273 Self::ModRem {
1274 ref mut dividend,
1275 ref mut divisor,
1276 ..
1277 } => {
1278 dividend.visit_depth_first_internal(f);
1279 divisor.visit_depth_first_internal(f);
1280 },
1281 Self::Sum(ref mut children)
1282 | Self::Product(ref mut children)
1283 | Self::MinMax(ref mut children, _)
1284 | Self::Hypot(ref mut children) => {
1285 for child in &mut **children {
1286 child.visit_depth_first_internal(f);
1287 }
1288 },
1289 Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
1290 value.visit_depth_first_internal(f);
1291 },
1292 Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
1293 value.visit_depth_first_internal(f);
1294 },
1295 Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
1296 }
1297 f(self);
1298 }
1299
1300 pub fn simplify_and_sort_direct_children(&mut self) {
1311 macro_rules! replace_self_with {
1312 ($slot:expr) => {{
1313 let result = mem::replace($slot, Self::dummy());
1314 *self = result;
1315 }};
1316 }
1317
1318 macro_rules! value_or_stop {
1319 ($op:expr) => {{
1320 match $op {
1321 Ok(value) => value,
1322 Err(_) => return,
1323 }
1324 }};
1325 }
1326
1327 match *self {
1328 Self::Clamp {
1329 ref mut min,
1330 ref mut center,
1331 ref mut max,
1332 } => {
1333 let min_cmp_center = match min.compare(¢er, PositivePercentageBasis::Unknown) {
1335 Some(o) => o,
1336 None => return,
1337 };
1338
1339 if matches!(min_cmp_center, cmp::Ordering::Greater) {
1342 replace_self_with!(&mut **min);
1343 return;
1344 }
1345
1346 let max_cmp_center = match max.compare(¢er, PositivePercentageBasis::Unknown) {
1348 Some(o) => o,
1349 None => return,
1350 };
1351
1352 if matches!(max_cmp_center, cmp::Ordering::Less) {
1353 let max_cmp_min = match max.compare(&min, PositivePercentageBasis::Unknown) {
1356 Some(o) => o,
1357 None => return,
1358 };
1359
1360 if matches!(max_cmp_min, cmp::Ordering::Less) {
1361 replace_self_with!(&mut **min);
1362 return;
1363 }
1364
1365 replace_self_with!(&mut **max);
1366 return;
1367 }
1368
1369 replace_self_with!(&mut **center);
1371 },
1372 Self::Round {
1373 strategy,
1374 ref mut value,
1375 ref mut step,
1376 } => {
1377 if value_or_stop!(step.is_zero_leaf()) {
1378 value_or_stop!(value.coerce_to_value(f32::NAN));
1379 replace_self_with!(&mut **value);
1380 return;
1381 }
1382
1383 if value_or_stop!(value.is_infinite_leaf())
1384 && value_or_stop!(step.is_infinite_leaf())
1385 {
1386 value_or_stop!(value.coerce_to_value(f32::NAN));
1387 replace_self_with!(&mut **value);
1388 return;
1389 }
1390
1391 if value_or_stop!(value.is_infinite_leaf()) {
1392 replace_self_with!(&mut **value);
1393 return;
1394 }
1395
1396 if value_or_stop!(step.is_infinite_leaf()) {
1397 match strategy {
1398 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1399 value_or_stop!(value.coerce_to_value(0.0));
1400 replace_self_with!(&mut **value);
1401 return;
1402 },
1403 RoundingStrategy::Up => {
1404 if !value_or_stop!(value.is_negative_leaf())
1405 && !value_or_stop!(value.is_zero_leaf())
1406 {
1407 value_or_stop!(value.coerce_to_value(f32::INFINITY));
1408 replace_self_with!(&mut **value);
1409 return;
1410 } else if !value_or_stop!(value.is_negative_leaf())
1411 && value_or_stop!(value.is_zero_leaf())
1412 {
1413 replace_self_with!(&mut **value);
1414 return;
1415 } else {
1416 value_or_stop!(value.coerce_to_value(0.0));
1417 replace_self_with!(&mut **value);
1418 return;
1419 }
1420 },
1421 RoundingStrategy::Down => {
1422 if value_or_stop!(value.is_negative_leaf())
1423 && !value_or_stop!(value.is_zero_leaf())
1424 {
1425 value_or_stop!(value.coerce_to_value(f32::INFINITY));
1426 replace_self_with!(&mut **value);
1427 return;
1428 } else if value_or_stop!(value.is_negative_leaf())
1429 && value_or_stop!(value.is_zero_leaf())
1430 {
1431 replace_self_with!(&mut **value);
1432 return;
1433 } else {
1434 value_or_stop!(value.coerce_to_value(0.0));
1435 replace_self_with!(&mut **value);
1436 return;
1437 }
1438 },
1439 }
1440 }
1441
1442 if value_or_stop!(step.is_negative_leaf()) {
1443 step.negate();
1444 }
1445
1446 let remainder = value_or_stop!(value.try_op(step, Rem::rem));
1447 if value_or_stop!(remainder.is_zero_leaf()) {
1448 replace_self_with!(&mut **value);
1449 return;
1450 }
1451
1452 let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
1453 {
1454 let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1455 let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub));
1456
1457 (lower_bound, upper_bound)
1458 } else {
1459 let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1460 let upper_bound = value_or_stop!(lower_bound.try_op(&step, Add::add));
1461
1462 (lower_bound, upper_bound)
1463 };
1464
1465 match strategy {
1466 RoundingStrategy::Nearest => {
1467 let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
1468 let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
1469 if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1471 replace_self_with!(&mut lower_bound);
1472 } else {
1473 replace_self_with!(&mut upper_bound);
1474 }
1475 },
1476 RoundingStrategy::Up => {
1477 replace_self_with!(&mut upper_bound);
1478 },
1479 RoundingStrategy::Down => {
1480 replace_self_with!(&mut lower_bound);
1481 },
1482 RoundingStrategy::ToZero => {
1483 let mut lower_diff = lower_bound.clone();
1484 let mut upper_diff = upper_bound.clone();
1485
1486 if value_or_stop!(lower_diff.is_negative_leaf()) {
1487 lower_diff.negate();
1488 }
1489
1490 if value_or_stop!(upper_diff.is_negative_leaf()) {
1491 upper_diff.negate();
1492 }
1493
1494 if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1496 replace_self_with!(&mut lower_bound);
1497 } else {
1498 replace_self_with!(&mut upper_bound);
1499 }
1500 },
1501 };
1502 },
1503 Self::ModRem {
1504 ref dividend,
1505 ref divisor,
1506 op,
1507 } => {
1508 let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
1509 replace_self_with!(&mut result);
1510 },
1511 Self::MinMax(ref mut children, op) => {
1512 let winning_order = match op {
1513 MinMaxOp::Min => cmp::Ordering::Less,
1514 MinMaxOp::Max => cmp::Ordering::Greater,
1515 };
1516
1517 if value_or_stop!(children[0].is_nan_leaf()) {
1518 replace_self_with!(&mut children[0]);
1519 return;
1520 }
1521
1522 let mut result = 0;
1523 for i in 1..children.len() {
1524 if value_or_stop!(children[i].is_nan_leaf()) {
1525 replace_self_with!(&mut children[i]);
1526 return;
1527 }
1528 let o = match children[i]
1529 .compare(&children[result], PositivePercentageBasis::Unknown)
1530 {
1531 None => return,
1538 Some(o) => o,
1539 };
1540
1541 if o == winning_order {
1542 result = i;
1543 }
1544 }
1545
1546 replace_self_with!(&mut children[result]);
1547 },
1548 Self::Sum(ref mut children_slot) => {
1549 let mut sums_to_merge = SmallVec::<[_; 3]>::new();
1550 let mut extra_kids = 0;
1551 for (i, child) in children_slot.iter().enumerate() {
1552 if let Self::Sum(ref children) = *child {
1553 extra_kids += children.len();
1554 sums_to_merge.push(i);
1555 }
1556 }
1557
1558 if children_slot.len() == 1 {
1562 replace_self_with!(&mut children_slot[0]);
1563 return;
1564 }
1565
1566 let mut children = mem::take(children_slot).into_vec();
1567
1568 if !sums_to_merge.is_empty() {
1569 children.reserve(extra_kids - sums_to_merge.len());
1570 for i in sums_to_merge.drain(..).rev() {
1573 let kid_children = match children.swap_remove(i) {
1574 Self::Sum(c) => c,
1575 _ => unreachable!(),
1576 };
1577
1578 children.extend(kid_children.into_vec());
1581 }
1582 }
1583
1584 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1585
1586 children.sort_unstable_by_key(|c| c.sort_key());
1588
1589 children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1592
1593 if children.len() == 1 {
1594 replace_self_with!(&mut children[0]);
1596 } else {
1597 *children_slot = children.into_boxed_slice().into();
1599 }
1600 },
1601 Self::Product(ref mut children_slot) => {
1602 let mut products_to_merge = SmallVec::<[_; 3]>::new();
1603 let mut extra_kids = 0;
1604 for (i, child) in children_slot.iter().enumerate() {
1605 if let Self::Product(ref children) = *child {
1606 extra_kids += children.len();
1607 products_to_merge.push(i);
1608 }
1609 }
1610
1611 if children_slot.len() == 1 {
1615 replace_self_with!(&mut children_slot[0]);
1616 return;
1617 }
1618
1619 let mut children = mem::take(children_slot).into_vec();
1620
1621 if !products_to_merge.is_empty() {
1622 children.reserve(extra_kids - products_to_merge.len());
1623 for i in products_to_merge.drain(..).rev() {
1626 let kid_children = match children.swap_remove(i) {
1627 Self::Product(c) => c,
1628 _ => unreachable!(),
1629 };
1630
1631 children.extend(kid_children.into_vec());
1634 }
1635 }
1636
1637 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1638
1639 children.sort_unstable_by_key(|c| c.sort_key());
1641
1642 children.dedup_by(|right, left| left.try_product_in_place(right));
1645
1646 if children.len() == 1 {
1647 replace_self_with!(&mut children[0]);
1649 } else {
1650 *children_slot = children.into_boxed_slice().into();
1652 }
1653 },
1654 Self::Hypot(ref children) => {
1655 let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
1656
1657 for child in children.iter().skip(1) {
1658 let square = value_or_stop!(child.try_op(&child, Mul::mul));
1659 result = value_or_stop!(result.try_op(&square, Add::add));
1660 }
1661
1662 result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
1663
1664 replace_self_with!(&mut result);
1665 },
1666 Self::Abs(ref mut child) => {
1667 if let CalcNode::Leaf(leaf) = child.as_mut() {
1668 value_or_stop!(leaf.map(|v| v.abs()));
1669 replace_self_with!(&mut **child);
1670 }
1671 },
1672 Self::Sign(ref mut child) => {
1673 if let CalcNode::Leaf(leaf) = child.as_mut() {
1674 let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
1675 replace_self_with!(&mut result);
1676 }
1677 },
1678 Self::Negate(ref mut child) => {
1679 match &mut **child {
1681 CalcNode::Leaf(_) => {
1682 child.negate();
1685 replace_self_with!(&mut **child);
1686 },
1687 CalcNode::Negate(value) => {
1688 replace_self_with!(&mut **value);
1690 },
1691 _ => {
1692 },
1694 }
1695 },
1696 Self::Invert(ref mut child) => {
1697 match &mut **child {
1699 CalcNode::Leaf(leaf) => {
1700 if leaf.unit().is_empty() {
1703 value_or_stop!(child.map(|v| 1.0 / v));
1704 replace_self_with!(&mut **child);
1705 }
1706 },
1707 CalcNode::Invert(value) => {
1708 replace_self_with!(&mut **value);
1710 },
1711 _ => {
1712 },
1714 }
1715 },
1716 Self::Leaf(ref mut l) => {
1717 l.simplify();
1718 },
1719 Self::Anchor(ref mut f) => {
1720 if let GenericAnchorSide::Percentage(ref mut n) = f.side {
1721 n.simplify_and_sort();
1722 }
1723 if let Some(fallback) = f.fallback.as_mut() {
1724 fallback.simplify_and_sort();
1725 }
1726 },
1727 Self::AnchorSize(ref mut f) => {
1728 if let Some(fallback) = f.fallback.as_mut() {
1729 fallback.simplify_and_sort();
1730 }
1731 },
1732 }
1733 }
1734
1735 pub fn simplify_and_sort(&mut self) {
1737 self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
1738 }
1739
1740 fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
1741 where
1742 W: Write,
1743 {
1744 let write_closing_paren = match *self {
1745 Self::MinMax(_, op) => {
1746 dest.write_str(match op {
1747 MinMaxOp::Max => "max(",
1748 MinMaxOp::Min => "min(",
1749 })?;
1750 true
1751 },
1752 Self::Clamp { .. } => {
1753 dest.write_str("clamp(")?;
1754 true
1755 },
1756 Self::Round { strategy, .. } => {
1757 match strategy {
1758 RoundingStrategy::Nearest => dest.write_str("round("),
1759 RoundingStrategy::Up => dest.write_str("round(up, "),
1760 RoundingStrategy::Down => dest.write_str("round(down, "),
1761 RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
1762 }?;
1763
1764 true
1765 },
1766 Self::ModRem { op, .. } => {
1767 dest.write_str(match op {
1768 ModRemOp::Mod => "mod(",
1769 ModRemOp::Rem => "rem(",
1770 })?;
1771
1772 true
1773 },
1774 Self::Hypot(_) => {
1775 dest.write_str("hypot(")?;
1776 true
1777 },
1778 Self::Abs(_) => {
1779 dest.write_str("abs(")?;
1780 true
1781 },
1782 Self::Sign(_) => {
1783 dest.write_str("sign(")?;
1784 true
1785 },
1786 Self::Negate(_) => {
1787 debug_assert!(
1791 false,
1792 "We never serialize Negate nodes as they are handled inside Sum nodes."
1793 );
1794 dest.write_str("(-1 * ")?;
1795 true
1796 },
1797 Self::Invert(_) => {
1798 if matches!(level, ArgumentLevel::CalculationRoot) {
1799 dest.write_str("calc")?;
1800 }
1801 dest.write_str("(1 / ")?;
1802 true
1803 },
1804 Self::Sum(_) | Self::Product(_) => match level {
1805 ArgumentLevel::CalculationRoot => {
1806 dest.write_str("calc(")?;
1807 true
1808 },
1809 ArgumentLevel::ArgumentRoot => false,
1810 ArgumentLevel::Nested => {
1811 dest.write_str("(")?;
1812 true
1813 },
1814 },
1815 Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => match level {
1816 ArgumentLevel::CalculationRoot => {
1817 dest.write_str("calc(")?;
1818 true
1819 },
1820 ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
1821 },
1822 };
1823
1824 match *self {
1825 Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
1826 let mut first = true;
1827 for child in &**children {
1828 if !first {
1829 dest.write_str(", ")?;
1830 }
1831 first = false;
1832 child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1833 }
1834 },
1835 Self::Negate(ref value) | Self::Invert(ref value) => {
1836 value.to_css_impl(dest, ArgumentLevel::Nested)?
1837 },
1838 Self::Sum(ref children) => {
1839 let mut first = true;
1840 for child in &**children {
1841 if !first {
1842 match child {
1843 Self::Leaf(l) => {
1844 if let Ok(true) = l.is_negative() {
1845 dest.write_str(" - ")?;
1846 let mut negated = l.clone();
1847 negated.map(std::ops::Neg::neg).unwrap();
1850 negated.to_css(dest)?;
1851 } else {
1852 dest.write_str(" + ")?;
1853 l.to_css(dest)?;
1854 }
1855 },
1856 Self::Negate(n) => {
1857 dest.write_str(" - ")?;
1858 n.to_css_impl(dest, ArgumentLevel::Nested)?;
1859 },
1860 _ => {
1861 dest.write_str(" + ")?;
1862 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1863 },
1864 }
1865 } else {
1866 first = false;
1867 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1868 }
1869 }
1870 },
1871 Self::Product(ref children) => {
1872 let mut first = true;
1873 for child in &**children {
1874 if !first {
1875 match child {
1876 Self::Invert(n) => {
1877 dest.write_str(" / ")?;
1878 n.to_css_impl(dest, ArgumentLevel::Nested)?;
1879 },
1880 _ => {
1881 dest.write_str(" * ")?;
1882 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1883 },
1884 }
1885 } else {
1886 first = false;
1887 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1888 }
1889 }
1890 },
1891 Self::Clamp {
1892 ref min,
1893 ref center,
1894 ref max,
1895 } => {
1896 min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1897 dest.write_str(", ")?;
1898 center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1899 dest.write_str(", ")?;
1900 max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1901 },
1902 Self::Round {
1903 ref value,
1904 ref step,
1905 ..
1906 } => {
1907 value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1908 dest.write_str(", ")?;
1909 step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1910 },
1911 Self::ModRem {
1912 ref dividend,
1913 ref divisor,
1914 ..
1915 } => {
1916 dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1917 dest.write_str(", ")?;
1918 divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1919 },
1920 Self::Abs(ref v) | Self::Sign(ref v) => {
1921 v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
1922 },
1923 Self::Leaf(ref l) => l.to_css(dest)?,
1924 Self::Anchor(ref f) => f.to_css(dest)?,
1925 Self::AnchorSize(ref f) => f.to_css(dest)?,
1926 }
1927
1928 if write_closing_paren {
1929 dest.write_char(')')?;
1930 }
1931 Ok(())
1932 }
1933
1934 fn compare(
1935 &self,
1936 other: &Self,
1937 basis_positive: PositivePercentageBasis,
1938 ) -> Option<cmp::Ordering> {
1939 match (self, other) {
1940 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
1941 one.compare(other, basis_positive)
1942 },
1943 _ => None,
1944 }
1945 }
1946
1947 compare_helpers!();
1948}
1949
1950impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
1951 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
1953 where
1954 W: Write,
1955 {
1956 self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
1957 }
1958}
1959
1960#[cfg(test)]
1961mod tests {
1962 use super::*;
1963
1964 #[test]
1965 fn can_sum_with_checks() {
1966 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH));
1967 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::PERCENTAGE));
1968 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
1969
1970 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
1971 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
1972 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
1973
1974 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
1975 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
1976 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
1977
1978 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::TIME));
1979 assert!(CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE));
1980
1981 assert!(!(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE));
1982 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME));
1983 assert!(
1984 !(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME)
1985 );
1986 }
1987}