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