diff --git a/components/style/values/computed/length_percentage.rs b/components/style/values/computed/length_percentage.rs index 4e2e6e5695f..98b46454d10 100644 --- a/components/style/values/computed/length_percentage.rs +++ b/components/style/values/computed/length_percentage.rs @@ -656,23 +656,14 @@ impl CalcLengthPercentage { /// Resolves the percentage. #[inline] fn resolve(&self, basis: Length) -> Length { - // TODO: This could be faster (without the extra allocations), - // potentially. - let mut resolved = self.node.map_leafs(|l| { - match l { - CalcLengthPercentageLeaf::Length(..) => l.clone(), - CalcLengthPercentageLeaf::Percentage(ref p) => { - CalcLengthPercentageLeaf::Length(Length::new(basis.px() * p.0)) - }, - } - }); - - resolved.simplify_and_sort_children(); - - match resolved { - CalcNode::Leaf(CalcLengthPercentageLeaf::Length(l)) => l, - other => unreachable!("Didn't manage to resolve : {:?}", other), - } + // unwrap() is fine because the conversion below is infallible. + let px = self.node.resolve(|l| { + Ok(match *l { + CalcLengthPercentageLeaf::Length(l) => l.px(), + CalcLengthPercentageLeaf::Percentage(ref p) => basis.px() * p.0, + }) + }).unwrap(); + Length::new(self.clamping_mode.clamp(px)) } fn clamp_to_non_negative(&self) -> LengthPercentage { diff --git a/components/style/values/generics/calc.rs b/components/style/values/generics/calc.rs index 833864aebf2..d7ba5e39807 100644 --- a/components/style/values/generics/calc.rs +++ b/components/style/values/generics/calc.rs @@ -6,9 +6,11 @@ //! //! [calc]: https://drafts.csswg.org/css-values/#calc-notation +use crate::Zero; use style_traits::{CssWriter, ToCss}; use std::fmt::{self, Write}; use std::{cmp, mem}; +use std::ops::Add; use smallvec::SmallVec; /// Whether we're a `min` or `max` function. @@ -149,11 +151,64 @@ impl CalcNode { let center = Box::new(center.map_leaves_internal(map)); let max = Box::new(max.map_leaves_internal(map)); CalcNode::Clamp { min, center, max } - } } } + /// Resolves the expression returning a value of `O`, given a function to + /// turn a leaf into the relevant value. + pub fn resolve(&self, mut leaf_to_output_fn: impl FnMut(&L) -> Result) -> Result + where + O: PartialOrd + PartialEq + Add + Zero, + { + self.resolve_internal(&mut leaf_to_output_fn) + } + + fn resolve_internal(&self, leaf_to_output_fn: &mut F) -> Result + where + O: PartialOrd + PartialEq + Add + Zero, + F: FnMut(&L) -> Result, + { + Ok(match *self { + Self::Leaf(ref l) => return leaf_to_output_fn(l), + Self::Sum(ref c) => { + let mut result = Zero::zero(); + for child in &**c { + result = result + child.resolve_internal(leaf_to_output_fn)?; + } + result + }, + Self::MinMax(ref nodes, op) => { + let mut result = nodes[0].resolve_internal(leaf_to_output_fn)?; + for node in nodes.iter().skip(1) { + let candidate = node.resolve_internal(leaf_to_output_fn)?; + let candidate_wins = match op { + MinMaxOp::Min => candidate < result, + MinMaxOp::Max => candidate > result, + }; + if candidate_wins { + result = candidate; + } + } + result + }, + Self::Clamp { ref min, ref center, ref max } => { + let min = min.resolve_internal(leaf_to_output_fn)?; + let center = center.resolve_internal(leaf_to_output_fn)?; + let max = max.resolve_internal(leaf_to_output_fn)?; + + let mut result = center; + if result > max { + result = max; + } + if result < min { + result = min + } + result + }, + }) + } + fn is_negative_leaf(&self) -> bool { match *self { Self::Leaf(ref l) => l.is_negative(), diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 9f5817a7703..8732929b0cd 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -98,72 +98,6 @@ pub struct CalcLengthPercentage { impl SpecifiedValueInfo for CalcLengthPercentage {} -macro_rules! impl_generic_to_type { - ($self:ident, $self_variant:ident, $to_self:ident, $to_float:ident, $from_float:path) => {{ - if let Self::Leaf(Leaf::$self_variant(ref v)) = *$self { - return Ok(v.clone()); - } - - Ok(match *$self { - Self::Sum(ref expressions) => { - let mut sum = 0.; - for sub in &**expressions { - sum += sub.$to_self()?.$to_float(); - } - $from_float(sum) - }, - Self::Clamp { - ref min, - ref center, - ref max, - } => { - let min = min.$to_self()?; - let center = center.$to_self()?; - let max = max.$to_self()?; - - // Equivalent to cmp::max(min, cmp::min(center, max)) - // - // But preserving units when appropriate. - let center_float = center.$to_float(); - let min_float = min.$to_float(); - let max_float = max.$to_float(); - - let mut result = center; - let mut result_float = center_float; - - if result_float > max_float { - result = max; - result_float = max_float; - } - - if result_float < min_float { - min - } else { - result - } - }, - Self::MinMax(ref nodes, op) => { - let mut result = nodes[0].$to_self()?; - let mut result_float = result.$to_float(); - for node in nodes.iter().skip(1) { - let candidate = node.$to_self()?; - let candidate_float = candidate.$to_float(); - let candidate_wins = match op { - MinMaxOp::Min => candidate_float < result_float, - MinMaxOp::Max => candidate_float > result_float, - }; - if candidate_wins { - result = candidate; - result_float = candidate_float; - } - } - result - }, - Self::Leaf(..) => return Err(()), - }) - }}; -} - impl PartialOrd for Leaf { fn partial_cmp(&self, other: &Self) -> Option { use self::Leaf::*; @@ -527,22 +461,44 @@ impl CalcNode { /// Tries to simplify this expression into a `