calc.rs (74784B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 //! [Calc expressions][calc]. 6 //! 7 //! [calc]: https://drafts.csswg.org/css-values/#calc-notation 8 9 use crate::derives::*; 10 use crate::values::generics::length::GenericAnchorSizeFunction; 11 use crate::values::generics::position::{GenericAnchorFunction, GenericAnchorSide}; 12 use num_traits::Zero; 13 use smallvec::SmallVec; 14 use std::convert::AsRef; 15 use std::fmt::{self, Write}; 16 use std::ops::{Add, Mul, Neg, Rem, Sub}; 17 use std::{cmp, mem}; 18 use strum_macros::AsRefStr; 19 use style_traits::{CssWriter, NumericValue, ToCss, ToTyped, TypedValue}; 20 21 use thin_vec::ThinVec; 22 23 /// Whether we're a `min` or `max` function. 24 #[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)] 37 pub enum MinMaxOp { 38 /// `min()` 39 Min, 40 /// `max()` 41 Max, 42 } 43 44 /// Whether we're a `mod` or `rem` function. 45 #[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)] 58 pub enum ModRemOp { 59 /// `mod()` 60 Mod, 61 /// `rem()` 62 Rem, 63 } 64 65 impl ModRemOp { 66 fn apply(self, dividend: f32, divisor: f32) -> f32 { 67 // In mod(A, B) only, if B is infinite and A has opposite sign to B 68 // (including an oppositely-signed zero), the result is NaN. 69 // https://drafts.csswg.org/css-values/#round-infinities 70 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 /// The strategy used in `round()` 90 #[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)] 103 pub enum RoundingStrategy { 104 /// `round(nearest, a, b)` 105 /// round a to the nearest multiple of b 106 Nearest, 107 /// `round(up, a, b)` 108 /// round a up to the nearest multiple of b 109 Up, 110 /// `round(down, a, b)` 111 /// round a down to the nearest multiple of b 112 Down, 113 /// `round(to-zero, a, b)` 114 /// round a to the nearest multiple of b that is towards zero 115 ToZero, 116 } 117 118 /// This determines the order in which we serialize members of a calc() sum. 119 /// 120 /// See https://drafts.csswg.org/css-values-4/#sort-a-calculations-children 121 #[derive( 122 AsRefStr, Clone, Copy, Debug, Eq, Ord, Parse, PartialEq, PartialOrd, MallocSizeOf, ToShmem, 123 )] 124 #[strum(serialize_all = "lowercase")] 125 #[allow(missing_docs)] 126 pub 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, // Sec 167 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 185 /// `anchor()` function used in math functions. 186 pub type GenericCalcAnchorFunction<L> = 187 GenericAnchorFunction<Box<GenericCalcNode<L>>, Box<GenericCalcNode<L>>>; 188 /// `anchor-size()` function used in math functions. 189 pub type GenericCalcAnchorSizeFunction<L> = GenericAnchorSizeFunction<Box<GenericCalcNode<L>>>; 190 191 /// A generic node in a calc expression. 192 /// 193 /// FIXME: This would be much more elegant if we used `Self` in the types below, 194 /// but we can't because of https://github.com/serde-rs/serde/issues/1565. 195 /// 196 /// FIXME: The following annotations are to workaround an LLVM inlining bug, see 197 /// bug 1631929. 198 /// 199 /// cbindgen:destructor-attributes=MOZ_NEVER_INLINE 200 /// cbindgen:copy-constructor-attributes=MOZ_NEVER_INLINE 201 /// cbindgen:eq-attributes=MOZ_NEVER_INLINE 202 #[repr(u8)] 203 #[derive( 204 Clone, 205 Debug, 206 Deserialize, 207 MallocSizeOf, 208 PartialEq, 209 Serialize, 210 ToAnimatedZero, 211 ToResolvedValue, 212 ToShmem, 213 )] 214 pub enum GenericCalcNode<L> { 215 /// A leaf node. 216 Leaf(L), 217 /// A node that negates its child, e.g. Negate(1) == -1. 218 Negate(Box<GenericCalcNode<L>>), 219 /// A node that inverts its child, e.g. Invert(10) == 1 / 10 == 0.1. The child must always 220 /// resolve to a number unit. 221 Invert(Box<GenericCalcNode<L>>), 222 /// A sum node, representing `a + b + c` where a, b, and c are the 223 /// arguments. 224 Sum(crate::OwnedSlice<GenericCalcNode<L>>), 225 /// A product node, representing `a * b * c` where a, b, and c are the 226 /// arguments. 227 Product(crate::OwnedSlice<GenericCalcNode<L>>), 228 /// A `min` or `max` function. 229 MinMax(crate::OwnedSlice<GenericCalcNode<L>>, MinMaxOp), 230 /// A `clamp()` function. 231 Clamp { 232 /// The minimum value. 233 min: Box<GenericCalcNode<L>>, 234 /// The central value. 235 center: Box<GenericCalcNode<L>>, 236 /// The maximum value. 237 max: Box<GenericCalcNode<L>>, 238 }, 239 /// A `round()` function. 240 Round { 241 /// The rounding strategy. 242 strategy: RoundingStrategy, 243 /// The value to round. 244 value: Box<GenericCalcNode<L>>, 245 /// The step value. 246 step: Box<GenericCalcNode<L>>, 247 }, 248 /// A `mod()` or `rem()` function. 249 ModRem { 250 /// The dividend calculation. 251 dividend: Box<GenericCalcNode<L>>, 252 /// The divisor calculation. 253 divisor: Box<GenericCalcNode<L>>, 254 /// Is the function mod or rem? 255 op: ModRemOp, 256 }, 257 /// A `hypot()` function 258 Hypot(crate::OwnedSlice<GenericCalcNode<L>>), 259 /// An `abs()` function. 260 Abs(Box<GenericCalcNode<L>>), 261 /// A `sign()` function. 262 Sign(Box<GenericCalcNode<L>>), 263 /// An `anchor()` function. 264 Anchor(Box<GenericCalcAnchorFunction<L>>), 265 /// An `anchor-size()` function. 266 AnchorSize(Box<GenericCalcAnchorSizeFunction<L>>), 267 } 268 269 pub use self::GenericCalcNode as CalcNode; 270 271 bitflags! { 272 /// Expected units we allow parsing within a `calc()` expression. 273 /// 274 /// This is used as a hint for the parser to fast-reject invalid 275 /// expressions. Numbers are always allowed because they multiply other 276 /// units. 277 #[derive(Clone, Copy, PartialEq, Eq)] 278 pub struct CalcUnits: u8 { 279 /// <length> 280 const LENGTH = 1 << 0; 281 /// <percentage> 282 const PERCENTAGE = 1 << 1; 283 /// <angle> 284 const ANGLE = 1 << 2; 285 /// <time> 286 const TIME = 1 << 3; 287 /// <resolution> 288 const RESOLUTION = 1 << 4; 289 /// A component of a color (r, g, b, h, s, l, alpha, etc.) 290 const COLOR_COMPONENT = 1 << 5; 291 292 /// <length-percentage> 293 const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits(); 294 // NOTE: When you add to this, make sure to make Atan2 deal with these. 295 /// Allow all units. 296 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 301 impl CalcUnits { 302 /// Returns whether the flags only represent a single unit. This will return true for 0, which 303 /// is a "number" this is also fine. 304 #[inline] 305 fn is_single_unit(&self) -> bool { 306 self.bits() == 0 || self.bits() & (self.bits() - 1) == 0 307 } 308 309 /// Returns true if this unit is allowed to be summed with the given unit, otherwise false. 310 #[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 321 /// For percentage resolution, sometimes we can't assume that the percentage basis is positive (so 322 /// we don't know whether a percentage is larger than another). 323 pub enum PositivePercentageBasis { 324 /// The percent basis is not known-positive, we can't compare percentages. 325 Unknown, 326 /// The percent basis is known-positive, we assume larger percentages are larger. 327 Yes, 328 } 329 330 macro_rules! compare_helpers { 331 () => { 332 /// Return whether a leaf is greater than another. 333 #[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 /// Return whether a leaf is less than another. 339 fn lt(&self, other: &Self, basis_positive: PositivePercentageBasis) -> bool { 340 self.compare(other, basis_positive) == Some(cmp::Ordering::Less) 341 } 342 343 /// Return whether a leaf is smaller or equal than another. 344 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 355 /// A trait that represents all the stuff a valid leaf of a calc expression. 356 pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss + ToTyped { 357 /// Returns the unit of the leaf. 358 fn unit(&self) -> CalcUnits; 359 360 /// Returns the unitless value of this leaf if one is available. 361 fn unitless_value(&self) -> Option<f32>; 362 363 /// Return true if the units of both leaves are equal. (NOTE: Does not take 364 /// the values into account) 365 fn is_same_unit_as(&self, other: &Self) -> bool { 366 std::mem::discriminant(self) == std::mem::discriminant(other) 367 } 368 369 /// Do a partial comparison of these values. 370 fn compare( 371 &self, 372 other: &Self, 373 base_is_positive: PositivePercentageBasis, 374 ) -> Option<cmp::Ordering>; 375 compare_helpers!(); 376 377 /// Create a new leaf with a number value. 378 fn new_number(value: f32) -> Self; 379 380 /// Returns a float value if the leaf is a number. 381 fn as_number(&self) -> Option<f32>; 382 383 /// Whether this value is known-negative. 384 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 /// Whether this value is infinite. 391 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 /// Whether this value is zero. 398 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 /// Whether this value is NaN. 405 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 /// Tries to merge one leaf into another using the sum, that is, perform `x` + `y`. 412 fn try_sum_in_place(&mut self, other: &Self) -> Result<(), ()>; 413 414 /// Try to merge the right leaf into the left by using a multiplication. Return true if the 415 /// merge was successful, otherwise false. 416 fn try_product_in_place(&mut self, other: &mut Self) -> bool; 417 418 /// Tries a generic arithmetic operation. 419 fn try_op<O>(&self, other: &Self, op: O) -> Result<Self, ()> 420 where 421 O: Fn(f32, f32) -> f32; 422 423 /// Map the value of this node with the given operation. 424 fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>; 425 426 /// Canonicalizes the expression if necessary. 427 fn simplify(&mut self); 428 429 /// Returns the sort key for simplification. 430 fn sort_key(&self) -> SortKey; 431 432 /// Create a new leaf containing the sign() result of the given leaf. 433 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 /// The level of any argument being serialized in `to_css_impl`. 451 enum ArgumentLevel { 452 /// The root of a calculation tree. 453 CalculationRoot, 454 /// The root of an operand node's argument, e.g. `min(10, 20)`, `10` and `20` will have this 455 /// level, but min in this case will have `TopMost`. 456 ArgumentRoot, 457 /// Any other values serialized in the tree. 458 Nested, 459 } 460 461 impl<L: CalcNodeLeaf> CalcNode<L> { 462 /// Create a dummy CalcNode that can be used to do replacements of other nodes. 463 fn dummy() -> Self { 464 Self::MinMax(Default::default(), MinMaxOp::Max) 465 } 466 467 /// Change all the leaf nodes to have the given value. This is useful when 468 /// you have `calc(1px * nan)` and you want to replace the product node with 469 /// `calc(nan)`, in which case the unit will be retained. 470 fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> { 471 self.map(|_| value) 472 } 473 474 /// Return true if a product is distributive over this node. 475 /// Is distributive: (2 + 3) * 4 = 8 + 12 476 /// Not distributive: sign(2 + 3) * 4 != sign(8 + 12) 477 #[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 /// If the node has a valid unit outcome, then return it, otherwise fail. 487 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 // Only one node is allowed to have a unit, the rest must be numbers. 506 let mut unit = None; 507 for child in children.iter() { 508 let child_unit = child.unit()?; 509 if child_unit.is_empty() { 510 // Numbers are always allowed in a product, so continue with the next. 511 continue; 512 } 513 514 if unit.is_some() { 515 // We already have a unit for the node, so another unit node is invalid. 516 return Err(()); 517 } 518 519 // We have the unit for the node. 520 unit = Some(child_unit); 521 } 522 // We only keep track of specified units, so if we end up with a None and no failure 523 // so far, then we have a number. 524 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 // sign() always resolves to a number, but we still need to make sure that the 573 // child units make sense. 574 let _ = child.unit()?; 575 CalcUnits::empty() 576 }, 577 CalcNode::Anchor(..) | CalcNode::AnchorSize(..) => CalcUnits::LENGTH_PERCENTAGE, 578 }) 579 } 580 581 /// Negate the node inline. If the node is distributive, it is replaced by the result, 582 /// otherwise the node is wrapped in a [`Negate`] node. 583 pub fn negate(&mut self) { 584 /// Node(params) -> Negate(Node(params)) 585 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 // Don't negate the value here. Replace `self` with it's child. 598 let result = mem::replace(value.as_mut(), Self::dummy()); 599 *self = result; 600 }, 601 CalcNode::Invert(_) => { 602 // -(1 / -10) == -(-0.1) == 0.1 603 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 // -(2 * 3 / 4) == -(1.5) 612 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 // Negating min-max means the operation is swapped. 620 *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 // Nearest is tricky because we'd have to swap the 648 // behavior at the half-way point from using the upper 649 // to lower bound. 650 // Simpler to just wrap self in a negate node. 651 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 /// Returns the leaf if we can (if simplification has allowed it). 695 pub fn as_leaf(&self) -> Option<&L> { 696 match *self { 697 Self::Leaf(ref l) => Some(l), 698 _ => None, 699 } 700 } 701 702 /// Tries to merge one node into another using the sum, that is, perform `x` + `y`. 703 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 /// Tries to merge one node into another using the product, that is, perform `x` * `y`. 713 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 /// Tries to apply a generic arithmetic operator 750 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 /// Map the value of this node with the given operation. 763 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 // It is invalid to treat inner `CalcNode`s here - `anchor(--foo 50%) / 2` != `anchor(--foo 25%)`. 806 // Same applies to fallback, as we don't know if it will be used. Similar reasoning applies to `anchor-size()`. 807 CalcNode::Anchor(_) | CalcNode::AnchorSize(_) => Err(()), 808 } 809 } 810 811 map_internal(self, &mut op) 812 } 813 814 /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind. 815 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 /// Resolve this node into a value. 916 pub fn resolve(&self) -> Result<L, ()> { 917 self.resolve_map(|l| Ok(l.clone())) 918 } 919 920 /// Resolve this node into a value, given a function that maps the leaf values. 921 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 // try_op will make sure we only sum leaves with the same type. 950 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 // Mutliply only allowed when either side is a number. 961 match result.as_number() { 962 Some(left) => { 963 // Left side is a number, so we use the right node as the result. 964 result = right; 965 result.map(|v| v * left)?; 966 }, 967 None => { 968 // Left side is not a number, so check if the right side is. 969 match right.as_number() { 970 Some(right) => { 971 result.map(|v| v * right)?; 972 }, 973 None => { 974 // Multiplying with both sides having units. 975 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 // Leaf types must match for each child. 995 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 // TODO(emilio): Seems like at least a few of these 1066 // special-cases could be removed if we do the math in a 1067 // particular order. 1068 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 // In case of a tie, use the upper bound 1112 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 // In case of a tie, use the upper bound 1122 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 /// Mutate nodes within this calc node tree using given the mapping function. 1187 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 // Assume that any sub-nodes don't need to be mutated. 1201 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 /// Visits all the nodes in this calculation tree recursively, starting by 1264 /// the leaves and bubbling all the way up. 1265 /// 1266 /// This is useful for simplification, but can also be used for validation 1267 /// and such. 1268 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 /// This function simplifies and sorts the calculation of the specified node. It simplifies 1319 /// directly nested nodes while assuming that all nodes below it have already been simplified. 1320 /// It is recommended to use this function in combination with `visit_depth_first()`. 1321 /// 1322 /// This function is necessary only if the node needs to be preserved after parsing, 1323 /// specifically for `<length-percentage>` cases where the calculation contains percentages or 1324 /// relative units. Otherwise, the node can be evaluated using `resolve()`, which will 1325 /// automatically provide a simplified value. 1326 /// 1327 /// <https://drafts.csswg.org/css-values-4/#calc-simplification> 1328 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 // NOTE: clamp() is max(min, min(center, max)) 1352 let min_cmp_center = match min.compare(¢er, PositivePercentageBasis::Unknown) { 1353 Some(o) => o, 1354 None => return, 1355 }; 1356 1357 // So if we can prove that min is more than center, then we won, 1358 // as that's what we should always return. 1359 if matches!(min_cmp_center, cmp::Ordering::Greater) { 1360 replace_self_with!(&mut **min); 1361 return; 1362 } 1363 1364 // Otherwise try with max. 1365 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 // max is less than center, so we need to return effectively 1372 // `max(min, max)`. 1373 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 // Otherwise we're the center node. 1388 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 // In case of a tie, use the upper bound 1488 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 // In case of a tie, use the upper bound 1513 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 // We can't compare all the children, so we can't 1550 // know which one will actually win. Bail out and 1551 // keep ourselves as a min / max function. 1552 // 1553 // TODO: Maybe we could simplify compatible children, 1554 // see https://github.com/w3c/csswg-drafts/issues/4756 1555 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 we only have one kid, we've already simplified it, and it 1577 // doesn't really matter whether it's a sum already or not, so 1578 // lift it up and continue. 1579 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 // Merge all our nested sums, in reverse order so that the 1589 // list indices are not invalidated. 1590 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 // This would be nicer with 1597 // https://github.com/rust-lang/rust/issues/59878 fixed. 1598 children.extend(kid_children.into_vec()); 1599 } 1600 } 1601 1602 debug_assert!(children.len() >= 2, "Should still have multiple kids!"); 1603 1604 // Sort by spec order. 1605 children.sort_unstable_by_key(|c| c.sort_key()); 1606 1607 // NOTE: if the function returns true, by the docs of dedup_by, 1608 // a is removed. 1609 children.dedup_by(|a, b| b.try_sum_in_place(a).is_ok()); 1610 1611 if children.len() == 1 { 1612 // If only one children remains, lift it up, and carry on. 1613 replace_self_with!(&mut children[0]); 1614 } else { 1615 // Else put our simplified children back. 1616 *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 we only have one kid, we've already simplified it, and it 1630 // doesn't really matter whether it's a product already or not, 1631 // so lift it up and continue. 1632 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 // Merge all our nested sums, in reverse order so that the 1642 // list indices are not invalidated. 1643 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 // This would be nicer with 1650 // https://github.com/rust-lang/rust/issues/59878 fixed. 1651 children.extend(kid_children.into_vec()); 1652 } 1653 } 1654 1655 debug_assert!(children.len() >= 2, "Should still have multiple kids!"); 1656 1657 // Sort by spec order. 1658 children.sort_unstable_by_key(|c| c.sort_key()); 1659 1660 // NOTE: if the function returns true, by the docs of dedup_by, 1661 // a is removed. 1662 children.dedup_by(|right, left| left.try_product_in_place(right)); 1663 1664 if children.len() == 1 { 1665 // If only one children remains, lift it up, and carry on. 1666 replace_self_with!(&mut children[0]); 1667 } else { 1668 // Else put our simplified children back. 1669 *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 // Step 6. 1698 match &mut **child { 1699 CalcNode::Leaf(_) => { 1700 // 1. If root’s child is a numeric value, return an equivalent numeric value, but 1701 // with the value negated (0 - value). 1702 child.negate(); 1703 replace_self_with!(&mut **child); 1704 }, 1705 CalcNode::Negate(value) => { 1706 // 2. If root’s child is a Negate node, return the child’s child. 1707 replace_self_with!(&mut **value); 1708 }, 1709 _ => { 1710 // 3. Return root. 1711 }, 1712 } 1713 }, 1714 Self::Invert(ref mut child) => { 1715 // Step 7. 1716 match &mut **child { 1717 CalcNode::Leaf(leaf) => { 1718 // 1. If root’s child is a number (not a percentage or dimension) return the 1719 // reciprocal of the child’s value. 1720 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 // 2. If root’s child is an Invert node, return the child’s child. 1727 replace_self_with!(&mut **value); 1728 }, 1729 _ => { 1730 // 3. Return root. 1731 }, 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 /// Simplifies and sorts the kids in the whole calculation subtree. 1754 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 // We never generate a [`Negate`] node as the root of a calculation, only inside 1806 // [`Sum`] nodes as a child. Because negate nodes are handled by the [`Sum`] node 1807 // directly (see below), this node will never be serialized. 1808 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 // We can unwrap here, because we already 1866 // checked if the value inside is negative. 1867 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 // XXX Only supporting Sum and Leaf for now 1954 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 1999 impl<L: CalcNodeLeaf> ToCss for CalcNode<L> { 2000 /// <https://drafts.csswg.org/css-values/#calc-serialize> 2001 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 2009 impl<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)] 2016 mod 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 }