diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:35:29 +0000 |
commit | 59203c63bb777a3bacec32fb8830fba33540e809 (patch) | |
tree | 58298e711c0ff0575818c30485b44a2f21bf28a0 /servo/components/style/values/generics/calc.rs | |
parent | Adding upstream version 126.0.1. (diff) | |
download | firefox-59203c63bb777a3bacec32fb8830fba33540e809.tar.xz firefox-59203c63bb777a3bacec32fb8830fba33540e809.zip |
Adding upstream version 127.0.upstream/127.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'servo/components/style/values/generics/calc.rs')
-rw-r--r-- | servo/components/style/values/generics/calc.rs | 243 |
1 files changed, 143 insertions, 100 deletions
diff --git a/servo/components/style/values/generics/calc.rs b/servo/components/style/values/generics/calc.rs index abcb5fe6eb..215db1932b 100644 --- a/servo/components/style/values/generics/calc.rs +++ b/servo/components/style/values/generics/calc.rs @@ -255,12 +255,15 @@ bitflags! { const TIME = 1 << 3; /// <resolution> const RESOLUTION = 1 << 4; + /// A component of a color (r, g, b, h, s, l, alpha, etc.) + const COLOR_COMPONENT = 1 << 5; /// <length-percentage> const LENGTH_PERCENTAGE = Self::LENGTH.bits() | Self::PERCENTAGE.bits(); // NOTE: When you add to this, make sure to make Atan2 deal with these. /// Allow all units. - const ALL = Self::LENGTH.bits() | Self::PERCENTAGE.bits() | Self::ANGLE.bits() | Self::TIME.bits() | Self::RESOLUTION.bits(); + const ALL = Self::LENGTH.bits() | Self::PERCENTAGE.bits() | Self::ANGLE.bits() | + Self::TIME.bits() | Self::RESOLUTION.bits() | Self::COLOR_COMPONENT.bits(); } } @@ -323,8 +326,8 @@ pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss { /// Returns the unit of the leaf. fn unit(&self) -> CalcUnits; - /// Returns the unitless value of this leaf. - fn unitless_value(&self) -> f32; + /// Returns the unitless value of this leaf if one is available. + fn unitless_value(&self) -> Option<f32>; /// Return true if the units of both leaves are equal. (NOTE: Does not take /// the values into account) @@ -347,23 +350,31 @@ pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss { fn as_number(&self) -> Option<f32>; /// Whether this value is known-negative. - fn is_negative(&self) -> bool { - self.unitless_value().is_sign_negative() + fn is_negative(&self) -> Result<bool, ()> { + self.unitless_value() + .map(|v| Ok(v.is_sign_negative())) + .unwrap_or_else(|| Err(())) } /// Whether this value is infinite. - fn is_infinite(&self) -> bool { - self.unitless_value().is_infinite() + fn is_infinite(&self) -> Result<bool, ()> { + self.unitless_value() + .map(|v| Ok(v.is_infinite())) + .unwrap_or_else(|| Err(())) } /// Whether this value is zero. - fn is_zero(&self) -> bool { - self.unitless_value().is_zero() + fn is_zero(&self) -> Result<bool, ()> { + self.unitless_value() + .map(|v| Ok(v.is_zero())) + .unwrap_or_else(|| Err(())) } /// Whether this value is NaN. - fn is_nan(&self) -> bool { - self.unitless_value().is_nan() + fn is_nan(&self) -> Result<bool, ()> { + self.unitless_value() + .map(|v| Ok(v.is_nan())) + .unwrap_or_else(|| Err(())) } /// Tries to merge one leaf into another using the sum, that is, perform `x` + `y`. @@ -379,12 +390,7 @@ pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss { O: Fn(f32, f32) -> f32; /// Map the value of this node with the given operation. - fn map(&mut self, op: impl FnMut(f32) -> f32); - - /// Negates the leaf. - fn negate(&mut self) { - self.map(std::ops::Neg::neg); - } + fn map(&mut self, op: impl FnMut(f32) -> f32) -> Result<(), ()>; /// Canonicalizes the expression if necessary. fn simplify(&mut self); @@ -393,16 +399,20 @@ pub trait CalcNodeLeaf: Clone + Sized + PartialEq + ToCss { fn sort_key(&self) -> SortKey; /// Create a new leaf containing the sign() result of the given leaf. - fn sign_from(leaf: &impl CalcNodeLeaf) -> Self { - Self::new_number(if leaf.is_nan() { + fn sign_from(leaf: &impl CalcNodeLeaf) -> Result<Self, ()> { + let Some(value) = leaf.unitless_value() else { + return Err(()); + }; + + Ok(Self::new_number(if value.is_nan() { f32::NAN - } else if leaf.is_zero() { - leaf.unitless_value() - } else if leaf.is_negative() { + } else if value.is_zero() { + value + } else if value.is_sign_negative() { -1.0 } else { 1.0 - }) + })) } } @@ -426,8 +436,8 @@ impl<L: CalcNodeLeaf> CalcNode<L> { /// Change all the leaf nodes to have the given value. This is useful when /// you have `calc(1px * nan)` and you want to replace the product node with /// `calc(nan)`, in which case the unit will be retained. - fn coerce_to_value(&mut self, value: f32) { - self.map(|_| value); + fn coerce_to_value(&mut self, value: f32) -> Result<(), ()> { + self.map(|_| value) } /// Return true if a product is distributive over this node. @@ -436,7 +446,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> { #[inline] pub fn is_product_distributive(&self) -> bool { match self { - Self::Leaf(_) => true, + Self::Leaf(l) => l.unit() != CalcUnits::COLOR_COMPONENT, Self::Sum(children) => children.iter().all(|c| c.is_product_distributive()), _ => false, } @@ -546,7 +556,11 @@ impl<L: CalcNodeLeaf> CalcNode<L> { } match *self { - CalcNode::Leaf(ref mut leaf) => leaf.negate(), + CalcNode::Leaf(ref mut leaf) => { + if leaf.map(std::ops::Neg::neg).is_err() { + wrap_self_in_negate(self) + } + }, CalcNode::Negate(ref mut value) => { // Don't negate the value here. Replace `self` with it's child. let result = mem::replace(value.as_mut(), Self::dummy()); @@ -668,7 +682,9 @@ impl<L: CalcNodeLeaf> CalcNode<L> { } if self.is_product_distributive() { - self.map(|v| v * number); + if self.map(|v| v * number).is_err() { + return false; + } return true; } } @@ -682,7 +698,9 @@ impl<L: CalcNodeLeaf> CalcNode<L> { } if other.is_product_distributive() { - other.map(|v| v * number); + if other.map(|v| v * number).is_err() { + return false; + } std::mem::swap(self, other); return true; } @@ -706,48 +724,52 @@ impl<L: CalcNodeLeaf> CalcNode<L> { } /// Map the value of this node with the given operation. - pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) { - fn map_internal<L: CalcNodeLeaf>(node: &mut CalcNode<L>, op: &mut impl FnMut(f32) -> f32) { + pub fn map(&mut self, mut op: impl FnMut(f32) -> f32) -> Result<(), ()> { + fn map_internal<L: CalcNodeLeaf>( + node: &mut CalcNode<L>, + op: &mut impl FnMut(f32) -> f32, + ) -> Result<(), ()> { match node { CalcNode::Leaf(l) => l.map(op), CalcNode::Negate(v) | CalcNode::Invert(v) => map_internal(v, op), CalcNode::Sum(children) | CalcNode::Product(children) => { for node in &mut **children { - map_internal(node, op); + map_internal(node, op)?; } + Ok(()) }, CalcNode::MinMax(children, _) => { for node in &mut **children { - map_internal(node, op); + map_internal(node, op)?; } + Ok(()) }, CalcNode::Clamp { min, center, max } => { - map_internal(min, op); - map_internal(center, op); - map_internal(max, op); + map_internal(min, op)?; + map_internal(center, op)?; + map_internal(max, op) }, CalcNode::Round { value, step, .. } => { - map_internal(value, op); - map_internal(step, op); + map_internal(value, op)?; + map_internal(step, op) }, CalcNode::ModRem { dividend, divisor, .. } => { - map_internal(dividend, op); - map_internal(divisor, op); + map_internal(dividend, op)?; + map_internal(divisor, op) }, CalcNode::Hypot(children) => { for node in &mut **children { - map_internal(node, op); + map_internal(node, op)?; } + Ok(()) }, - CalcNode::Abs(child) | CalcNode::Sign(child) => { - map_internal(child, op); - }, + CalcNode::Abs(child) | CalcNode::Sign(child) => map_internal(child, op), } } - map_internal(self, &mut op); + map_internal(self, &mut op) } /// Convert this `CalcNode` into a `CalcNode` with a different leaf kind. @@ -849,12 +871,12 @@ impl<L: CalcNodeLeaf> CalcNode<L> { Self::Leaf(l) => leaf_to_output_fn(l), Self::Negate(child) => { let mut result = child.resolve_internal(leaf_to_output_fn)?; - result.map(|v| v.neg()); + result.map(|v| v.neg())?; Ok(result) }, Self::Invert(child) => { let mut result = child.resolve_internal(leaf_to_output_fn)?; - result.map(|v| 1.0 / v); + result.map(|v| 1.0 / v)?; Ok(result) }, Self::Sum(children) => { @@ -878,13 +900,13 @@ impl<L: CalcNodeLeaf> CalcNode<L> { Some(left) => { // Left side is a number, so we use the right node as the result. result = right; - result.map(|v| v * left); + result.map(|v| v * left)?; }, None => { // Left side is not a number, so check if the right side is. match right.as_number() { Some(right) => { - result.map(|v| v * right); + result.map(|v| v * right)?; }, None => { // Multiplying with both sides having units. @@ -900,7 +922,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> { Self::MinMax(children, op) => { let mut result = children[0].resolve_internal(leaf_to_output_fn)?; - if result.is_nan() { + if result.is_nan()? { return Ok(result); } @@ -912,7 +934,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> { return Err(()); } - if candidate.is_nan() { + if candidate.is_nan()? { result = candidate; break; } @@ -938,15 +960,15 @@ impl<L: CalcNodeLeaf> CalcNode<L> { return Err(()); } - if min.is_nan() { + if min.is_nan()? { return Ok(min); } - if center.is_nan() { + if center.is_nan()? { return Ok(center); } - if max.is_nan() { + if max.is_nan()? { return Ok(max); } @@ -972,7 +994,10 @@ impl<L: CalcNodeLeaf> CalcNode<L> { return Err(()); } - let step = step.unitless_value().abs(); + let Some(step) = step.unitless_value() else { + return Err(()); + }; + let step = step.abs(); value.map(|value| { // TODO(emilio): Seems like at least a few of these @@ -1039,7 +1064,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> { } }, } - }); + })?; Ok(value) }, @@ -1055,13 +1080,15 @@ impl<L: CalcNodeLeaf> CalcNode<L> { return Err(()); } - let divisor = divisor.unitless_value(); - dividend.map(|dividend| op.apply(dividend, divisor)); + let Some(divisor) = divisor.unitless_value() else { + return Err(()); + }; + dividend.map(|dividend| op.apply(dividend, divisor))?; Ok(dividend) }, Self::Hypot(children) => { let mut result = children[0].resolve_internal(leaf_to_output_fn)?; - result.map(|v| v.powi(2)); + result.map(|v| v.powi(2))?; for child in children.iter().skip(1) { let child_value = child.resolve_internal(leaf_to_output_fn)?; @@ -1070,45 +1097,48 @@ impl<L: CalcNodeLeaf> CalcNode<L> { return Err(()); } - result.map(|v| v + child_value.unitless_value().powi(2)); + let Some(child_value) = child_value.unitless_value() else { + return Err(()); + }; + result.map(|v| v + child_value.powi(2))?; } - result.map(|v| v.sqrt()); + result.map(|v| v.sqrt())?; Ok(result) }, Self::Abs(ref c) => { let mut result = c.resolve_internal(leaf_to_output_fn)?; - result.map(|v| v.abs()); + result.map(|v| v.abs())?; Ok(result) }, Self::Sign(ref c) => { let result = c.resolve_internal(leaf_to_output_fn)?; - Ok(L::sign_from(&result)) + Ok(L::sign_from(&result)?) }, } } - fn is_negative_leaf(&self) -> bool { - match *self { - Self::Leaf(ref l) => l.is_negative(), + fn is_negative_leaf(&self) -> Result<bool, ()> { + Ok(match *self { + Self::Leaf(ref l) => l.is_negative()?, _ => false, - } + }) } - fn is_zero_leaf(&self) -> bool { - match *self { - Self::Leaf(ref l) => l.is_zero(), + fn is_zero_leaf(&self) -> Result<bool, ()> { + Ok(match *self { + Self::Leaf(ref l) => l.is_zero()?, _ => false, - } + }) } - fn is_infinite_leaf(&self) -> bool { - match *self { - Self::Leaf(ref l) => l.is_infinite(), + fn is_infinite_leaf(&self) -> Result<bool, ()> { + Ok(match *self { + Self::Leaf(ref l) => l.is_infinite()?, _ => false, - } + }) } /// Visits all the nodes in this calculation tree recursively, starting by @@ -1250,54 +1280,64 @@ impl<L: CalcNodeLeaf> CalcNode<L> { ref mut value, ref mut step, } => { - if step.is_zero_leaf() { - value.coerce_to_value(f32::NAN); + if value_or_stop!(step.is_zero_leaf()) { + value_or_stop!(value.coerce_to_value(f32::NAN)); replace_self_with!(&mut **value); return; } - if value.is_infinite_leaf() && step.is_infinite_leaf() { - value.coerce_to_value(f32::NAN); + if value_or_stop!(value.is_infinite_leaf()) && + value_or_stop!(step.is_infinite_leaf()) + { + value_or_stop!(value.coerce_to_value(f32::NAN)); replace_self_with!(&mut **value); return; } - if value.is_infinite_leaf() { + if value_or_stop!(value.is_infinite_leaf()) { replace_self_with!(&mut **value); return; } - if step.is_infinite_leaf() { + if value_or_stop!(step.is_infinite_leaf()) { match strategy { RoundingStrategy::Nearest | RoundingStrategy::ToZero => { - value.coerce_to_value(0.0); + value_or_stop!(value.coerce_to_value(0.0)); replace_self_with!(&mut **value); return; }, RoundingStrategy::Up => { - if !value.is_negative_leaf() && !value.is_zero_leaf() { - value.coerce_to_value(f32::INFINITY); + if !value_or_stop!(value.is_negative_leaf()) && + !value_or_stop!(value.is_zero_leaf()) + { + value_or_stop!(value.coerce_to_value(f32::INFINITY)); replace_self_with!(&mut **value); return; - } else if !value.is_negative_leaf() && value.is_zero_leaf() { + } else if !value_or_stop!(value.is_negative_leaf()) && + value_or_stop!(value.is_zero_leaf()) + { replace_self_with!(&mut **value); return; } else { - value.coerce_to_value(0.0); + value_or_stop!(value.coerce_to_value(0.0)); replace_self_with!(&mut **value); return; } }, RoundingStrategy::Down => { - if value.is_negative_leaf() && !value.is_zero_leaf() { - value.coerce_to_value(f32::INFINITY); + if value_or_stop!(value.is_negative_leaf()) && + !value_or_stop!(value.is_zero_leaf()) + { + value_or_stop!(value.coerce_to_value(f32::INFINITY)); replace_self_with!(&mut **value); return; - } else if value.is_negative_leaf() && value.is_zero_leaf() { + } else if value_or_stop!(value.is_negative_leaf()) && + value_or_stop!(value.is_zero_leaf()) + { replace_self_with!(&mut **value); return; } else { - value.coerce_to_value(0.0); + value_or_stop!(value.coerce_to_value(0.0)); replace_self_with!(&mut **value); return; } @@ -1305,17 +1345,18 @@ impl<L: CalcNodeLeaf> CalcNode<L> { } } - if step.is_negative_leaf() { + if value_or_stop!(step.is_negative_leaf()) { step.negate(); } let remainder = value_or_stop!(value.try_op(step, Rem::rem)); - if remainder.is_zero_leaf() { + if value_or_stop!(remainder.is_zero_leaf()) { replace_self_with!(&mut **value); return; } - let (mut lower_bound, mut upper_bound) = if value.is_negative_leaf() { + let (mut lower_bound, mut upper_bound) = if value_or_stop!(value.is_negative_leaf()) + { let upper_bound = value_or_stop!(value.try_op(&remainder, Sub::sub)); let lower_bound = value_or_stop!(upper_bound.try_op(&step, Sub::sub)); @@ -1348,11 +1389,11 @@ impl<L: CalcNodeLeaf> CalcNode<L> { let mut lower_diff = lower_bound.clone(); let mut upper_diff = upper_bound.clone(); - if lower_diff.is_negative_leaf() { + if value_or_stop!(lower_diff.is_negative_leaf()) { lower_diff.negate(); } - if upper_diff.is_negative_leaf() { + if value_or_stop!(upper_diff.is_negative_leaf()) { upper_diff.negate(); } @@ -1518,13 +1559,13 @@ impl<L: CalcNodeLeaf> CalcNode<L> { }, Self::Abs(ref mut child) => { if let CalcNode::Leaf(leaf) = child.as_mut() { - leaf.map(|v| v.abs()); + value_or_stop!(leaf.map(|v| v.abs())); replace_self_with!(&mut **child); } }, Self::Sign(ref mut child) => { if let CalcNode::Leaf(leaf) = child.as_mut() { - let mut result = Self::Leaf(L::sign_from(leaf)); + let mut result = Self::Leaf(value_or_stop!(L::sign_from(leaf))); replace_self_with!(&mut result); } }, @@ -1553,7 +1594,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> { // 1. If root’s child is a number (not a percentage or dimension) return the // reciprocal of the child’s value. if leaf.unit().is_empty() { - child.map(|v| 1.0 / v); + value_or_stop!(child.map(|v| 1.0 / v)); replace_self_with!(&mut **child); } }, @@ -1678,10 +1719,12 @@ impl<L: CalcNodeLeaf> CalcNode<L> { if !first { match child { Self::Leaf(l) => { - if l.is_negative() { + if let Ok(true) = l.is_negative() { dest.write_str(" - ")?; let mut negated = l.clone(); - negated.negate(); + // We can unwrap here, because we already + // checked if the value inside is negative. + negated.map(std::ops::Neg::neg).unwrap(); negated.to_css(dest)?; } else { dest.write_str(" + ")?; |