Bug 1942715: Part 3 - Remove old & now-unused anchor resolution infrastructure in CalcNode. r=firefox-style-system-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D237096
This commit is contained in:
@@ -91,9 +91,7 @@ impl<ValueType: ColorComponentType> ColorComponent<ValueType> {
|
|||||||
} else {
|
} else {
|
||||||
ValueType::units()
|
ValueType::units()
|
||||||
});
|
});
|
||||||
let node = GenericCalcNode::parse(context, input, function, allow)?;
|
let mut node = GenericCalcNode::parse(context, input, function, allow)?;
|
||||||
debug_assert!(!node.has_anchor_function, "Anchor function used for color?");
|
|
||||||
let mut node = node.node;
|
|
||||||
|
|
||||||
// TODO(tlouw): We only have to simplify the node when we have to store it, but we
|
// TODO(tlouw): We only have to simplify the node when we have to store it, but we
|
||||||
// only know if we have to store it much later when the whole color
|
// only know if we have to store it much later when the whole color
|
||||||
|
|||||||
@@ -30,10 +30,7 @@ use crate::gecko_bindings::structs::GeckoFontMetrics;
|
|||||||
use crate::logical_geometry::PhysicalSide;
|
use crate::logical_geometry::PhysicalSide;
|
||||||
use crate::values::animated::{Animate, Context as AnimatedContext, Procedure, ToAnimatedValue, ToAnimatedZero};
|
use crate::values::animated::{Animate, Context as AnimatedContext, Procedure, ToAnimatedValue, ToAnimatedZero};
|
||||||
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||||
use crate::values::generics::calc::{
|
use crate::values::generics::calc::{CalcUnits, PositivePercentageBasis};
|
||||||
AnchorPositioningResolver, CalcUnits, GenericCalcAnchorFunction, GenericCalcAnchorSizeFunction,
|
|
||||||
PositivePercentageBasis,
|
|
||||||
};
|
|
||||||
use crate::values::generics::length::AnchorResolutionResult;
|
use crate::values::generics::length::AnchorResolutionResult;
|
||||||
use crate::values::generics::{calc, NonNegative};
|
use crate::values::generics::{calc, NonNegative};
|
||||||
use crate::values::resolved::{Context as ResolvedContext, ToResolvedValue};
|
use crate::values::resolved::{Context as ResolvedContext, ToResolvedValue};
|
||||||
@@ -231,12 +228,6 @@ enum Serializable {
|
|||||||
Percentage(Percentage),
|
Percentage(Percentage),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CalcLengthPercentage> for LengthPercentage {
|
|
||||||
fn from(value: CalcLengthPercentage) -> Self {
|
|
||||||
Self::new_calc(value.node, value.clamping_mode, value.has_anchor_function)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LengthPercentage {
|
impl LengthPercentage {
|
||||||
/// 1px length value for SVG defaults
|
/// 1px length value for SVG defaults
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -250,14 +241,11 @@ impl LengthPercentage {
|
|||||||
Self::new_percent(Percentage::zero())
|
Self::new_percent(Percentage::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_calc_node(&self) -> (CalcNode, bool) {
|
fn to_calc_node(&self) -> CalcNode {
|
||||||
match self.unpack() {
|
match self.unpack() {
|
||||||
Unpacked::Length(l) => (CalcNode::Leaf(CalcLengthPercentageLeaf::Length(l)), false),
|
Unpacked::Length(l) => CalcNode::Leaf(CalcLengthPercentageLeaf::Length(l)),
|
||||||
Unpacked::Percentage(p) => (
|
Unpacked::Percentage(p) => CalcNode::Leaf(CalcLengthPercentageLeaf::Percentage(p)),
|
||||||
CalcNode::Leaf(CalcLengthPercentageLeaf::Percentage(p)),
|
Unpacked::Calc(p) => p.node.clone(),
|
||||||
false,
|
|
||||||
),
|
|
||||||
Unpacked::Calc(p) => (p.node.clone(), p.has_anchor_function),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,9 +255,10 @@ impl LengthPercentage {
|
|||||||
Unpacked::Percentage(p) => Self::new_percent(p),
|
Unpacked::Percentage(p) => Self::new_percent(p),
|
||||||
Unpacked::Calc(lp) => Self::new_calc_unchecked(Box::new(CalcLengthPercentage {
|
Unpacked::Calc(lp) => Self::new_calc_unchecked(Box::new(CalcLengthPercentage {
|
||||||
clamping_mode: lp.clamping_mode,
|
clamping_mode: lp.clamping_mode,
|
||||||
has_anchor_function: lp.has_anchor_function,
|
|
||||||
node: lp.node.map_leaves(|leaf| match *leaf {
|
node: lp.node.map_leaves(|leaf| match *leaf {
|
||||||
CalcLengthPercentageLeaf::Length(ref l) => CalcLengthPercentageLeaf::Length(map_fn(*l)),
|
CalcLengthPercentageLeaf::Length(ref l) => {
|
||||||
|
CalcLengthPercentageLeaf::Length(map_fn(*l))
|
||||||
|
},
|
||||||
ref l => l.clone(),
|
ref l => l.clone(),
|
||||||
}),
|
}),
|
||||||
})),
|
})),
|
||||||
@@ -307,7 +296,7 @@ impl LengthPercentage {
|
|||||||
pub fn hundred_percent_minus(v: Self, clamping_mode: AllowedNumericType) -> Self {
|
pub fn hundred_percent_minus(v: Self, clamping_mode: AllowedNumericType) -> Self {
|
||||||
// TODO: This could in theory take ownership of the calc node in `v` if
|
// TODO: This could in theory take ownership of the calc node in `v` if
|
||||||
// possible instead of cloning.
|
// possible instead of cloning.
|
||||||
let (mut node, has_anchor_function) = v.to_calc_node();
|
let mut node = v.to_calc_node();
|
||||||
node.negate();
|
node.negate();
|
||||||
|
|
||||||
let new_node = CalcNode::Sum(
|
let new_node = CalcNode::Sum(
|
||||||
@@ -318,7 +307,7 @@ impl LengthPercentage {
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Self::new_calc(new_node, clamping_mode, has_anchor_function)
|
Self::new_calc(new_node, clamping_mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given a list of `LengthPercentage` values, construct the value representing
|
/// Given a list of `LengthPercentage` values, construct the value representing
|
||||||
@@ -328,38 +317,18 @@ impl LengthPercentage {
|
|||||||
Percentage::hundred(),
|
Percentage::hundred(),
|
||||||
))];
|
))];
|
||||||
|
|
||||||
let mut has_anchor_function = false;
|
|
||||||
for lp in list.iter() {
|
for lp in list.iter() {
|
||||||
let (mut node, node_has_anchor_function) = lp.to_calc_node();
|
let mut node = lp.to_calc_node();
|
||||||
has_anchor_function |= node_has_anchor_function;
|
|
||||||
node.negate();
|
node.negate();
|
||||||
new_list.push(node)
|
new_list.push(node)
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::new_calc(
|
Self::new_calc(CalcNode::Sum(new_list.into()), clamping_mode)
|
||||||
CalcNode::Sum(new_list.into()),
|
|
||||||
clamping_mode,
|
|
||||||
has_anchor_function,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a new `calc()` value from `CalcLengthPercentage`.
|
|
||||||
#[inline]
|
|
||||||
pub fn new_calc_from(calc_length_percentage: CalcLengthPercentage) -> Self {
|
|
||||||
Self::new_calc(
|
|
||||||
calc_length_percentage.node,
|
|
||||||
calc_length_percentage.clamping_mode,
|
|
||||||
calc_length_percentage.has_anchor_function,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a `calc()` value.
|
/// Constructs a `calc()` value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new_calc(
|
pub fn new_calc(mut node: CalcNode, clamping_mode: AllowedNumericType) -> Self {
|
||||||
mut node: CalcNode,
|
|
||||||
clamping_mode: AllowedNumericType,
|
|
||||||
has_anchor_function: bool,
|
|
||||||
) -> Self {
|
|
||||||
node.simplify_and_sort();
|
node.simplify_and_sort();
|
||||||
|
|
||||||
match node {
|
match node {
|
||||||
@@ -383,7 +352,6 @@ impl LengthPercentage {
|
|||||||
_ => Self::new_calc_unchecked(Box::new(CalcLengthPercentage {
|
_ => Self::new_calc_unchecked(Box::new(CalcLengthPercentage {
|
||||||
clamping_mode,
|
clamping_mode,
|
||||||
node,
|
node,
|
||||||
has_anchor_function,
|
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -918,11 +886,6 @@ impl calc::CalcNodeLeaf for CalcLengthPercentageLeaf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computed `anchor()` function in math functions.
|
|
||||||
pub type CalcAnchorFunction = GenericCalcAnchorFunction<CalcLengthPercentageLeaf>;
|
|
||||||
/// Computed `anchor-size()` function in math functions.
|
|
||||||
pub type CalcAnchorSizeFunction = GenericCalcAnchorSizeFunction<CalcLengthPercentageLeaf>;
|
|
||||||
|
|
||||||
/// The computed version of a calc() node for `<length-percentage>` values.
|
/// The computed version of a calc() node for `<length-percentage>` values.
|
||||||
pub type CalcNode = calc::GenericCalcNode<CalcLengthPercentageLeaf>;
|
pub type CalcNode = calc::GenericCalcNode<CalcLengthPercentageLeaf>;
|
||||||
|
|
||||||
@@ -935,10 +898,6 @@ pub struct CalcLengthPercentage {
|
|||||||
#[animation(constant)]
|
#[animation(constant)]
|
||||||
#[css(skip)]
|
#[css(skip)]
|
||||||
clamping_mode: AllowedNumericType,
|
clamping_mode: AllowedNumericType,
|
||||||
/// See documentation for field of the same name in `specified::CalcLengthPercentage`.
|
|
||||||
#[animation(constant)]
|
|
||||||
#[css(skip)]
|
|
||||||
has_anchor_function: bool,
|
|
||||||
node: CalcNode,
|
node: CalcNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1109,56 +1068,6 @@ impl CalcLengthPercentage {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolves anchor positioning functions. This is separate from percentage length resolution, as
|
|
||||||
/// it's valid to ask "Is a given inset auto?" without having to resolve the full length value.
|
|
||||||
/// Note(dshin): When interleaving is implemented, and if the anchor function resolves to a percentage
|
|
||||||
/// fallback value, percentage values probably be left as-is, for animation.
|
|
||||||
#[inline]
|
|
||||||
pub fn resolve_anchor_functions(
|
|
||||||
&self,
|
|
||||||
side: PhysicalSide,
|
|
||||||
prop: PositionProperty,
|
|
||||||
) -> Result<Self, ()> {
|
|
||||||
let result = self.node.resolve_anchor(side, prop, &Resolver)?;
|
|
||||||
Ok(Self {
|
|
||||||
clamping_mode: self.clamping_mode,
|
|
||||||
// TODO(dshin): When the interleaving is implemented, we need to mark anchor-resolved
|
|
||||||
// values somehow so that we know this value need to be animated when the anchor element or
|
|
||||||
// the absolute containing block is changed.
|
|
||||||
has_anchor_function: false,
|
|
||||||
node: result,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Resolver;
|
|
||||||
|
|
||||||
impl AnchorPositioningResolver<CalcLengthPercentageLeaf> for Resolver {
|
|
||||||
fn resolve_anchor(
|
|
||||||
&self,
|
|
||||||
f: &CalcAnchorFunction,
|
|
||||||
side: PhysicalSide,
|
|
||||||
position: PositionProperty,
|
|
||||||
) -> Result<CalcNode, ()> {
|
|
||||||
match f.resolve(side, position) {
|
|
||||||
AnchorResolutionResult::Resolved(v) => Ok(*v),
|
|
||||||
AnchorResolutionResult::Fallback(v) => Ok(*v.clone()),
|
|
||||||
AnchorResolutionResult::Invalid => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve_anchor_size(
|
|
||||||
&self,
|
|
||||||
f: &CalcAnchorSizeFunction,
|
|
||||||
position: PositionProperty,
|
|
||||||
) -> Result<CalcNode, ()> {
|
|
||||||
match f.resolve(position) {
|
|
||||||
AnchorResolutionResult::Resolved(v) => Ok(*v),
|
|
||||||
AnchorResolutionResult::Fallback(v) => Ok(*v.clone()),
|
|
||||||
AnchorResolutionResult::Invalid => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(emilio): We don't compare `clamping_mode` since we want to preserve the
|
// NOTE(emilio): We don't compare `clamping_mode` since we want to preserve the
|
||||||
@@ -1210,7 +1119,7 @@ impl specified::CalcLengthPercentage {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
LengthPercentage::new_calc(node, self.clamping_mode, self.has_anchor_function)
|
LengthPercentage::new_calc(node, self.clamping_mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute font-size or line-height taking into account text-zoom if necessary.
|
/// Compute font-size or line-height taking into account text-zoom if necessary.
|
||||||
@@ -1289,7 +1198,6 @@ impl specified::CalcLengthPercentage {
|
|||||||
CalcLengthPercentageLeaf::Percentage(ref p) => Leaf::Percentage(p.0),
|
CalcLengthPercentageLeaf::Percentage(ref p) => Leaf::Percentage(p.0),
|
||||||
CalcLengthPercentageLeaf::Number(n) => Leaf::Number(*n),
|
CalcLengthPercentageLeaf::Number(n) => Leaf::Number(*n),
|
||||||
}),
|
}),
|
||||||
has_anchor_function: computed.has_anchor_function,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1320,15 +1228,12 @@ impl Animate for LengthPercentage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (l, r) = procedure.weights();
|
let (l, r) = procedure.weights();
|
||||||
let (one, one_has_anchor_function) = self.to_calc_node();
|
let one = product_with(self.to_calc_node(), l as f32);
|
||||||
let (other, other_has_anchor_function) = other.to_calc_node();
|
let other = product_with(other.to_calc_node(), r as f32);
|
||||||
let one = product_with(one, l as f32);
|
|
||||||
let other = product_with(other, r as f32);
|
|
||||||
|
|
||||||
Self::new_calc(
|
Self::new_calc(
|
||||||
CalcNode::Sum(vec![one, other].into()),
|
CalcNode::Sum(vec![one, other].into()),
|
||||||
AllowedNumericType::All,
|
AllowedNumericType::All,
|
||||||
one_has_anchor_function || other_has_anchor_function,
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
//!
|
//!
|
||||||
//! [calc]: https://drafts.csswg.org/css-values/#calc-notation
|
//! [calc]: https://drafts.csswg.org/css-values/#calc-notation
|
||||||
|
|
||||||
use crate::logical_geometry::PhysicalSide;
|
|
||||||
use crate::values::generics::box_::PositionProperty;
|
|
||||||
use crate::values::generics::length::GenericAnchorSizeFunction;
|
use crate::values::generics::length::GenericAnchorSizeFunction;
|
||||||
use crate::values::generics::position::{AnchorSide, GenericAnchorFunction};
|
use crate::values::generics::position::{AnchorSide, GenericAnchorFunction};
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
@@ -442,24 +440,6 @@ enum ArgumentLevel {
|
|||||||
Nested,
|
Nested,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for resolving anchor positioning functions in math functions.
|
|
||||||
pub trait AnchorPositioningResolver<L: CalcNodeLeaf> {
|
|
||||||
/// Resolve `anchor()` function to a value.
|
|
||||||
fn resolve_anchor(
|
|
||||||
&self,
|
|
||||||
f: &GenericCalcAnchorFunction<L>,
|
|
||||||
side: PhysicalSide,
|
|
||||||
position: PositionProperty,
|
|
||||||
) -> Result<GenericCalcNode<L>, ()>;
|
|
||||||
|
|
||||||
/// Resolve `anchor-size()` function to a value.
|
|
||||||
fn resolve_anchor_size(
|
|
||||||
&self,
|
|
||||||
f: &GenericCalcAnchorSizeFunction<L>,
|
|
||||||
position: PositionProperty,
|
|
||||||
) -> Result<GenericCalcNode<L>, ()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<L: CalcNodeLeaf> CalcNode<L> {
|
impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||||
/// Create a dummy CalcNode that can be used to do replacements of other nodes.
|
/// Create a dummy CalcNode that can be used to do replacements of other nodes.
|
||||||
fn dummy() -> Self {
|
fn dummy() -> Self {
|
||||||
@@ -1214,135 +1194,6 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve anchor functions, returning the reduced node as a result of it.
|
|
||||||
/// This returns a cloned node, so callers should ideally keep track of
|
|
||||||
/// the node's usage of anchor functions and skip calling this.
|
|
||||||
/// Returns `Err(())` if the anchor function used resolves to an invalid
|
|
||||||
/// anchor and there is no fallback available.
|
|
||||||
pub fn resolve_anchor<R>(
|
|
||||||
&self,
|
|
||||||
side: PhysicalSide,
|
|
||||||
position_property: PositionProperty,
|
|
||||||
anchor_function_resolver: &R,
|
|
||||||
) -> Result<Self, ()>
|
|
||||||
where
|
|
||||||
R: AnchorPositioningResolver<L>,
|
|
||||||
{
|
|
||||||
fn resolve_anchor_internal<L: CalcNodeLeaf, R>(
|
|
||||||
node: &mut CalcNode<L>,
|
|
||||||
side: PhysicalSide,
|
|
||||||
position_property: PositionProperty,
|
|
||||||
anchor_positioning_resolver: &R,
|
|
||||||
) -> Result<(), ()>
|
|
||||||
where
|
|
||||||
R: AnchorPositioningResolver<L>,
|
|
||||||
{
|
|
||||||
match node {
|
|
||||||
CalcNode::Leaf(_) => Ok(()),
|
|
||||||
CalcNode::Negate(child) |
|
|
||||||
CalcNode::Invert(child) |
|
|
||||||
CalcNode::Abs(child) |
|
|
||||||
CalcNode::Sign(child) => resolve_anchor_internal(
|
|
||||||
child,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
),
|
|
||||||
CalcNode::Sum(children) |
|
|
||||||
CalcNode::Product(children) |
|
|
||||||
CalcNode::MinMax(children, _) |
|
|
||||||
CalcNode::Hypot(children) => {
|
|
||||||
for child in children.iter_mut() {
|
|
||||||
resolve_anchor_internal(
|
|
||||||
child,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
CalcNode::Clamp { min, center, max } => {
|
|
||||||
resolve_anchor_internal(
|
|
||||||
min,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)?;
|
|
||||||
resolve_anchor_internal(
|
|
||||||
center,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)?;
|
|
||||||
resolve_anchor_internal(
|
|
||||||
max,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
CalcNode::Round {
|
|
||||||
value,
|
|
||||||
step,
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
resolve_anchor_internal(
|
|
||||||
value,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)?;
|
|
||||||
resolve_anchor_internal(
|
|
||||||
step,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
CalcNode::ModRem {
|
|
||||||
dividend,
|
|
||||||
divisor,
|
|
||||||
op: _,
|
|
||||||
} => {
|
|
||||||
resolve_anchor_internal(
|
|
||||||
dividend,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)?;
|
|
||||||
resolve_anchor_internal(
|
|
||||||
divisor,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_positioning_resolver,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
CalcNode::Anchor(f) => {
|
|
||||||
*node =
|
|
||||||
anchor_positioning_resolver.resolve_anchor(f, side, position_property)?;
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
CalcNode::AnchorSize(f) => {
|
|
||||||
*node =
|
|
||||||
anchor_positioning_resolver.resolve_anchor_size(f, position_property)?;
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(dshin, Bug 1924225): When interleaving for anchor positioning happens, we can
|
|
||||||
// mutate the node in place.
|
|
||||||
let mut cloned = self.clone();
|
|
||||||
resolve_anchor_internal(
|
|
||||||
&mut cloned,
|
|
||||||
side,
|
|
||||||
position_property,
|
|
||||||
anchor_function_resolver,
|
|
||||||
)?;
|
|
||||||
Ok(cloned)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_negative_leaf(&self) -> Result<bool, ()> {
|
fn is_negative_leaf(&self) -> Result<bool, ()> {
|
||||||
Ok(match *self {
|
Ok(match *self {
|
||||||
Self::Leaf(ref l) => l.is_negative()?,
|
Self::Leaf(ref l) => l.is_negative()?,
|
||||||
|
|||||||
@@ -129,11 +129,6 @@ impl ToCss for Leaf {
|
|||||||
pub struct CalcLengthPercentage {
|
pub struct CalcLengthPercentage {
|
||||||
#[css(skip)]
|
#[css(skip)]
|
||||||
pub clamping_mode: AllowedNumericType,
|
pub clamping_mode: AllowedNumericType,
|
||||||
/// Flag indicating if any anchor function is part of this node.
|
|
||||||
/// This can be used to skip the traversal of calc node tree for
|
|
||||||
/// math functions not using any anchor function.
|
|
||||||
#[css(skip)]
|
|
||||||
pub has_anchor_function: bool,
|
|
||||||
pub node: CalcNode,
|
pub node: CalcNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,9 +489,11 @@ impl AnchorSide<Box<CalcNode>> {
|
|||||||
if let Ok(k) = input.try_parse(|i| AnchorSideKeyword::parse(i)) {
|
if let Ok(k) = input.try_parse(|i| AnchorSideKeyword::parse(i)) {
|
||||||
return Ok(Self::Keyword(k));
|
return Ok(Self::Keyword(k));
|
||||||
}
|
}
|
||||||
Ok(Self::Percentage(Box::new(
|
Ok(Self::Percentage(Box::new(CalcNode::parse_argument(
|
||||||
CalcNode::parse_argument(context, input, AllowParse::new(CalcUnits::PERCENTAGE))?.node,
|
context,
|
||||||
)))
|
input,
|
||||||
|
AllowParse::new(CalcUnits::PERCENTAGE),
|
||||||
|
)?)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -523,8 +520,7 @@ impl GenericAnchorFunction<Box<CalcNode>, Box<CalcNode>> {
|
|||||||
context,
|
context,
|
||||||
i,
|
i,
|
||||||
AllowParse::new(CalcUnits::LENGTH_PERCENTAGE),
|
AllowParse::new(CalcUnits::LENGTH_PERCENTAGE),
|
||||||
)?
|
)?;
|
||||||
.node;
|
|
||||||
Ok::<Box<CalcNode>, ParseError<'i>>(Box::new(node))
|
Ok::<Box<CalcNode>, ParseError<'i>>(Box::new(node))
|
||||||
})
|
})
|
||||||
.ok();
|
.ok();
|
||||||
@@ -547,7 +543,7 @@ impl GenericAnchorSizeFunction<Box<CalcNode>> {
|
|||||||
}
|
}
|
||||||
GenericAnchorSizeFunction::parse_inner(context, input, |i| {
|
GenericAnchorSizeFunction::parse_inner(context, input, |i| {
|
||||||
CalcNode::parse_argument(context, i, AllowParse::new(CalcUnits::LENGTH_PERCENTAGE))
|
CalcNode::parse_argument(context, i, AllowParse::new(CalcUnits::LENGTH_PERCENTAGE))
|
||||||
.map(|r| Box::new(r.node))
|
.map(|r| Box::new(r))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -559,73 +555,6 @@ pub type CalcAnchorSizeFunction = generic::GenericCalcAnchorSizeFunction<Leaf>;
|
|||||||
|
|
||||||
/// A calc node representation for specified values.
|
/// A calc node representation for specified values.
|
||||||
pub type CalcNode = generic::GenericCalcNode<Leaf>;
|
pub type CalcNode = generic::GenericCalcNode<Leaf>;
|
||||||
|
|
||||||
/// Result of parsing the calc node.
|
|
||||||
pub struct ParsedCalcNode {
|
|
||||||
/// The parsed calc node.
|
|
||||||
pub node: CalcNode,
|
|
||||||
/// See documentation for the field of the same name in `CalcLengthPercentage`.
|
|
||||||
pub has_anchor_function: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParsedCalcNode {
|
|
||||||
#[inline]
|
|
||||||
fn new(node: CalcNode, has_anchor_function: bool) -> Self {
|
|
||||||
Self {
|
|
||||||
node,
|
|
||||||
has_anchor_function,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn into_length_or_percentage(
|
|
||||||
self,
|
|
||||||
clamping_mode: AllowedNumericType,
|
|
||||||
) -> Result<CalcLengthPercentage, ()> {
|
|
||||||
self.node
|
|
||||||
.into_length_or_percentage(clamping_mode, self.has_anchor_function)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_time(&self, clamping_mode: Option<AllowedNumericType>) -> Result<Time, ()> {
|
|
||||||
debug_assert!(!self.has_anchor_function, "Anchor function used for time?");
|
|
||||||
self.node.to_time(clamping_mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_resolution(&self) -> Result<Resolution, ()> {
|
|
||||||
debug_assert!(
|
|
||||||
!self.has_anchor_function,
|
|
||||||
"Anchor function used for resolution?"
|
|
||||||
);
|
|
||||||
self.node.to_resolution()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_angle(&self) -> Result<Angle, ()> {
|
|
||||||
debug_assert!(!self.has_anchor_function, "Anchor function used for angle?");
|
|
||||||
self.node.to_angle()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_number(&self) -> Result<CSSFloat, ()> {
|
|
||||||
debug_assert!(
|
|
||||||
!self.has_anchor_function,
|
|
||||||
"Anchor function used for number?"
|
|
||||||
);
|
|
||||||
self.node.to_number()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_percentage(&self) -> Result<CSSFloat, ()> {
|
|
||||||
debug_assert!(
|
|
||||||
!self.has_anchor_function,
|
|
||||||
"Anchor function used for percentage?"
|
|
||||||
);
|
|
||||||
self.node.to_percentage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CalcNode {
|
impl CalcNode {
|
||||||
/// Tries to parse a single element in the expression, that is, a
|
/// Tries to parse a single element in the expression, that is, a
|
||||||
/// `<length>`, `<angle>`, `<time>`, `<percentage>`, `<resolution>`, etc.
|
/// `<length>`, `<angle>`, `<time>`, `<percentage>`, `<resolution>`, etc.
|
||||||
@@ -636,44 +565,38 @@ impl CalcNode {
|
|||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
allowed: AllowParse,
|
allowed: AllowParse,
|
||||||
) -> Result<ParsedCalcNode, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let location = input.current_source_location();
|
let location = input.current_source_location();
|
||||||
match input.next()? {
|
match input.next()? {
|
||||||
&Token::Number { value, .. } => Ok(ParsedCalcNode::new(
|
&Token::Number { value, .. } => Ok(CalcNode::Leaf(Leaf::Number(value))),
|
||||||
CalcNode::Leaf(Leaf::Number(value)),
|
|
||||||
false,
|
|
||||||
)),
|
|
||||||
&Token::Dimension {
|
&Token::Dimension {
|
||||||
value, ref unit, ..
|
value, ref unit, ..
|
||||||
} => {
|
} => {
|
||||||
if allowed.includes(CalcUnits::LENGTH) {
|
if allowed.includes(CalcUnits::LENGTH) {
|
||||||
if let Ok(l) = NoCalcLength::parse_dimension(context, value, unit) {
|
if let Ok(l) = NoCalcLength::parse_dimension(context, value, unit) {
|
||||||
return Ok(ParsedCalcNode::new(CalcNode::Leaf(Leaf::Length(l)), false));
|
return Ok(CalcNode::Leaf(Leaf::Length(l)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allowed.includes(CalcUnits::ANGLE) {
|
if allowed.includes(CalcUnits::ANGLE) {
|
||||||
if let Ok(a) = Angle::parse_dimension(value, unit, /* from_calc = */ true) {
|
if let Ok(a) = Angle::parse_dimension(value, unit, /* from_calc = */ true) {
|
||||||
return Ok(ParsedCalcNode::new(CalcNode::Leaf(Leaf::Angle(a)), false));
|
return Ok(CalcNode::Leaf(Leaf::Angle(a)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allowed.includes(CalcUnits::TIME) {
|
if allowed.includes(CalcUnits::TIME) {
|
||||||
if let Ok(t) = Time::parse_dimension(value, unit) {
|
if let Ok(t) = Time::parse_dimension(value, unit) {
|
||||||
return Ok(ParsedCalcNode::new(CalcNode::Leaf(Leaf::Time(t)), false));
|
return Ok(CalcNode::Leaf(Leaf::Time(t)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if allowed.includes(CalcUnits::RESOLUTION) {
|
if allowed.includes(CalcUnits::RESOLUTION) {
|
||||||
if let Ok(t) = Resolution::parse_dimension(value, unit) {
|
if let Ok(t) = Resolution::parse_dimension(value, unit) {
|
||||||
return Ok(ParsedCalcNode::new(
|
return Ok(CalcNode::Leaf(Leaf::Resolution(t)));
|
||||||
CalcNode::Leaf(Leaf::Resolution(t)),
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
},
|
},
|
||||||
&Token::Percentage { unit_value, .. } if allowed.includes(CalcUnits::PERCENTAGE) => Ok(
|
&Token::Percentage { unit_value, .. } if allowed.includes(CalcUnits::PERCENTAGE) => {
|
||||||
ParsedCalcNode::new(CalcNode::Leaf(Leaf::Percentage(unit_value)), false),
|
Ok(CalcNode::Leaf(Leaf::Percentage(unit_value)))
|
||||||
),
|
},
|
||||||
&Token::ParenthesisBlock => {
|
&Token::ParenthesisBlock => {
|
||||||
input.parse_nested_block(|input| CalcNode::parse_argument(context, input, allowed))
|
input.parse_nested_block(|input| CalcNode::parse_argument(context, input, allowed))
|
||||||
},
|
},
|
||||||
@@ -684,10 +607,7 @@ impl CalcNode {
|
|||||||
name.eq_ignore_ascii_case("anchor") =>
|
name.eq_ignore_ascii_case("anchor") =>
|
||||||
{
|
{
|
||||||
let anchor_function = GenericAnchorFunction::parse_in_calc(context, input)?;
|
let anchor_function = GenericAnchorFunction::parse_in_calc(context, input)?;
|
||||||
Ok(ParsedCalcNode::new(
|
Ok(CalcNode::Anchor(Box::new(anchor_function)))
|
||||||
CalcNode::Anchor(Box::new(anchor_function)),
|
|
||||||
true,
|
|
||||||
))
|
|
||||||
},
|
},
|
||||||
&Token::Function(ref name)
|
&Token::Function(ref name)
|
||||||
if allowed
|
if allowed
|
||||||
@@ -697,10 +617,7 @@ impl CalcNode {
|
|||||||
{
|
{
|
||||||
let anchor_size_function =
|
let anchor_size_function =
|
||||||
GenericAnchorSizeFunction::parse_in_calc(context, input)?;
|
GenericAnchorSizeFunction::parse_in_calc(context, input)?;
|
||||||
Ok(ParsedCalcNode::new(
|
Ok(CalcNode::AnchorSize(Box::new(anchor_size_function)))
|
||||||
CalcNode::AnchorSize(Box::new(anchor_size_function)),
|
|
||||||
true,
|
|
||||||
))
|
|
||||||
},
|
},
|
||||||
&Token::Function(ref name) => {
|
&Token::Function(ref name) => {
|
||||||
let function = CalcNode::math_function(context, name, location)?;
|
let function = CalcNode::math_function(context, name, location)?;
|
||||||
@@ -730,7 +647,7 @@ impl CalcNode {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
Ok(ParsedCalcNode::new(CalcNode::Leaf(leaf), false))
|
Ok(CalcNode::Leaf(leaf))
|
||||||
},
|
},
|
||||||
t => Err(location.new_unexpected_token_error(t.clone())),
|
t => Err(location.new_unexpected_token_error(t.clone())),
|
||||||
}
|
}
|
||||||
@@ -744,7 +661,7 @@ impl CalcNode {
|
|||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
function: MathFunction,
|
function: MathFunction,
|
||||||
allowed: AllowParse,
|
allowed: AllowParse,
|
||||||
) -> Result<ParsedCalcNode, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
input.parse_nested_block(|input| {
|
input.parse_nested_block(|input| {
|
||||||
match function {
|
match function {
|
||||||
MathFunction::Calc => Self::parse_argument(context, input, allowed),
|
MathFunction::Calc => Self::parse_argument(context, input, allowed),
|
||||||
@@ -754,15 +671,10 @@ impl CalcNode {
|
|||||||
let center = Self::parse_argument(context, input, allowed)?;
|
let center = Self::parse_argument(context, input, allowed)?;
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
let max = Self::parse_argument(context, input, allowed)?;
|
let max = Self::parse_argument(context, input, allowed)?;
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Clamp {
|
||||||
node: Self::Clamp {
|
min: Box::new(min),
|
||||||
min: Box::new(min.node),
|
center: Box::new(center),
|
||||||
center: Box::new(center.node),
|
max: Box::new(max),
|
||||||
max: Box::new(max.node),
|
|
||||||
},
|
|
||||||
has_anchor_function: min.has_anchor_function ||
|
|
||||||
center.has_anchor_function ||
|
|
||||||
max.has_anchor_function,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
MathFunction::Round => {
|
MathFunction::Round => {
|
||||||
@@ -794,17 +706,12 @@ impl CalcNode {
|
|||||||
Self::parse_argument(context, input, allowed)
|
Self::parse_argument(context, input, allowed)
|
||||||
});
|
});
|
||||||
|
|
||||||
let (step, step_has_anchor_function) = step
|
let step = step.unwrap_or(Self::Leaf(Leaf::Number(1.0)));
|
||||||
.map(|s| (s.node, s.has_anchor_function))
|
|
||||||
.unwrap_or((Self::Leaf(Leaf::Number(1.0)), false));
|
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Round {
|
||||||
node: Self::Round {
|
strategy: strategy.unwrap_or(RoundingStrategy::Nearest),
|
||||||
strategy: strategy.unwrap_or(RoundingStrategy::Nearest),
|
value: Box::new(value),
|
||||||
value: Box::new(value.node),
|
step: Box::new(step),
|
||||||
step: Box::new(step),
|
|
||||||
},
|
|
||||||
has_anchor_function: value.has_anchor_function || step_has_anchor_function,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
MathFunction::Mod | MathFunction::Rem => {
|
MathFunction::Mod | MathFunction::Rem => {
|
||||||
@@ -817,14 +724,10 @@ impl CalcNode {
|
|||||||
MathFunction::Rem => ModRemOp::Rem,
|
MathFunction::Rem => ModRemOp::Rem,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::ModRem {
|
||||||
node: Self::ModRem {
|
dividend: Box::new(dividend),
|
||||||
dividend: Box::new(dividend.node),
|
divisor: Box::new(divisor),
|
||||||
divisor: Box::new(divisor.node),
|
op,
|
||||||
op,
|
|
||||||
},
|
|
||||||
has_anchor_function: dividend.has_anchor_function ||
|
|
||||||
divisor.has_anchor_function,
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
MathFunction::Min | MathFunction::Max => {
|
MathFunction::Min | MathFunction::Max => {
|
||||||
@@ -833,11 +736,9 @@ impl CalcNode {
|
|||||||
//
|
//
|
||||||
// Consider adding an API to cssparser to specify the
|
// Consider adding an API to cssparser to specify the
|
||||||
// initial vector capacity?
|
// initial vector capacity?
|
||||||
let mut has_anchor_function = false;
|
|
||||||
let arguments = input.parse_comma_separated(|input| {
|
let arguments = input.parse_comma_separated(|input| {
|
||||||
let result = Self::parse_argument(context, input, allowed)?;
|
let result = Self::parse_argument(context, input, allowed)?;
|
||||||
has_anchor_function |= result.has_anchor_function;
|
Ok(result)
|
||||||
Ok(result.node)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let op = match function {
|
let op = match function {
|
||||||
@@ -846,10 +747,7 @@ impl CalcNode {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::MinMax(arguments.into(), op))
|
||||||
node: Self::MinMax(arguments.into(), op),
|
|
||||||
has_anchor_function,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Sin | MathFunction::Cos | MathFunction::Tan => {
|
MathFunction::Sin | MathFunction::Cos | MathFunction::Tan => {
|
||||||
let a = Self::parse_angle_argument(context, input)?;
|
let a = Self::parse_angle_argument(context, input)?;
|
||||||
@@ -863,10 +761,7 @@ impl CalcNode {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Leaf(Leaf::Number(number)))
|
||||||
node: Self::Leaf(Leaf::Number(number)),
|
|
||||||
has_anchor_function: false,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Asin | MathFunction::Acos | MathFunction::Atan => {
|
MathFunction::Asin | MathFunction::Acos | MathFunction::Atan => {
|
||||||
let a = Self::parse_number_argument(context, input)?;
|
let a = Self::parse_number_argument(context, input)?;
|
||||||
@@ -880,18 +775,13 @@ impl CalcNode {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Leaf(Leaf::Angle(Angle::from_radians(radians))))
|
||||||
node: Self::Leaf(Leaf::Angle(Angle::from_radians(radians))),
|
|
||||||
has_anchor_function: false,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Atan2 => {
|
MathFunction::Atan2 => {
|
||||||
let allow_all = allowed.new_including(CalcUnits::ALL);
|
let allow_all = allowed.new_including(CalcUnits::ALL);
|
||||||
let a = Self::parse_argument(context, input, allow_all)?;
|
let a = Self::parse_argument(context, input, allow_all)?;
|
||||||
let (a, a_has_anchor_function) = (a.node, a.has_anchor_function);
|
|
||||||
input.expect_comma()?;
|
input.expect_comma()?;
|
||||||
let b = Self::parse_argument(context, input, allow_all)?;
|
let b = Self::parse_argument(context, input, allow_all)?;
|
||||||
let (b, b_has_anchor_function) = (b.node, b.has_anchor_function);
|
|
||||||
|
|
||||||
let radians = Self::try_resolve(input, || {
|
let radians = Self::try_resolve(input, || {
|
||||||
if let Ok(a) = a.to_number() {
|
if let Ok(a) = a.to_number() {
|
||||||
@@ -919,23 +809,14 @@ impl CalcNode {
|
|||||||
return Ok(a.dppx().atan2(b.dppx()));
|
return Ok(a.dppx().atan2(b.dppx()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = a.into_length_or_percentage(
|
let a = a.into_length_or_percentage(AllowedNumericType::All)?;
|
||||||
AllowedNumericType::All,
|
let b = b.into_length_or_percentage(AllowedNumericType::All)?;
|
||||||
a_has_anchor_function,
|
|
||||||
)?;
|
|
||||||
let b = b.into_length_or_percentage(
|
|
||||||
AllowedNumericType::All,
|
|
||||||
b_has_anchor_function,
|
|
||||||
)?;
|
|
||||||
let (a, b) = CalcLengthPercentage::same_unit_length_as(&a, &b).ok_or(())?;
|
let (a, b) = CalcLengthPercentage::same_unit_length_as(&a, &b).ok_or(())?;
|
||||||
|
|
||||||
Ok(a.atan2(b))
|
Ok(a.atan2(b))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Leaf(Leaf::Angle(Angle::from_radians(radians))))
|
||||||
node: Self::Leaf(Leaf::Angle(Angle::from_radians(radians))),
|
|
||||||
has_anchor_function: a_has_anchor_function || b_has_anchor_function,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Pow => {
|
MathFunction::Pow => {
|
||||||
let a = Self::parse_number_argument(context, input)?;
|
let a = Self::parse_number_argument(context, input)?;
|
||||||
@@ -944,33 +825,22 @@ impl CalcNode {
|
|||||||
|
|
||||||
let number = a.powf(b);
|
let number = a.powf(b);
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Leaf(Leaf::Number(number)))
|
||||||
node: Self::Leaf(Leaf::Number(number)),
|
|
||||||
has_anchor_function: false,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Sqrt => {
|
MathFunction::Sqrt => {
|
||||||
let a = Self::parse_number_argument(context, input)?;
|
let a = Self::parse_number_argument(context, input)?;
|
||||||
|
|
||||||
let number = a.sqrt();
|
let number = a.sqrt();
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Leaf(Leaf::Number(number)))
|
||||||
node: Self::Leaf(Leaf::Number(number)),
|
|
||||||
has_anchor_function: false,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Hypot => {
|
MathFunction::Hypot => {
|
||||||
let mut has_anchor_function = false;
|
|
||||||
let arguments = input.parse_comma_separated(|input| {
|
let arguments = input.parse_comma_separated(|input| {
|
||||||
let result = Self::parse_argument(context, input, allowed)?;
|
let result = Self::parse_argument(context, input, allowed)?;
|
||||||
has_anchor_function |= result.has_anchor_function;
|
Ok(result)
|
||||||
Ok(result.node)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Hypot(arguments.into()))
|
||||||
node: Self::Hypot(arguments.into()),
|
|
||||||
has_anchor_function,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Log => {
|
MathFunction::Log => {
|
||||||
let a = Self::parse_number_argument(context, input)?;
|
let a = Self::parse_number_argument(context, input)?;
|
||||||
@@ -986,25 +856,16 @@ impl CalcNode {
|
|||||||
None => a.ln(),
|
None => a.ln(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Leaf(Leaf::Number(number)))
|
||||||
node: Self::Leaf(Leaf::Number(number)),
|
|
||||||
has_anchor_function: false,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Exp => {
|
MathFunction::Exp => {
|
||||||
let a = Self::parse_number_argument(context, input)?;
|
let a = Self::parse_number_argument(context, input)?;
|
||||||
let number = a.exp();
|
let number = a.exp();
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Leaf(Leaf::Number(number)))
|
||||||
node: Self::Leaf(Leaf::Number(number)),
|
|
||||||
has_anchor_function: false,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Abs => {
|
MathFunction::Abs => {
|
||||||
let node = Self::parse_argument(context, input, allowed)?;
|
let node = Self::parse_argument(context, input, allowed)?;
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Abs(Box::new(node)))
|
||||||
node: Self::Abs(Box::new(node.node)),
|
|
||||||
has_anchor_function: node.has_anchor_function,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
MathFunction::Sign => {
|
MathFunction::Sign => {
|
||||||
// The sign of a percentage is dependent on the percentage basis, so if
|
// The sign of a percentage is dependent on the percentage basis, so if
|
||||||
@@ -1015,10 +876,7 @@ impl CalcNode {
|
|||||||
input,
|
input,
|
||||||
allowed.new_including(CalcUnits::ALL - CalcUnits::PERCENTAGE),
|
allowed.new_including(CalcUnits::ALL - CalcUnits::PERCENTAGE),
|
||||||
)?;
|
)?;
|
||||||
Ok(ParsedCalcNode {
|
Ok(Self::Sign(Box::new(node)))
|
||||||
node: Self::Sign(Box::new(node.node)),
|
|
||||||
has_anchor_function: node.has_anchor_function,
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -1028,8 +886,7 @@ impl CalcNode {
|
|||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<CSSFloat, ParseError<'i>> {
|
) -> Result<CSSFloat, ParseError<'i>> {
|
||||||
let argument =
|
let argument = Self::parse_argument(context, input, AllowParse::new(CalcUnits::ANGLE))?;
|
||||||
Self::parse_argument(context, input, AllowParse::new(CalcUnits::ANGLE))?.node;
|
|
||||||
argument
|
argument
|
||||||
.to_number()
|
.to_number()
|
||||||
.or_else(|()| Ok(argument.to_angle()?.radians()))
|
.or_else(|()| Ok(argument.to_angle()?.radians()))
|
||||||
@@ -1041,7 +898,6 @@ impl CalcNode {
|
|||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<CSSFloat, ParseError<'i>> {
|
) -> Result<CSSFloat, ParseError<'i>> {
|
||||||
Self::parse_argument(context, input, AllowParse::new(CalcUnits::empty()))?
|
Self::parse_argument(context, input, AllowParse::new(CalcUnits::empty()))?
|
||||||
.node
|
|
||||||
.to_number()
|
.to_number()
|
||||||
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
.map_err(|()| input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
}
|
}
|
||||||
@@ -1050,11 +906,10 @@ impl CalcNode {
|
|||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
allowed: AllowParse,
|
allowed: AllowParse,
|
||||||
) -> Result<ParsedCalcNode, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let mut sum = SmallVec::<[CalcNode; 1]>::new();
|
let mut sum = SmallVec::<[CalcNode; 1]>::new();
|
||||||
let first = Self::parse_product(context, input, allowed)?;
|
let first = Self::parse_product(context, input, allowed)?;
|
||||||
sum.push(first.node);
|
sum.push(first);
|
||||||
let mut has_anchor_function = first.has_anchor_function;
|
|
||||||
loop {
|
loop {
|
||||||
let start = input.state();
|
let start = input.state();
|
||||||
match input.next_including_whitespace() {
|
match input.next_including_whitespace() {
|
||||||
@@ -1065,18 +920,15 @@ impl CalcNode {
|
|||||||
match *input.next()? {
|
match *input.next()? {
|
||||||
Token::Delim('+') => {
|
Token::Delim('+') => {
|
||||||
let rhs = Self::parse_product(context, input, allowed)?;
|
let rhs = Self::parse_product(context, input, allowed)?;
|
||||||
has_anchor_function |= rhs.has_anchor_function;
|
if sum.last_mut().unwrap().try_sum_in_place(&rhs).is_err() {
|
||||||
if sum.last_mut().unwrap().try_sum_in_place(&rhs.node).is_err() {
|
sum.push(rhs);
|
||||||
// TODO(dshin): need to combine
|
|
||||||
sum.push(rhs.node);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Token::Delim('-') => {
|
Token::Delim('-') => {
|
||||||
let mut rhs = Self::parse_product(context, input, allowed)?;
|
let mut rhs = Self::parse_product(context, input, allowed)?;
|
||||||
has_anchor_function |= rhs.has_anchor_function;
|
rhs.negate();
|
||||||
rhs.node.negate();
|
if sum.last_mut().unwrap().try_sum_in_place(&rhs).is_err() {
|
||||||
if sum.last_mut().unwrap().try_sum_in_place(&rhs.node).is_err() {
|
sum.push(rhs);
|
||||||
sum.push(rhs.node);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
@@ -1092,13 +944,10 @@ impl CalcNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(if sum.len() == 1 {
|
||||||
node: if sum.len() == 1 {
|
sum.drain(..).next().unwrap()
|
||||||
sum.drain(..).next().unwrap()
|
} else {
|
||||||
} else {
|
Self::Sum(sum.into_boxed_slice().into())
|
||||||
Self::Sum(sum.into_boxed_slice().into())
|
|
||||||
},
|
|
||||||
has_anchor_function,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1115,33 +964,25 @@ impl CalcNode {
|
|||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
allowed: AllowParse,
|
allowed: AllowParse,
|
||||||
) -> Result<ParsedCalcNode, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let mut product = SmallVec::<[CalcNode; 1]>::new();
|
let mut product = SmallVec::<[CalcNode; 1]>::new();
|
||||||
let first = Self::parse_one(context, input, allowed)?;
|
let first = Self::parse_one(context, input, allowed)?;
|
||||||
product.push(first.node);
|
product.push(first);
|
||||||
let mut has_anchor_function = first.has_anchor_function;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let start = input.state();
|
let start = input.state();
|
||||||
match input.next() {
|
match input.next() {
|
||||||
Ok(&Token::Delim('*')) => {
|
Ok(&Token::Delim('*')) => {
|
||||||
let mut rhs = Self::parse_one(context, input, allowed)?;
|
let mut rhs = Self::parse_one(context, input, allowed)?;
|
||||||
has_anchor_function |= rhs.has_anchor_function;
|
|
||||||
|
|
||||||
// We can unwrap here, becuase we start the function by adding a node to
|
// We can unwrap here, becuase we start the function by adding a node to
|
||||||
// the list.
|
// the list.
|
||||||
if !product
|
if !product.last_mut().unwrap().try_product_in_place(&mut rhs) {
|
||||||
.last_mut()
|
product.push(rhs);
|
||||||
.unwrap()
|
|
||||||
.try_product_in_place(&mut rhs.node)
|
|
||||||
{
|
|
||||||
// TODO(dshin): need to combine
|
|
||||||
product.push(rhs.node);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Ok(&Token::Delim('/')) => {
|
Ok(&Token::Delim('/')) => {
|
||||||
let rhs = Self::parse_one(context, input, allowed)?;
|
let rhs = Self::parse_one(context, input, allowed)?;
|
||||||
has_anchor_function |= rhs.has_anchor_function;
|
|
||||||
|
|
||||||
enum InPlaceDivisionResult {
|
enum InPlaceDivisionResult {
|
||||||
/// The right was merged into the left.
|
/// The right was merged into the left.
|
||||||
@@ -1183,10 +1024,10 @@ impl CalcNode {
|
|||||||
// already resolve it, then merge it with the last node on the product list.
|
// already resolve it, then merge it with the last node on the product list.
|
||||||
// We can unwrap here, becuase we start the function by adding a node to
|
// We can unwrap here, becuase we start the function by adding a node to
|
||||||
// the list.
|
// the list.
|
||||||
match try_division_in_place(&mut product.last_mut().unwrap(), &rhs.node) {
|
match try_division_in_place(&mut product.last_mut().unwrap(), &rhs) {
|
||||||
InPlaceDivisionResult::Merged => {},
|
InPlaceDivisionResult::Merged => {},
|
||||||
InPlaceDivisionResult::Unchanged => {
|
InPlaceDivisionResult::Unchanged => {
|
||||||
product.push(Self::Invert(Box::new(rhs.node)))
|
product.push(Self::Invert(Box::new(rhs)))
|
||||||
},
|
},
|
||||||
InPlaceDivisionResult::Invalid => {
|
InPlaceDivisionResult::Invalid => {
|
||||||
return Err(
|
return Err(
|
||||||
@@ -1202,13 +1043,10 @@ impl CalcNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ParsedCalcNode {
|
Ok(if product.len() == 1 {
|
||||||
node: if product.len() == 1 {
|
product.drain(..).next().unwrap()
|
||||||
product.drain(..).next().unwrap()
|
} else {
|
||||||
} else {
|
Self::Product(product.into_boxed_slice().into())
|
||||||
Self::Product(product.into_boxed_slice().into())
|
|
||||||
},
|
|
||||||
has_anchor_function,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1227,7 +1065,6 @@ impl CalcNode {
|
|||||||
pub fn into_length_or_percentage(
|
pub fn into_length_or_percentage(
|
||||||
mut self,
|
mut self,
|
||||||
clamping_mode: AllowedNumericType,
|
clamping_mode: AllowedNumericType,
|
||||||
has_anchor_function: bool,
|
|
||||||
) -> Result<CalcLengthPercentage, ()> {
|
) -> Result<CalcLengthPercentage, ()> {
|
||||||
self.simplify_and_sort();
|
self.simplify_and_sort();
|
||||||
|
|
||||||
@@ -1240,7 +1077,6 @@ impl CalcNode {
|
|||||||
Ok(CalcLengthPercentage {
|
Ok(CalcLengthPercentage {
|
||||||
clamping_mode,
|
clamping_mode,
|
||||||
node: self,
|
node: self,
|
||||||
has_anchor_function,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1649,7 +1649,6 @@ impl From<Percentage> for LengthPercentage {
|
|||||||
if let Some(clamping_mode) = pc.calc_clamping_mode() {
|
if let Some(clamping_mode) = pc.calc_clamping_mode() {
|
||||||
LengthPercentage::Calc(Box::new(CalcLengthPercentage {
|
LengthPercentage::Calc(Box::new(CalcLengthPercentage {
|
||||||
clamping_mode,
|
clamping_mode,
|
||||||
has_anchor_function: false,
|
|
||||||
node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())),
|
node: CalcNode::Leaf(calc::Leaf::Percentage(pc.get())),
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
@@ -1812,11 +1811,11 @@ impl LengthPercentage {
|
|||||||
/// Returns self as specified::calc::CalcNode.
|
/// Returns self as specified::calc::CalcNode.
|
||||||
/// Note that this expect the clamping_mode is AllowedNumericType::All for Calc. The caller
|
/// Note that this expect the clamping_mode is AllowedNumericType::All for Calc. The caller
|
||||||
/// should take care about it when using this function.
|
/// should take care about it when using this function.
|
||||||
fn to_calc_node(self) -> (CalcNode, bool) {
|
fn to_calc_node(self) -> CalcNode {
|
||||||
match self {
|
match self {
|
||||||
LengthPercentage::Length(l) => (CalcNode::Leaf(calc::Leaf::Length(l)), false),
|
LengthPercentage::Length(l) => CalcNode::Leaf(calc::Leaf::Length(l)),
|
||||||
LengthPercentage::Percentage(p) => (CalcNode::Leaf(calc::Leaf::Percentage(p.0)), false),
|
LengthPercentage::Percentage(p) => CalcNode::Leaf(calc::Leaf::Percentage(p.0)),
|
||||||
LengthPercentage::Calc(p) => (p.node, p.has_anchor_function),
|
LengthPercentage::Calc(p) => p.node,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1825,14 +1824,13 @@ impl LengthPercentage {
|
|||||||
let mut sum = smallvec::SmallVec::<[CalcNode; 2]>::new();
|
let mut sum = smallvec::SmallVec::<[CalcNode; 2]>::new();
|
||||||
sum.push(CalcNode::Leaf(calc::Leaf::Percentage(1.0)));
|
sum.push(CalcNode::Leaf(calc::Leaf::Percentage(1.0)));
|
||||||
|
|
||||||
let (mut node, has_anchor_function) = self.to_calc_node();
|
let mut node = self.to_calc_node();
|
||||||
node.negate();
|
node.negate();
|
||||||
sum.push(node);
|
sum.push(node);
|
||||||
|
|
||||||
let calc = CalcNode::Sum(sum.into_boxed_slice().into());
|
let calc = CalcNode::Sum(sum.into_boxed_slice().into());
|
||||||
LengthPercentage::Calc(Box::new(
|
LengthPercentage::Calc(Box::new(
|
||||||
calc.into_length_or_percentage(clamping_mode, has_anchor_function)
|
calc.into_length_or_percentage(clamping_mode).unwrap(),
|
||||||
.unwrap(),
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9812,29 +9812,3 @@ pub extern "C" fn Servo_ResolveAnchorSizeFunction(
|
|||||||
) {
|
) {
|
||||||
*out = AnchorPositioningFunctionResolution::new(func.resolve(prop));
|
*out = AnchorPositioningFunctionResolution::new(func.resolve(prop));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Result of resolving a math function node potentially containing
|
|
||||||
/// anchor positioning function.
|
|
||||||
#[repr(u8)]
|
|
||||||
pub enum CalcAnchorPositioningFunctionResolution {
|
|
||||||
/// Anchor positioning function is used, but at least one of them
|
|
||||||
/// did not resolve to a valid reference - Property using this
|
|
||||||
/// expression is now invalid at computed time.
|
|
||||||
Invalid,
|
|
||||||
/// Anchor positioning function is used, and all of them resolved
|
|
||||||
/// to valid references, or specified a fallback.
|
|
||||||
Valid(computed::LengthPercentage),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[no_mangle]
|
|
||||||
pub extern "C" fn Servo_ResolveAnchorPositioningFunctionInCalc(
|
|
||||||
calc: &computed::length_percentage::CalcLengthPercentage,
|
|
||||||
side: PhysicalSide,
|
|
||||||
prop: PositionProperty,
|
|
||||||
out: &mut CalcAnchorPositioningFunctionResolution,
|
|
||||||
) {
|
|
||||||
*out = match calc.resolve_anchor_functions(side, prop) {
|
|
||||||
Ok(l) => CalcAnchorPositioningFunctionResolution::Valid(l.into()),
|
|
||||||
Err(_) => CalcAnchorPositioningFunctionResolution::Invalid,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user