1use 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#[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(..) => {
560 CalcUnits::LENGTH_PERCENTAGE
561 }
562 })
563 }
564
565 pub fn negate(&mut self) {
568 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 let result = mem::replace(value.as_mut(), Self::dummy());
583 *self = result;
584 },
585 CalcNode::Invert(_) => {
586 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 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 *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 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 pub fn as_leaf(&self) -> Option<&L> {
680 match *self {
681 Self::Leaf(ref l) => Some(l),
682 _ => None,
683 }
684 }
685
686 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 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 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 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 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(())
792 }
793 }
794
795 map_internal(self, &mut op)
796 }
797
798 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 pub fn resolve(&self) -> Result<L, ()> {
895 self.resolve_map(|l| Ok(l.clone()))
896 }
897
898 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 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 match result.as_number() {
940 Some(left) => {
941 result = right;
943 result.map(|v| v * left)?;
944 },
945 None => {
946 match right.as_number() {
948 Some(right) => {
949 result.map(|v| v * right)?;
950 },
951 None => {
952 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 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(¢er) || !max.is_same_unit_as(¢er) {
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 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 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 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 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 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 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 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 let min_cmp_center = match min.compare(¢er, PositivePercentageBasis::Unknown) {
1328 Some(o) => o,
1329 None => return,
1330 };
1331
1332 if matches!(min_cmp_center, cmp::Ordering::Greater) {
1335 replace_self_with!(&mut **min);
1336 return;
1337 }
1338
1339 let max_cmp_center = match max.compare(¢er, PositivePercentageBasis::Unknown) {
1341 Some(o) => o,
1342 None => return,
1343 };
1344
1345 if matches!(max_cmp_center, cmp::Ordering::Less) {
1346 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 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 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 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 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 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 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 children.extend(kid_children.into_vec());
1574 }
1575 }
1576
1577 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1578
1579 children.sort_unstable_by_key(|c| c.sort_key());
1581
1582 children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1585
1586 if children.len() == 1 {
1587 replace_self_with!(&mut children[0]);
1589 } else {
1590 *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 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 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 children.extend(kid_children.into_vec());
1627 }
1628 }
1629
1630 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1631
1632 children.sort_unstable_by_key(|c| c.sort_key());
1634
1635 children.dedup_by(|right, left| left.try_product_in_place(right));
1638
1639 if children.len() == 1 {
1640 replace_self_with!(&mut children[0]);
1642 } else {
1643 *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 match &mut **child {
1674 CalcNode::Leaf(_) => {
1675 child.negate();
1678 replace_self_with!(&mut **child);
1679 },
1680 CalcNode::Negate(value) => {
1681 replace_self_with!(&mut **value);
1683 },
1684 _ => {
1685 },
1687 }
1688 },
1689 Self::Invert(ref mut child) => {
1690 match &mut **child {
1692 CalcNode::Leaf(leaf) => {
1693 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 replace_self_with!(&mut **value);
1703 },
1704 _ => {
1705 },
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 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 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 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 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}