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, 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
450enum ArgumentLevel {
452 CalculationRoot,
454 ArgumentRoot,
457 Nested,
459}
460
461impl<L: CalcNodeLeaf> CalcNode<L> {
462 fn dummy() -> Self {
464 Self::MinMax(Default::default(), MinMaxOp::Max)
465 }
466
467 fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> {
471 self.map(|_| value)
472 }
473
474 #[inline]
478 pub fn is_product_distributive(&self) -> bool {
479 match self {
480 Self::Leaf(l) => l.unit() != CalcUnits::COLOR_COMPONENT,
481 Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()),
482 _ => false,
483 }
484 }
485
486 pub fn unit(&self) -> Result<CalcUnits, ()> {
488 Ok(match self {
489 CalcNode::Leaf(l) => l.unit(),
490 CalcNode::Negate(child) | CalcNode::Invert(child) | CalcNode::Abs(child) => {
491 child.unit()?
492 },
493 CalcNode::Sum(children) => {
494 let mut unit = children.first().unwrap().unit()?;
495 for child in children.iter().skip(1) {
496 let child_unit = child.unit()?;
497 if !child_unit.can_sum_with(unit) {
498 return Err(());
499 }
500 unit |= child_unit;
501 }
502 unit
503 },
504 CalcNode::Product(children) => {
505 let mut unit = None;
507 for child in children.iter() {
508 let child_unit = child.unit()?;
509 if child_unit.is_empty() {
510 continue;
512 }
513
514 if unit.is_some() {
515 return Err(());
517 }
518
519 unit = Some(child_unit);
521 }
522 unit.unwrap_or(CalcUnits::empty())
525 },
526 CalcNode::MinMax(children, _) | CalcNode::Hypot(children) => {
527 let mut unit = children.first().unwrap().unit()?;
528 for child in children.iter().skip(1) {
529 let child_unit = child.unit()?;
530 if !child_unit.can_sum_with(unit) {
531 return Err(());
532 }
533 unit |= child_unit;
534 }
535 unit
536 },
537 CalcNode::Clamp { min, center, max } => {
538 let min_unit = min.unit()?;
539 let center_unit = center.unit()?;
540
541 if !min_unit.can_sum_with(center_unit) {
542 return Err(());
543 }
544
545 let max_unit = max.unit()?;
546
547 if !center_unit.can_sum_with(max_unit) {
548 return Err(());
549 }
550
551 min_unit | center_unit | max_unit
552 },
553 CalcNode::Round { value, step, .. } => {
554 let value_unit = value.unit()?;
555 let step_unit = step.unit()?;
556 if !step_unit.can_sum_with(value_unit) {
557 return Err(());
558 }
559 value_unit | step_unit
560 },
561 CalcNode::ModRem {
562 dividend, divisor, ..
563 } => {
564 let dividend_unit = dividend.unit()?;
565 let divisor_unit = divisor.unit()?;
566 if !divisor_unit.can_sum_with(dividend_unit) {
567 return Err(());
568 }
569 dividend_unit | divisor_unit
570 },
571 CalcNode::Sign(ref child) => {
572 let _ = child.unit()?;
575 CalcUnits::empty()
576 },
577 CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE,
578 })
579 }
580
581 pub fn negate(&mut self) {
584 fn wrap_self_in_negate<L: CalcNodeLeaf>(s: &mut CalcNode<L>) {
586 let result = mem::replace(s, CalcNode::dummy());
587 *s = CalcNode::Negate(Box::new(result));
588 }
589
590 match *self {
591 CalcNode::Leaf(ref mut leaf) => {
592 if leaf.map(std::ops::Neg::neg).is_err() {
593 wrap_self_in_negate(self)
594 }
595 },
596 CalcNode::Negate(ref mut value) => {
597 let result = mem::replace(value.as_mut(), Self::dummy());
599 *self = result;
600 },
601 CalcNode::Invert(_) => {
602 wrap_self_in_negate(self)
604 },
605 CalcNode::Sum(ref mut children) => {
606 for child in children.iter_mut() {
607 child.negate();
608 }
609 },
610 CalcNode::Product(_) => {
611 wrap_self_in_negate(self);
613 },
614 CalcNode::MinMax(ref mut children, ref mut op) => {
615 for child in children.iter_mut() {
616 child.negate();
617 }
618
619 *op = match *op {
621 MinMaxOp::Min => MinMaxOp::Max,
622 MinMaxOp::Max => MinMaxOp::Min,
623 };
624 },
625 CalcNode::Clamp {
626 ref mut min,
627 ref mut center,
628 ref mut max,
629 } => {
630 if min.lte(max, PositivePercentageBasis::Unknown) {
631 min.negate();
632 center.negate();
633 max.negate();
634
635 mem::swap(min, max);
636 } else {
637 wrap_self_in_negate(self);
638 }
639 },
640 CalcNode::Round {
641 ref mut strategy,
642 ref mut value,
643 ref mut step,
644 } => {
645 match *strategy {
646 RoundingStrategy::Nearest => {
647 wrap_self_in_negate(self);
652 return;
653 },
654 RoundingStrategy::Up => *strategy = RoundingStrategy::Down,
655 RoundingStrategy::Down => *strategy = RoundingStrategy::Up,
656 RoundingStrategy::ToZero => (),
657 }
658 value.negate();
659 step.negate();
660 },
661 CalcNode::ModRem {
662 ref mut dividend,
663 ref mut divisor,
664 ..
665 } => {
666 dividend.negate();
667 divisor.negate();
668 },
669 CalcNode::Hypot(ref mut children) => {
670 for child in children.iter_mut() {
671 child.negate();
672 }
673 },
674 CalcNode::Abs(_) => {
675 wrap_self_in_negate(self);
676 },
677 CalcNode::Sign(ref mut child) => {
678 child.negate();
679 },
680 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => {
681 wrap_self_in_negate(self);
682 },
683 }
684 }
685
686 fn sort_key(&self) -> SortKey {
687 match *self {
688 Self::Leaf(ref l) => l.sort_key(),
689 Self::Anchor(..) | Self::AnchorSize(..) => SortKey::Px,
690 _ => SortKey::Other,
691 }
692 }
693
694 pub fn as_leaf(&self) -> Option<&L> {
696 match *self {
697 Self::Leaf(ref l) => Some(l),
698 _ => None,
699 }
700 }
701
702 pub fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()> {
704 match (self, other) {
705 (&mut CalcNode::Leaf(ref mut one), &CalcNode::Leaf(ref other)) => {
706 one.try_sum_in_place(other)
707 },
708 _ => Err(()),
709 }
710 }
711
712 pub fn try_product_in_place(&mut self, other: &mut Self) -> bool {
714 if let Ok(resolved) = other.resolve() {
715 if let Some(number) = resolved.as_number() {
716 if number == 1.0 {
717 return true;
718 }
719
720 if self.is_product_distributive() {
721 if self.map(|v| v * number).is_err() {
722 return false;
723 }
724 return true;
725 }
726 }
727 }
728
729 if let Ok(resolved) = self.resolve() {
730 if let Some(number) = resolved.as_number() {
731 if number == 1.0 {
732 std::mem::swap(self, other);
733 return true;
734 }
735
736 if other.is_product_distributive() {
737 if other.map(|v| v * number).is_err() {
738 return false;
739 }
740 std::mem::swap(self, other);
741 return true;
742 }
743 }
744 }
745
746 false
747 }
748
749 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()>
751 where
752 O: Fn(f32, f32) -> f32,
753 {
754 match (self, other) {
755 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
756 Ok(CalcNode::Leaf(one.try_op(other, op)?))
757 },
758 _ => Err(()),
759 }
760 }
761
762 pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> {
764 fn map_internal<L: CalcNodeLeaf>(
765 node: &mut CalcNode<L>,
766 op: &mut impl FnMut(f32) -> f32,
767 ) -> Result<(), ()> {
768 match node {
769 CalcNode::Leaf(l) => l.map(op),
770 CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op),
771 CalcNode::Sum(children) | CalcNode::Product(children) => {
772 for node in &mut **children {
773 map_internal(node, op)?;
774 }
775 Ok(())
776 },
777 CalcNode::MinMax(children, _) => {
778 for node in &mut **children {
779 map_internal(node, op)?;
780 }
781 Ok(())
782 },
783 CalcNode::Clamp { min, center, max } => {
784 map_internal(min, op)?;
785 map_internal(center, op)?;
786 map_internal(max, op)
787 },
788 CalcNode::Round { value, step, .. } => {
789 map_internal(value, op)?;
790 map_internal(step, op)
791 },
792 CalcNode::ModRem {
793 dividend, divisor, ..
794 } => {
795 map_internal(dividend, op)?;
796 map_internal(divisor, op)
797 },
798 CalcNode::Hypot(children) => {
799 for node in &mut **children {
800 map_internal(node, op)?;
801 }
802 Ok(())
803 },
804 CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op),
805 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()),
808 }
809 }
810
811 map_internal(self, &mut op)
812 }
813
814 pub fn map_leaves<O, F>(&self, mut map: F) -> CalcNode<O>
816 where
817 O: CalcNodeLeaf,
818 F: FnMut(&L) -> O,
819 {
820 self.map_leaves_internal(&mut map)
821 }
822
823 fn map_leaves_internal<O, F>(&self, map: &mut F) -> CalcNode<O>
824 where
825 O: CalcNodeLeaf,
826 F: FnMut(&L) -> O,
827 {
828 fn map_children<L, O, F>(
829 children: &[CalcNode<L>],
830 map: &mut F,
831 ) -> crate::OwnedSlice<CalcNode<O>>
832 where
833 L: CalcNodeLeaf,
834 O: CalcNodeLeaf,
835 F: FnMut(&L) -> O,
836 {
837 children
838 .iter()
839 .map(|c| c.map_leaves_internal(map))
840 .collect()
841 }
842
843 match *self {
844 Self::Leaf(ref l) => CalcNode::Leaf(map(l)),
845 Self::Negate(ref c) => CalcNode::Negate(Box::new(c.map_leaves_internal(map))),
846 Self::Invert(ref c) => CalcNode::Invert(Box::new(c.map_leaves_internal(map))),
847 Self::Sum(ref c) => CalcNode::Sum(map_children(c, map)),
848 Self::Product(ref c) => CalcNode::Product(map_children(c, map)),
849 Self::MinMax(ref c, op) => CalcNode::MinMax(map_children(c, map), op),
850 Self::Clamp {
851 ref min,
852 ref center,
853 ref max,
854 } => {
855 let min = Box::new(min.map_leaves_internal(map));
856 let center = Box::new(center.map_leaves_internal(map));
857 let max = Box::new(max.map_leaves_internal(map));
858 CalcNode::Clamp { min, center, max }
859 },
860 Self::Round {
861 strategy,
862 ref value,
863 ref step,
864 } => {
865 let value = Box::new(value.map_leaves_internal(map));
866 let step = Box::new(step.map_leaves_internal(map));
867 CalcNode::Round {
868 strategy,
869 value,
870 step,
871 }
872 },
873 Self::ModRem {
874 ref dividend,
875 ref divisor,
876 op,
877 } => {
878 let dividend = Box::new(dividend.map_leaves_internal(map));
879 let divisor = Box::new(divisor.map_leaves_internal(map));
880 CalcNode::ModRem {
881 dividend,
882 divisor,
883 op,
884 }
885 },
886 Self::Hypot(ref c) => CalcNode::Hypot(map_children(c, map)),
887 Self::Abs(ref c) => CalcNode::Abs(Box::new(c.map_leaves_internal(map))),
888 Self::Sign(ref c) => CalcNode::Sign(Box::new(c.map_leaves_internal(map))),
889 Self::Anchor(ref f) => CalcNode::Anchor(Box::new(GenericAnchorFunction {
890 target_element: f.target_element.clone(),
891 side: match &f.side {
892 GenericAnchorSide::Keyword(k) => GenericAnchorSide::Keyword(*k),
893 GenericAnchorSide::Percentage(p) => {
894 GenericAnchorSide::Percentage(Box::new(p.map_leaves_internal(map)))
895 },
896 },
897 fallback: f
898 .fallback
899 .as_ref()
900 .map(|fb| Box::new(fb.map_leaves_internal(map)))
901 .into(),
902 })),
903 Self::AnchorSize(ref f) => CalcNode::AnchorSize(Box::new(GenericAnchorSizeFunction {
904 target_element: f.target_element.clone(),
905 size: f.size,
906 fallback: f
907 .fallback
908 .as_ref()
909 .map(|fb| Box::new(fb.map_leaves_internal(map)))
910 .into(),
911 })),
912 }
913 }
914
915 pub fn resolve(&self) -> Result<L, ()> {
917 self.resolve_map(|l| Ok(l.clone()))
918 }
919
920 pub fn resolve_map<F>(&self, mut leaf_to_output_fn: F) -> Result<L, ()>
922 where
923 F: FnMut(&L) -> Result<L, ()>,
924 {
925 self.resolve_internal(&mut leaf_to_output_fn)
926 }
927
928 fn resolve_internal<F>(&self, leaf_to_output_fn: &mut F) -> Result<L, ()>
929 where
930 F: FnMut(&L) -> Result<L, ()>,
931 {
932 match self {
933 Self::Leaf(l) => leaf_to_output_fn(l),
934 Self::Negate(child) => {
935 let mut result = child.resolve_internal(leaf_to_output_fn)?;
936 result.map(|v| v.neg())?;
937 Ok(result)
938 },
939 Self::Invert(child) => {
940 let mut result = child.resolve_internal(leaf_to_output_fn)?;
941 result.map(|v| 1.0 / v)?;
942 Ok(result)
943 },
944 Self::Sum(children) => {
945 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
946
947 for child in children.iter().skip(1) {
948 let right = child.resolve_internal(leaf_to_output_fn)?;
949 result = result.try_op(&right, |left, right| left + right)?;
951 }
952
953 Ok(result)
954 },
955 Self::Product(children) => {
956 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
957
958 for child in children.iter().skip(1) {
959 let right = child.resolve_internal(leaf_to_output_fn)?;
960 match result.as_number() {
962 Some(left) => {
963 result = right;
965 result.map(|v| v * left)?;
966 },
967 None => {
968 match right.as_number() {
970 Some(right) => {
971 result.map(|v| v * right)?;
972 },
973 None => {
974 return Err(());
976 },
977 }
978 },
979 }
980 }
981
982 Ok(result)
983 },
984 Self::MinMax(children, op) => {
985 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
986
987 if result.is_nan()? {
988 return Ok(result);
989 }
990
991 for child in children.iter().skip(1) {
992 let candidate = child.resolve_internal(leaf_to_output_fn)?;
993
994 if !result.is_same_unit_as(&candidate) {
996 return Err(());
997 }
998
999 if candidate.is_nan()? {
1000 result = candidate;
1001 break;
1002 }
1003
1004 let candidate_wins = match op {
1005 MinMaxOp::Min => candidate.lt(&result, PositivePercentageBasis::Yes),
1006 MinMaxOp::Max => candidate.gt(&result, PositivePercentageBasis::Yes),
1007 };
1008
1009 if candidate_wins {
1010 result = candidate;
1011 }
1012 }
1013
1014 Ok(result)
1015 },
1016 Self::Clamp { min, center, max } => {
1017 let min = min.resolve_internal(leaf_to_output_fn)?;
1018 let center = center.resolve_internal(leaf_to_output_fn)?;
1019 let max = max.resolve_internal(leaf_to_output_fn)?;
1020
1021 if !min.is_same_unit_as(¢er) || !max.is_same_unit_as(¢er) {
1022 return Err(());
1023 }
1024
1025 if min.is_nan()? {
1026 return Ok(min);
1027 }
1028
1029 if center.is_nan()? {
1030 return Ok(center);
1031 }
1032
1033 if max.is_nan()? {
1034 return Ok(max);
1035 }
1036
1037 let mut result = center;
1038 if result.gt(&max, PositivePercentageBasis::Yes) {
1039 result = max;
1040 }
1041 if result.lt(&min, PositivePercentageBasis::Yes) {
1042 result = min
1043 }
1044
1045 Ok(result)
1046 },
1047 Self::Round {
1048 strategy,
1049 value,
1050 step,
1051 } => {
1052 let mut value = value.resolve_internal(leaf_to_output_fn)?;
1053 let step = step.resolve_internal(leaf_to_output_fn)?;
1054
1055 if !value.is_same_unit_as(&step) {
1056 return Err(());
1057 }
1058
1059 let Some(step) = step.unitless_value() else {
1060 return Err(());
1061 };
1062 let step = step.abs();
1063
1064 value.map(|value| {
1065 if step.is_zero() {
1069 return f32::NAN;
1070 }
1071
1072 if value.is_infinite() {
1073 if step.is_infinite() {
1074 return f32::NAN;
1075 }
1076 return value;
1077 }
1078
1079 if step.is_infinite() {
1080 match strategy {
1081 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1082 return if value.is_sign_negative() { -0.0 } else { 0.0 }
1083 },
1084 RoundingStrategy::Up => {
1085 return if !value.is_sign_negative() && !value.is_zero() {
1086 f32::INFINITY
1087 } else if !value.is_sign_negative() && value.is_zero() {
1088 value
1089 } else {
1090 -0.0
1091 }
1092 },
1093 RoundingStrategy::Down => {
1094 return if value.is_sign_negative() && !value.is_zero() {
1095 -f32::INFINITY
1096 } else if value.is_sign_negative() && value.is_zero() {
1097 value
1098 } else {
1099 0.0
1100 }
1101 },
1102 }
1103 }
1104
1105 let div = value / step;
1106 let lower_bound = div.floor() * step;
1107 let upper_bound = div.ceil() * step;
1108
1109 match strategy {
1110 RoundingStrategy::Nearest => {
1111 if value - lower_bound < upper_bound - value {
1113 lower_bound
1114 } else {
1115 upper_bound
1116 }
1117 },
1118 RoundingStrategy::Up => upper_bound,
1119 RoundingStrategy::Down => lower_bound,
1120 RoundingStrategy::ToZero => {
1121 if lower_bound.abs() < upper_bound.abs() {
1123 lower_bound
1124 } else {
1125 upper_bound
1126 }
1127 },
1128 }
1129 })?;
1130
1131 Ok(value)
1132 },
1133 Self::ModRem {
1134 dividend,
1135 divisor,
1136 op,
1137 } => {
1138 let mut dividend = dividend.resolve_internal(leaf_to_output_fn)?;
1139 let divisor = divisor.resolve_internal(leaf_to_output_fn)?;
1140
1141 if !dividend.is_same_unit_as(&divisor) {
1142 return Err(());
1143 }
1144
1145 let Some(divisor) = divisor.unitless_value() else {
1146 return Err(());
1147 };
1148 dividend.map(|dividend| op.apply(dividend, divisor))?;
1149 Ok(dividend)
1150 },
1151 Self::Hypot(children) => {
1152 let mut result = children[0].resolve_internal(leaf_to_output_fn)?;
1153 result.map(|v| v.powi(2))?;
1154
1155 for child in children.iter().skip(1) {
1156 let child_value = child.resolve_internal(leaf_to_output_fn)?;
1157
1158 if !result.is_same_unit_as(&child_value) {
1159 return Err(());
1160 }
1161
1162 let Some(child_value) = child_value.unitless_value() else {
1163 return Err(());
1164 };
1165 result.map(|v| v + child_value.powi(2))?;
1166 }
1167
1168 result.map(|v| v.sqrt())?;
1169 Ok(result)
1170 },
1171 Self::Abs(ref c) => {
1172 let mut result = c.resolve_internal(leaf_to_output_fn)?;
1173
1174 result.map(|v| v.abs())?;
1175
1176 Ok(result)
1177 },
1178 Self::Sign(ref c) => {
1179 let result = c.resolve_internal(leaf_to_output_fn)?;
1180 Ok(L::sign_from(&result)?)
1181 },
1182 Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
1183 }
1184 }
1185
1186 pub fn map_node<F>(&mut self, mut mapping_fn: F) -> Result<(), ()>
1188 where
1189 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1190 {
1191 self.map_node_internal(&mut mapping_fn)
1192 }
1193
1194 fn map_node_internal<F>(&mut self, mapping_fn: &mut F) -> Result<(), ()>
1195 where
1196 F: FnMut(&CalcNode<L>) -> Result<Option<CalcNode<L>>, ()>,
1197 {
1198 if let Some(node) = mapping_fn(self)? {
1199 *self = node;
1200 return Ok(());
1202 }
1203 match self {
1204 Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => (),
1205 Self::Negate(child) | Self::Invert(child) | Self::Abs(child) | Self::Sign(child) => {
1206 child.map_node_internal(mapping_fn)?;
1207 },
1208 Self::Sum(children)
1209 | Self::Product(children)
1210 | Self::Hypot(children)
1211 | Self::MinMax(children, _) => {
1212 for child in children.iter_mut() {
1213 child.map_node_internal(mapping_fn)?;
1214 }
1215 },
1216 Self::Clamp { min, center, max } => {
1217 min.map_node_internal(mapping_fn)?;
1218 center.map_node_internal(mapping_fn)?;
1219 max.map_node_internal(mapping_fn)?;
1220 },
1221 Self::Round { value, step, .. } => {
1222 value.map_node_internal(mapping_fn)?;
1223 step.map_node_internal(mapping_fn)?;
1224 },
1225 Self::ModRem {
1226 dividend, divisor, ..
1227 } => {
1228 dividend.map_node_internal(mapping_fn)?;
1229 divisor.map_node_internal(mapping_fn)?;
1230 },
1231 };
1232 Ok(())
1233 }
1234
1235 fn is_negative_leaf(&self) -> Result<bool, ()> {
1236 Ok(match *self {
1237 Self::Leaf(ref l) => l.is_negative()?,
1238 _ => false,
1239 })
1240 }
1241
1242 fn is_zero_leaf(&self) -> Result<bool, ()> {
1243 Ok(match *self {
1244 Self::Leaf(ref l) => l.is_zero()?,
1245 _ => false,
1246 })
1247 }
1248
1249 fn is_infinite_leaf(&self) -> Result<bool, ()> {
1250 Ok(match *self {
1251 Self::Leaf(ref l) => l.is_infinite()?,
1252 _ => false,
1253 })
1254 }
1255
1256 fn is_nan_leaf(&self) -> Result<bool, ()> {
1257 Ok(match *self {
1258 Self::Leaf(ref l) => l.is_nan()?,
1259 _ => false,
1260 })
1261 }
1262
1263 pub fn visit_depth_first(&mut self, mut f: impl FnMut(&mut Self)) {
1269 self.visit_depth_first_internal(&mut f)
1270 }
1271
1272 fn visit_depth_first_internal(&mut self, f: &mut impl FnMut(&mut Self)) {
1273 match *self {
1274 Self::Clamp {
1275 ref mut min,
1276 ref mut center,
1277 ref mut max,
1278 } => {
1279 min.visit_depth_first_internal(f);
1280 center.visit_depth_first_internal(f);
1281 max.visit_depth_first_internal(f);
1282 },
1283 Self::Round {
1284 ref mut value,
1285 ref mut step,
1286 ..
1287 } => {
1288 value.visit_depth_first_internal(f);
1289 step.visit_depth_first_internal(f);
1290 },
1291 Self::ModRem {
1292 ref mut dividend,
1293 ref mut divisor,
1294 ..
1295 } => {
1296 dividend.visit_depth_first_internal(f);
1297 divisor.visit_depth_first_internal(f);
1298 },
1299 Self::Sum(ref mut children)
1300 | Self::Product(ref mut children)
1301 | Self::MinMax(ref mut children, _)
1302 | Self::Hypot(ref mut children) => {
1303 for child in &mut **children {
1304 child.visit_depth_first_internal(f);
1305 }
1306 },
1307 Self::Negate(ref mut value) | Self::Invert(ref mut value) => {
1308 value.visit_depth_first_internal(f);
1309 },
1310 Self::Abs(ref mut value) | Self::Sign(ref mut value) => {
1311 value.visit_depth_first_internal(f);
1312 },
1313 Self::Leaf(..) | Self::Anchor(..) | Self::AnchorSize(..) => {},
1314 }
1315 f(self);
1316 }
1317
1318 pub fn simplify_and_sort_direct_children(&mut self) {
1329 macro_rules! replace_self_with {
1330 ($slot:expr) => {{
1331 let result = mem::replace($slot, Self::dummy());
1332 *self = result;
1333 }};
1334 }
1335
1336 macro_rules! value_or_stop {
1337 ($op:expr) => {{
1338 match $op {
1339 Ok(value) => value,
1340 Err(_) => return,
1341 }
1342 }};
1343 }
1344
1345 match *self {
1346 Self::Clamp {
1347 ref mut min,
1348 ref mut center,
1349 ref mut max,
1350 } => {
1351 let min_cmp_center = match min.compare(¢er, PositivePercentageBasis::Unknown) {
1353 Some(o) => o,
1354 None => return,
1355 };
1356
1357 if matches!(min_cmp_center, cmp::Ordering::Greater) {
1360 replace_self_with!(&mut **min);
1361 return;
1362 }
1363
1364 let max_cmp_center = match max.compare(¢er, PositivePercentageBasis::Unknown) {
1366 Some(o) => o,
1367 None => return,
1368 };
1369
1370 if matches!(max_cmp_center, cmp::Ordering::Less) {
1371 let max_cmp_min = match max.compare(&min, PositivePercentageBasis::Unknown) {
1374 Some(o) => o,
1375 None => return,
1376 };
1377
1378 if matches!(max_cmp_min, cmp::Ordering::Less) {
1379 replace_self_with!(&mut **min);
1380 return;
1381 }
1382
1383 replace_self_with!(&mut **max);
1384 return;
1385 }
1386
1387 replace_self_with!(&mut **center);
1389 },
1390 Self::Round {
1391 strategy,
1392 ref mut value,
1393 ref mut step,
1394 } => {
1395 if value_or_stop!(step.is_zero_leaf()) {
1396 value_or_stop!(value.coerce_to_value(f32::NAN));
1397 replace_self_with!(&mut **value);
1398 return;
1399 }
1400
1401 if value_or_stop!(value.is_infinite_leaf())
1402 && value_or_stop!(step.is_infinite_leaf())
1403 {
1404 value_or_stop!(value.coerce_to_value(f32::NAN));
1405 replace_self_with!(&mut **value);
1406 return;
1407 }
1408
1409 if value_or_stop!(value.is_infinite_leaf()) {
1410 replace_self_with!(&mut **value);
1411 return;
1412 }
1413
1414 if value_or_stop!(step.is_infinite_leaf()) {
1415 match strategy {
1416 RoundingStrategy::Nearest | RoundingStrategy::ToZero => {
1417 value_or_stop!(value.coerce_to_value(0.0));
1418 replace_self_with!(&mut **value);
1419 return;
1420 },
1421 RoundingStrategy::Up => {
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 RoundingStrategy::Down => {
1440 if value_or_stop!(value.is_negative_leaf())
1441 && !value_or_stop!(value.is_zero_leaf())
1442 {
1443 value_or_stop!(value.coerce_to_value(f32::INFINITY));
1444 replace_self_with!(&mut **value);
1445 return;
1446 } else if value_or_stop!(value.is_negative_leaf())
1447 && value_or_stop!(value.is_zero_leaf())
1448 {
1449 replace_self_with!(&mut **value);
1450 return;
1451 } else {
1452 value_or_stop!(value.coerce_to_value(0.0));
1453 replace_self_with!(&mut **value);
1454 return;
1455 }
1456 },
1457 }
1458 }
1459
1460 if value_or_stop!(step.is_negative_leaf()) {
1461 step.negate();
1462 }
1463
1464 let remainder = value_or_stop!(value.try_op(step, Rem::rem));
1465 if value_or_stop!(remainder.is_zero_leaf()) {
1466 replace_self_with!(&mut **value);
1467 return;
1468 }
1469
1470 let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf())
1471 {
1472 let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1473 let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub));
1474
1475 (lower_bound, upper_bound)
1476 } else {
1477 let lower_bound = value_or_stop!(value.try_op(&remainder, Sub::sub));
1478 let upper_bound = value_or_stop!(lower_bound.try_op(&step, Add::add));
1479
1480 (lower_bound, upper_bound)
1481 };
1482
1483 match strategy {
1484 RoundingStrategy::Nearest => {
1485 let lower_diff = value_or_stop!(value.try_op(&lower_bound, Sub::sub));
1486 let upper_diff = value_or_stop!(upper_bound.try_op(value, Sub::sub));
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 RoundingStrategy::Up => {
1495 replace_self_with!(&mut upper_bound);
1496 },
1497 RoundingStrategy::Down => {
1498 replace_self_with!(&mut lower_bound);
1499 },
1500 RoundingStrategy::ToZero => {
1501 let mut lower_diff = lower_bound.clone();
1502 let mut upper_diff = upper_bound.clone();
1503
1504 if value_or_stop!(lower_diff.is_negative_leaf()) {
1505 lower_diff.negate();
1506 }
1507
1508 if value_or_stop!(upper_diff.is_negative_leaf()) {
1509 upper_diff.negate();
1510 }
1511
1512 if lower_diff.lt(&upper_diff, PositivePercentageBasis::Unknown) {
1514 replace_self_with!(&mut lower_bound);
1515 } else {
1516 replace_self_with!(&mut upper_bound);
1517 }
1518 },
1519 };
1520 },
1521 Self::ModRem {
1522 ref dividend,
1523 ref divisor,
1524 op,
1525 } => {
1526 let mut result = value_or_stop!(dividend.try_op(divisor, |a, b| op.apply(a, b)));
1527 replace_self_with!(&mut result);
1528 },
1529 Self::MinMax(ref mut children, op) => {
1530 let winning_order = match op {
1531 MinMaxOp::Min => cmp::Ordering::Less,
1532 MinMaxOp::Max => cmp::Ordering::Greater,
1533 };
1534
1535 if value_or_stop!(children[0].is_nan_leaf()) {
1536 replace_self_with!(&mut children[0]);
1537 return;
1538 }
1539
1540 let mut result = 0;
1541 for i in 1..children.len() {
1542 if value_or_stop!(children[i].is_nan_leaf()) {
1543 replace_self_with!(&mut children[i]);
1544 return;
1545 }
1546 let o = match children[i]
1547 .compare(&children[result], PositivePercentageBasis::Unknown)
1548 {
1549 None => return,
1556 Some(o) => o,
1557 };
1558
1559 if o == winning_order {
1560 result = i;
1561 }
1562 }
1563
1564 replace_self_with!(&mut children[result]);
1565 },
1566 Self::Sum(ref mut children_slot) => {
1567 let mut sums_to_merge = SmallVec::<[_; 3]>::new();
1568 let mut extra_kids = 0;
1569 for (i, child) in children_slot.iter().enumerate() {
1570 if let Self::Sum(ref children) = *child {
1571 extra_kids += children.len();
1572 sums_to_merge.push(i);
1573 }
1574 }
1575
1576 if children_slot.len() == 1 {
1580 replace_self_with!(&mut children_slot[0]);
1581 return;
1582 }
1583
1584 let mut children = mem::take(children_slot).into_vec();
1585
1586 if !sums_to_merge.is_empty() {
1587 children.reserve(extra_kids - sums_to_merge.len());
1588 for i in sums_to_merge.drain(..).rev() {
1591 let kid_children = match children.swap_remove(i) {
1592 Self::Sum(c) => c,
1593 _ => unreachable!(),
1594 };
1595
1596 children.extend(kid_children.into_vec());
1599 }
1600 }
1601
1602 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1603
1604 children.sort_unstable_by_key(|c| c.sort_key());
1606
1607 children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok());
1610
1611 if children.len() == 1 {
1612 replace_self_with!(&mut children[0]);
1614 } else {
1615 *children_slot = children.into_boxed_slice().into();
1617 }
1618 },
1619 Self::Product(ref mut children_slot) => {
1620 let mut products_to_merge = SmallVec::<[_; 3]>::new();
1621 let mut extra_kids = 0;
1622 for (i, child) in children_slot.iter().enumerate() {
1623 if let Self::Product(ref children) = *child {
1624 extra_kids += children.len();
1625 products_to_merge.push(i);
1626 }
1627 }
1628
1629 if children_slot.len() == 1 {
1633 replace_self_with!(&mut children_slot[0]);
1634 return;
1635 }
1636
1637 let mut children = mem::take(children_slot).into_vec();
1638
1639 if !products_to_merge.is_empty() {
1640 children.reserve(extra_kids - products_to_merge.len());
1641 for i in products_to_merge.drain(..).rev() {
1644 let kid_children = match children.swap_remove(i) {
1645 Self::Product(c) => c,
1646 _ => unreachable!(),
1647 };
1648
1649 children.extend(kid_children.into_vec());
1652 }
1653 }
1654
1655 debug_assert!(children.len() >= 2, "Should still have multiple kids!");
1656
1657 children.sort_unstable_by_key(|c| c.sort_key());
1659
1660 children.dedup_by(|right, left| left.try_product_in_place(right));
1663
1664 if children.len() == 1 {
1665 replace_self_with!(&mut children[0]);
1667 } else {
1668 *children_slot = children.into_boxed_slice().into();
1670 }
1671 },
1672 Self::Hypot(ref children) => {
1673 let mut result = value_or_stop!(children[0].try_op(&children[0], Mul::mul));
1674
1675 for child in children.iter().skip(1) {
1676 let square = value_or_stop!(child.try_op(&child, Mul::mul));
1677 result = value_or_stop!(result.try_op(&square, Add::add));
1678 }
1679
1680 result = value_or_stop!(result.try_op(&result, |a, _| a.sqrt()));
1681
1682 replace_self_with!(&mut result);
1683 },
1684 Self::Abs(ref mut child) => {
1685 if let CalcNode::Leaf(leaf) = child.as_mut() {
1686 value_or_stop!(leaf.map(|v| v.abs()));
1687 replace_self_with!(&mut **child);
1688 }
1689 },
1690 Self::Sign(ref mut child) => {
1691 if let CalcNode::Leaf(leaf) = child.as_mut() {
1692 let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf)));
1693 replace_self_with!(&mut result);
1694 }
1695 },
1696 Self::Negate(ref mut child) => {
1697 match &mut **child {
1699 CalcNode::Leaf(_) => {
1700 child.negate();
1703 replace_self_with!(&mut **child);
1704 },
1705 CalcNode::Negate(value) => {
1706 replace_self_with!(&mut **value);
1708 },
1709 _ => {
1710 },
1712 }
1713 },
1714 Self::Invert(ref mut child) => {
1715 match &mut **child {
1717 CalcNode::Leaf(leaf) => {
1718 if leaf.unit().is_empty() {
1721 value_or_stop!(child.map(|v| 1.0 / v));
1722 replace_self_with!(&mut **child);
1723 }
1724 },
1725 CalcNode::Invert(value) => {
1726 replace_self_with!(&mut **value);
1728 },
1729 _ => {
1730 },
1732 }
1733 },
1734 Self::Leaf(ref mut l) => {
1735 l.simplify();
1736 },
1737 Self::Anchor(ref mut f) => {
1738 if let GenericAnchorSide::Percentage(ref mut n) = f.side {
1739 n.simplify_and_sort();
1740 }
1741 if let Some(fallback) = f.fallback.as_mut() {
1742 fallback.simplify_and_sort();
1743 }
1744 },
1745 Self::AnchorSize(ref mut f) => {
1746 if let Some(fallback) = f.fallback.as_mut() {
1747 fallback.simplify_and_sort();
1748 }
1749 },
1750 }
1751 }
1752
1753 pub fn simplify_and_sort(&mut self) {
1755 self.visit_depth_first(|node| node.simplify_and_sort_direct_children())
1756 }
1757
1758 fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, level: ArgumentLevel) -> fmt::Result
1759 where
1760 W: Write,
1761 {
1762 let write_closing_paren = match *self {
1763 Self::MinMax(_, op) => {
1764 dest.write_str(match op {
1765 MinMaxOp::Max => "max(",
1766 MinMaxOp::Min => "min(",
1767 })?;
1768 true
1769 },
1770 Self::Clamp { .. } => {
1771 dest.write_str("clamp(")?;
1772 true
1773 },
1774 Self::Round { strategy, .. } => {
1775 match strategy {
1776 RoundingStrategy::Nearest => dest.write_str("round("),
1777 RoundingStrategy::Up => dest.write_str("round(up, "),
1778 RoundingStrategy::Down => dest.write_str("round(down, "),
1779 RoundingStrategy::ToZero => dest.write_str("round(to-zero, "),
1780 }?;
1781
1782 true
1783 },
1784 Self::ModRem { op, .. } => {
1785 dest.write_str(match op {
1786 ModRemOp::Mod => "mod(",
1787 ModRemOp::Rem => "rem(",
1788 })?;
1789
1790 true
1791 },
1792 Self::Hypot(_) => {
1793 dest.write_str("hypot(")?;
1794 true
1795 },
1796 Self::Abs(_) => {
1797 dest.write_str("abs(")?;
1798 true
1799 },
1800 Self::Sign(_) => {
1801 dest.write_str("sign(")?;
1802 true
1803 },
1804 Self::Negate(_) => {
1805 debug_assert!(
1809 false,
1810 "We never serialize Negate nodes as they are handled inside Sum nodes."
1811 );
1812 dest.write_str("(-1 * ")?;
1813 true
1814 },
1815 Self::Invert(_) => {
1816 if matches!(level, ArgumentLevel::CalculationRoot) {
1817 dest.write_str("calc")?;
1818 }
1819 dest.write_str("(1 / ")?;
1820 true
1821 },
1822 Self::Sum(_) | Self::Product(_) => match level {
1823 ArgumentLevel::CalculationRoot => {
1824 dest.write_str("calc(")?;
1825 true
1826 },
1827 ArgumentLevel::ArgumentRoot => false,
1828 ArgumentLevel::Nested => {
1829 dest.write_str("(")?;
1830 true
1831 },
1832 },
1833 Self::Leaf(_) | Self::Anchor(_) | Self::AnchorSize(_) => match level {
1834 ArgumentLevel::CalculationRoot => {
1835 dest.write_str("calc(")?;
1836 true
1837 },
1838 ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => false,
1839 },
1840 };
1841
1842 match *self {
1843 Self::MinMax(ref children, _) | Self::Hypot(ref children) => {
1844 let mut first = true;
1845 for child in &**children {
1846 if !first {
1847 dest.write_str(", ")?;
1848 }
1849 first = false;
1850 child.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1851 }
1852 },
1853 Self::Negate(ref value) | Self::Invert(ref value) => {
1854 value.to_css_impl(dest, ArgumentLevel::Nested)?
1855 },
1856 Self::Sum(ref children) => {
1857 let mut first = true;
1858 for child in &**children {
1859 if !first {
1860 match child {
1861 Self::Leaf(l) => {
1862 if let Ok(true) = l.is_negative() {
1863 dest.write_str(" - ")?;
1864 let mut negated = l.clone();
1865 negated.map(std::ops::Neg::neg).unwrap();
1868 negated.to_css(dest)?;
1869 } else {
1870 dest.write_str(" + ")?;
1871 l.to_css(dest)?;
1872 }
1873 },
1874 Self::Negate(n) => {
1875 dest.write_str(" - ")?;
1876 n.to_css_impl(dest, ArgumentLevel::Nested)?;
1877 },
1878 _ => {
1879 dest.write_str(" + ")?;
1880 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1881 },
1882 }
1883 } else {
1884 first = false;
1885 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1886 }
1887 }
1888 },
1889 Self::Product(ref children) => {
1890 let mut first = true;
1891 for child in &**children {
1892 if !first {
1893 match child {
1894 Self::Invert(n) => {
1895 dest.write_str(" / ")?;
1896 n.to_css_impl(dest, ArgumentLevel::Nested)?;
1897 },
1898 _ => {
1899 dest.write_str(" * ")?;
1900 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1901 },
1902 }
1903 } else {
1904 first = false;
1905 child.to_css_impl(dest, ArgumentLevel::Nested)?;
1906 }
1907 }
1908 },
1909 Self::Clamp {
1910 ref min,
1911 ref center,
1912 ref max,
1913 } => {
1914 min.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1915 dest.write_str(", ")?;
1916 center.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1917 dest.write_str(", ")?;
1918 max.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1919 },
1920 Self::Round {
1921 ref value,
1922 ref step,
1923 ..
1924 } => {
1925 value.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1926 dest.write_str(", ")?;
1927 step.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1928 },
1929 Self::ModRem {
1930 ref dividend,
1931 ref divisor,
1932 ..
1933 } => {
1934 dividend.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1935 dest.write_str(", ")?;
1936 divisor.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?;
1937 },
1938 Self::Abs(ref v) | Self::Sign(ref v) => {
1939 v.to_css_impl(dest, ArgumentLevel::ArgumentRoot)?
1940 },
1941 Self::Leaf(ref l) => l.to_css(dest)?,
1942 Self::Anchor(ref f) => f.to_css(dest)?,
1943 Self::AnchorSize(ref f) => f.to_css(dest)?,
1944 }
1945
1946 if write_closing_paren {
1947 dest.write_char(')')?;
1948 }
1949 Ok(())
1950 }
1951
1952 fn to_typed_impl(&self, level: ArgumentLevel) -> Option<TypedValue> {
1953 match *self {
1955 Self::Sum(ref children) => {
1956 let mut values = ThinVec::new();
1957 for child in &**children {
1958 if let Some(TypedValue::Numeric(inner)) =
1959 child.to_typed_impl(ArgumentLevel::Nested)
1960 {
1961 values.push(inner);
1962 }
1963 }
1964 Some(TypedValue::Numeric(NumericValue::Sum { values }))
1965 },
1966 Self::Leaf(ref l) => match l.to_typed() {
1967 Some(TypedValue::Numeric(inner)) => match level {
1968 ArgumentLevel::CalculationRoot => {
1969 Some(TypedValue::Numeric(NumericValue::Sum {
1970 values: ThinVec::from([inner]),
1971 }))
1972 },
1973 ArgumentLevel::ArgumentRoot | ArgumentLevel::Nested => {
1974 Some(TypedValue::Numeric(inner))
1975 },
1976 },
1977 _ => None,
1978 },
1979 _ => None,
1980 }
1981 }
1982
1983 fn compare(
1984 &self,
1985 other: &Self,
1986 basis_positive: PositivePercentageBasis,
1987 ) -> Option<cmp::Ordering> {
1988 match (self, other) {
1989 (&CalcNode::Leaf(ref one), &CalcNode::Leaf(ref other)) => {
1990 one.compare(other, basis_positive)
1991 },
1992 _ => None,
1993 }
1994 }
1995
1996 compare_helpers!();
1997}
1998
1999impl<L: CalcNodeLeaf> ToCss for CalcNode<L> {
2000 fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
2002 where
2003 W: Write,
2004 {
2005 self.to_css_impl(dest, ArgumentLevel::CalculationRoot)
2006 }
2007}
2008
2009impl<L: CalcNodeLeaf> ToTyped for CalcNode<L> {
2010 fn to_typed(&self) -> Option<TypedValue> {
2011 self.to_typed_impl(ArgumentLevel::CalculationRoot)
2012 }
2013}
2014
2015#[cfg(test)]
2016mod tests {
2017 use super::*;
2018
2019 #[test]
2020 fn can_sum_with_checks() {
2021 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH));
2022 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::PERCENTAGE));
2023 assert!(CalcUnits::LENGTH.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2024
2025 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2026 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2027 assert!(CalcUnits::PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2028
2029 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH));
2030 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::PERCENTAGE));
2031 assert!(CalcUnits::LENGTH_PERCENTAGE.can_sum_with(CalcUnits::LENGTH_PERCENTAGE));
2032
2033 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::TIME));
2034 assert!(CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE));
2035
2036 assert!(!(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE));
2037 assert!(!CalcUnits::ANGLE.can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME));
2038 assert!(
2039 !(CalcUnits::ANGLE | CalcUnits::TIME).can_sum_with(CalcUnits::ANGLE | CalcUnits::TIME)
2040 );
2041 }
2042}