Bug 1942715: Part 1 - Implement anchor resolution that takes the same code path as percentage resolution. r=firefox-style-system-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D237094
This commit is contained in:
@@ -111,6 +111,7 @@ impl<ValueType: ColorComponentType> ColorComponent<ValueType> {
|
|||||||
|
|
||||||
/// Resolve a [ColorComponent] into a float. None is "none".
|
/// Resolve a [ColorComponent] into a float. None is "none".
|
||||||
pub fn resolve(&self, origin_color: Option<&AbsoluteColor>) -> Result<Option<ValueType>, ()> {
|
pub fn resolve(&self, origin_color: Option<&AbsoluteColor>) -> Result<Option<ValueType>, ()> {
|
||||||
|
struct EmptyContext;
|
||||||
Ok(match self {
|
Ok(match self {
|
||||||
ColorComponent::None => None,
|
ColorComponent::None => None,
|
||||||
ColorComponent::Value(value) => Some(value.clone()),
|
ColorComponent::Value(value) => Some(value.clone()),
|
||||||
@@ -123,7 +124,7 @@ impl<ValueType: ColorComponentType> ColorComponent<ValueType> {
|
|||||||
},
|
},
|
||||||
ColorComponent::Calc(node) => {
|
ColorComponent::Calc(node) => {
|
||||||
let Ok(resolved_leaf) = node.resolve_map(
|
let Ok(resolved_leaf) = node.resolve_map(
|
||||||
|leaf| {
|
|leaf, _| {
|
||||||
Ok(match leaf {
|
Ok(match leaf {
|
||||||
Leaf::ColorComponent(channel_keyword) => match origin_color {
|
Leaf::ColorComponent(channel_keyword) => match origin_color {
|
||||||
Some(origin_color) => {
|
Some(origin_color) => {
|
||||||
@@ -136,7 +137,8 @@ impl<ValueType: ColorComponentType> ColorComponent<ValueType> {
|
|||||||
l => l.clone(),
|
l => l.clone(),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|_| Err(()),
|
|_, _| Ok(None),
|
||||||
|
&mut EmptyContext,
|
||||||
) else {
|
) else {
|
||||||
return Err(());
|
return Err(());
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ 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::{
|
||||||
AnchorPositioningResolver, GenericCalcAnchorFunction, GenericCalcAnchorSizeFunction, CalcUnits,
|
AnchorPositioningResolver, CalcUnits, GenericCalcAnchorFunction, GenericCalcAnchorSizeFunction,
|
||||||
PositivePercentageBasis,
|
PositivePercentageBasis,
|
||||||
};
|
};
|
||||||
use crate::values::generics::length::AnchorResolutionResult;
|
use crate::values::generics::length::AnchorResolutionResult;
|
||||||
@@ -492,7 +492,7 @@ impl LengthPercentage {
|
|||||||
match self.unpack() {
|
match self.unpack() {
|
||||||
Unpacked::Length(l) => l,
|
Unpacked::Length(l) => l,
|
||||||
Unpacked::Percentage(p) => (basis * p.0).normalized(),
|
Unpacked::Percentage(p) => (basis * p.0).normalized(),
|
||||||
Unpacked::Calc(ref c) => c.resolve(basis),
|
Unpacked::Calc(ref c) => c.resolve_non_anchor(basis),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +540,7 @@ impl LengthPercentage {
|
|||||||
Some(match self.unpack() {
|
Some(match self.unpack() {
|
||||||
Unpacked::Length(l) => Percentage(l.px() / basis.px()),
|
Unpacked::Length(l) => Percentage(l.px() / basis.px()),
|
||||||
Unpacked::Percentage(p) => p,
|
Unpacked::Percentage(p) => p,
|
||||||
Unpacked::Calc(ref c) => Percentage(c.resolve(basis).px() / basis.px()),
|
Unpacked::Calc(ref c) => Percentage(c.resolve_non_anchor(basis).px() / basis.px()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,41 +942,171 @@ pub struct CalcLengthPercentage {
|
|||||||
node: CalcNode,
|
node: CalcNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ResolveContext {
|
||||||
|
percentage_used: bool,
|
||||||
|
anchor_function_used: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ResolveContext {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
percentage_used: false,
|
||||||
|
anchor_function_used: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leaf_to_output(
|
||||||
|
leaf: &CalcLengthPercentageLeaf,
|
||||||
|
basis: Length,
|
||||||
|
context: &mut ResolveContext,
|
||||||
|
) -> Result<CalcLengthPercentageLeaf, ()> {
|
||||||
|
Ok(if let CalcLengthPercentageLeaf::Percentage(p) = leaf {
|
||||||
|
context.percentage_used = true;
|
||||||
|
CalcLengthPercentageLeaf::Length(Length::new(basis.px() * p.0))
|
||||||
|
} else {
|
||||||
|
leaf.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map_node(
|
||||||
|
node: &CalcNode,
|
||||||
|
basis: Length,
|
||||||
|
info: &CalcAnchorFunctionResolutionInfo,
|
||||||
|
context: &mut ResolveContext,
|
||||||
|
) -> Result<Option<CalcNode>, ()> {
|
||||||
|
match node {
|
||||||
|
CalcNode::Anchor(f) => {
|
||||||
|
context.anchor_function_used = true;
|
||||||
|
match f.resolve(info.side, info.position_property) {
|
||||||
|
AnchorResolutionResult::Invalid => return Err(()),
|
||||||
|
AnchorResolutionResult::Fallback(fb) => {
|
||||||
|
let mut inner_context = ResolveContext::default();
|
||||||
|
// TODO(dshin, bug 1923759): At least for now, fallbacks should always resolve, since they do not contain
|
||||||
|
// recursive anchor functions.
|
||||||
|
let resolved = fb
|
||||||
|
.resolve_map(
|
||||||
|
|leaf, percentage_used| leaf_to_output(leaf, basis, percentage_used),
|
||||||
|
|_, _| Ok(None),
|
||||||
|
&mut inner_context,
|
||||||
|
)
|
||||||
|
.expect("anchor() fallback should have been resolvable?");
|
||||||
|
context.percentage_used |= inner_context.percentage_used;
|
||||||
|
debug_assert!(
|
||||||
|
!inner_context.anchor_function_used,
|
||||||
|
"Nested anchor function used?"
|
||||||
|
);
|
||||||
|
Ok(Some(CalcNode::Leaf(resolved)))
|
||||||
|
},
|
||||||
|
AnchorResolutionResult::Resolved(v) => Ok(Some(*v.clone())),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CalcNode::AnchorSize(f) => {
|
||||||
|
context.anchor_function_used = true;
|
||||||
|
match f.resolve(info.position_property) {
|
||||||
|
AnchorResolutionResult::Invalid => return Err(()),
|
||||||
|
AnchorResolutionResult::Fallback(fb) => {
|
||||||
|
let mut inner_context = ResolveContext::default();
|
||||||
|
// TODO(dshin, bug 1923956): Equivalent to corresponding matching arm for `anchor()`.
|
||||||
|
let resolved = fb
|
||||||
|
.resolve_map(
|
||||||
|
|leaf, percentage_used| leaf_to_output(leaf, basis, percentage_used),
|
||||||
|
|_, _| Ok(None),
|
||||||
|
&mut inner_context,
|
||||||
|
)
|
||||||
|
.expect("anchor-size() fallbaack should have been resolvable?");
|
||||||
|
context.percentage_used |= inner_context.percentage_used;
|
||||||
|
debug_assert!(
|
||||||
|
!inner_context.anchor_function_used,
|
||||||
|
"Nested anchor function used?"
|
||||||
|
);
|
||||||
|
Ok(Some(CalcNode::Leaf(resolved)))
|
||||||
|
},
|
||||||
|
AnchorResolutionResult::Resolved(v) => Ok(Some(*v.clone())),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Information required for resolving anchor functions.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct CalcAnchorFunctionResolutionInfo {
|
||||||
|
/// Which side we're resolving anchor functions for.
|
||||||
|
/// This is only relevant for `anchor()`, which requires
|
||||||
|
/// the property using the function to be in the same axis
|
||||||
|
/// as the specified side [1].
|
||||||
|
/// [1]: https://drafts.csswg.org/css-anchor-position-1/#anchor-valid
|
||||||
|
pub side: PhysicalSide,
|
||||||
|
/// `position` property of the box for which this style is being resolved.
|
||||||
|
pub position_property: PositionProperty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CalcAnchorFunctionResolutionInfo {
|
||||||
|
fn invalid() -> Self {
|
||||||
|
Self {
|
||||||
|
// Makes anchor functions always invalid
|
||||||
|
position_property: PositionProperty::Static,
|
||||||
|
// Doesn't matter
|
||||||
|
side: PhysicalSide::Left,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Result of resolving `CalcLengthPercentage`
|
||||||
|
pub struct CalcLengthPercentageResolution {
|
||||||
|
/// The resolved length.
|
||||||
|
pub result: Length,
|
||||||
|
/// Did the resolution of this calc node require resolving percentages?
|
||||||
|
pub percentage_used: bool,
|
||||||
|
}
|
||||||
|
|
||||||
impl CalcLengthPercentage {
|
impl CalcLengthPercentage {
|
||||||
/// Resolves the percentage.
|
/// Resolves the percentage, resolving anchor functions as specified in `resolve`.
|
||||||
|
pub fn resolve_non_anchor(&self, basis: Length) -> Length {
|
||||||
|
self.resolve(basis, None)
|
||||||
|
.expect("Non-anchor calc resolution returned None")
|
||||||
|
.result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Resolves the percentage and anchor functions, if provided. Otherwise, anchor functions
|
||||||
|
/// will be resolved as invalid.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn resolve(&self, basis: Length) -> Length {
|
pub fn resolve(
|
||||||
// unwrap() is fine because the conversion below is infallible.
|
&self,
|
||||||
if let CalcLengthPercentageLeaf::Length(px) = self
|
basis: Length,
|
||||||
.node
|
anchor_resolution_info: Option<CalcAnchorFunctionResolutionInfo>,
|
||||||
.resolve_map(|leaf| {
|
) -> Option<CalcLengthPercentageResolution> {
|
||||||
Ok(if let CalcLengthPercentageLeaf::Percentage(p) = leaf {
|
let mut context = ResolveContext::default();
|
||||||
CalcLengthPercentageLeaf::Length(Length::new(basis.px() * p.0))
|
let info = anchor_resolution_info.unwrap_or(CalcAnchorFunctionResolutionInfo::invalid());
|
||||||
|
let result = self.node.resolve_map(
|
||||||
|
|leaf, context| leaf_to_output(leaf, basis, context),
|
||||||
|
|node, context| map_node(node, basis, &info, context),
|
||||||
|
&mut context,
|
||||||
|
);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(r) => match r {
|
||||||
|
CalcLengthPercentageLeaf::Length(px) => Some(CalcLengthPercentageResolution{
|
||||||
|
result: Length::new(self.clamping_mode.clamp(px.px())).normalized(),
|
||||||
|
percentage_used: context.percentage_used,
|
||||||
|
}),
|
||||||
|
_ => unreachable!("resolve_map should turn percentages to lengths, and parsing should ensure that we don't end up with a number"),
|
||||||
|
},
|
||||||
|
Err(()) => {
|
||||||
|
if anchor_resolution_info.is_some() {
|
||||||
|
None
|
||||||
} else {
|
} else {
|
||||||
leaf.clone()
|
// TODO(dshin, bug 1923959): This should be an assert; we can't do that at the moment because size properties with anchor
|
||||||
})
|
// functions in calc node end up here. For now, return an invalid-but-reasonable-enough 0.
|
||||||
}, |node| {
|
debug_assert!(context.anchor_function_used, "Anchor function not used but failed resolution?");
|
||||||
match node {
|
Some(CalcLengthPercentageResolution{
|
||||||
CalcNode::Anchor(f) => {
|
result: Length::zero(),
|
||||||
if let Some(fallback) = f.fallback.as_ref() {
|
percentage_used: false,
|
||||||
return Ok((**fallback).clone());
|
})
|
||||||
}
|
|
||||||
Ok(CalcNode::Leaf(CalcLengthPercentageLeaf::Length(Length::zero())))
|
|
||||||
},
|
|
||||||
CalcNode::AnchorSize(f) => {
|
|
||||||
if let Some(fallback) = f.fallback.as_ref() {
|
|
||||||
return Ok((**fallback).clone());
|
|
||||||
}
|
|
||||||
Ok(CalcNode::Leaf(CalcLengthPercentageLeaf::Length(Length::zero())))
|
|
||||||
}
|
|
||||||
_ => Err(()),
|
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
.unwrap()
|
|
||||||
{
|
|
||||||
Length::new(self.clamping_mode.clamp(px.px())).normalized()
|
|
||||||
} else {
|
|
||||||
unreachable!("resolve_map should turn percentages to lengths, and parsing should ensure that we don't end up with a number");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -912,41 +912,61 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
|
|
||||||
/// Resolve this node into a value.
|
/// Resolve this node into a value.
|
||||||
pub fn resolve(&self) -> Result<L, ()> {
|
pub fn resolve(&self) -> Result<L, ()> {
|
||||||
self.resolve_map(|l| Ok(l.clone()), |_| Err(()))
|
struct EmptyContext;
|
||||||
|
self.resolve_map(
|
||||||
|
|l, _| Ok(l.clone()),
|
||||||
|
|_, _| Ok(None),
|
||||||
|
&mut EmptyContext,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve this node into a value, given a function that maps the leaf values.
|
/// Resolve this node into a value, given a function that maps the leaf values.
|
||||||
pub fn resolve_map<F, NF>(&self, mut leaf_to_output_fn: F, mut node_mapping_fn: NF) -> Result<L, ()>
|
pub fn resolve_map<F, NF, C>(
|
||||||
|
&self,
|
||||||
|
mut leaf_to_output_fn: F,
|
||||||
|
mut node_mapping_fn: NF,
|
||||||
|
context: &mut C,
|
||||||
|
) -> Result<L, ()>
|
||||||
where
|
where
|
||||||
F: FnMut(&L) -> Result<L, ()>,
|
F: FnMut(&L, &mut C) -> Result<L, ()>,
|
||||||
NF: FnMut(&CalcNode<L>) -> Result<CalcNode<L>, ()>,
|
NF: FnMut(&CalcNode<L>, &mut C) -> Result<Option<CalcNode<L>>, ()>,
|
||||||
{
|
{
|
||||||
self.resolve_internal(&mut leaf_to_output_fn, &mut node_mapping_fn)
|
self.resolve_internal(&mut leaf_to_output_fn, &mut node_mapping_fn, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_internal<F, NF>(&self, leaf_to_output_fn: &mut F, node_mapping_fn: &mut NF) -> Result<L, ()>
|
fn resolve_internal<F, NF, C>(
|
||||||
|
&self,
|
||||||
|
leaf_to_output_fn: &mut F,
|
||||||
|
node_mapping_fn: &mut NF,
|
||||||
|
context: &mut C,
|
||||||
|
) -> Result<L, ()>
|
||||||
where
|
where
|
||||||
F: FnMut(&L) -> Result<L, ()>,
|
F: FnMut(&L, &mut C) -> Result<L, ()>,
|
||||||
NF: FnMut(&CalcNode<L>) -> Result<CalcNode<L>, ()>,
|
NF: FnMut(&CalcNode<L>, &mut C) -> Result<Option<CalcNode<L>>, ()>,
|
||||||
{
|
{
|
||||||
let node = node_mapping_fn(self).ok();
|
let result = node_mapping_fn(self, context)?;
|
||||||
match node.as_ref().unwrap_or(self) {
|
let node = result.as_ref().unwrap_or(self);
|
||||||
Self::Leaf(l) => leaf_to_output_fn(l),
|
match node {
|
||||||
|
Self::Leaf(l) => leaf_to_output_fn(l, context),
|
||||||
Self::Negate(child) => {
|
Self::Negate(child) => {
|
||||||
let mut result = child.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut result =
|
||||||
|
child.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
result.map(|v| v.neg())?;
|
result.map(|v| v.neg())?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
},
|
},
|
||||||
Self::Invert(child) => {
|
Self::Invert(child) => {
|
||||||
let mut result = child.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut result =
|
||||||
|
child.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
result.map(|v| 1.0 / v)?;
|
result.map(|v| 1.0 / v)?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
},
|
},
|
||||||
Self::Sum(children) => {
|
Self::Sum(children) => {
|
||||||
let mut result = children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut result =
|
||||||
|
children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
for child in children.iter().skip(1) {
|
for child in children.iter().skip(1) {
|
||||||
let right = child.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let right =
|
||||||
|
child.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
// try_op will make sure we only sum leaves with the same type.
|
// try_op will make sure we only sum leaves with the same type.
|
||||||
result = result.try_op(&right, |left, right| left + right)?;
|
result = result.try_op(&right, |left, right| left + right)?;
|
||||||
}
|
}
|
||||||
@@ -954,10 +974,12 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
},
|
},
|
||||||
Self::Product(children) => {
|
Self::Product(children) => {
|
||||||
let mut result = children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut result =
|
||||||
|
children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
for child in children.iter().skip(1) {
|
for child in children.iter().skip(1) {
|
||||||
let right = child.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let right =
|
||||||
|
child.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
// Mutliply only allowed when either side is a number.
|
// Mutliply only allowed when either side is a number.
|
||||||
match result.as_number() {
|
match result.as_number() {
|
||||||
Some(left) => {
|
Some(left) => {
|
||||||
@@ -983,14 +1005,16 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
},
|
},
|
||||||
Self::MinMax(children, op) => {
|
Self::MinMax(children, op) => {
|
||||||
let mut result = children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut result =
|
||||||
|
children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
if result.is_nan()? {
|
if result.is_nan()? {
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
for child in children.iter().skip(1) {
|
for child in children.iter().skip(1) {
|
||||||
let candidate = child.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let candidate =
|
||||||
|
child.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
// Leaf types must match for each child.
|
// Leaf types must match for each child.
|
||||||
if !result.is_same_unit_as(&candidate) {
|
if !result.is_same_unit_as(&candidate) {
|
||||||
@@ -1015,9 +1039,10 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
},
|
},
|
||||||
Self::Clamp { min, center, max } => {
|
Self::Clamp { min, center, max } => {
|
||||||
let min = min.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let min = min.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
let center = center.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let center =
|
||||||
let max = max.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
center.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
let max = max.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
if !min.is_same_unit_as(¢er) || !max.is_same_unit_as(¢er) {
|
if !min.is_same_unit_as(¢er) || !max.is_same_unit_as(¢er) {
|
||||||
return Err(());
|
return Err(());
|
||||||
@@ -1050,8 +1075,9 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
value,
|
value,
|
||||||
step,
|
step,
|
||||||
} => {
|
} => {
|
||||||
let mut value = value.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut value =
|
||||||
let step = step.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
value.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
let step = step.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
if !value.is_same_unit_as(&step) {
|
if !value.is_same_unit_as(&step) {
|
||||||
return Err(());
|
return Err(());
|
||||||
@@ -1136,8 +1162,10 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
divisor,
|
divisor,
|
||||||
op,
|
op,
|
||||||
} => {
|
} => {
|
||||||
let mut dividend = dividend.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut dividend =
|
||||||
let divisor = divisor.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
dividend.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
let divisor =
|
||||||
|
divisor.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
if !dividend.is_same_unit_as(&divisor) {
|
if !dividend.is_same_unit_as(&divisor) {
|
||||||
return Err(());
|
return Err(());
|
||||||
@@ -1150,11 +1178,13 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
Ok(dividend)
|
Ok(dividend)
|
||||||
},
|
},
|
||||||
Self::Hypot(children) => {
|
Self::Hypot(children) => {
|
||||||
let mut result = children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut result =
|
||||||
|
children[0].resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
result.map(|v| v.powi(2))?;
|
result.map(|v| v.powi(2))?;
|
||||||
|
|
||||||
for child in children.iter().skip(1) {
|
for child in children.iter().skip(1) {
|
||||||
let child_value = child.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let child_value =
|
||||||
|
child.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
if !result.is_same_unit_as(&child_value) {
|
if !result.is_same_unit_as(&child_value) {
|
||||||
return Err(());
|
return Err(());
|
||||||
@@ -1170,14 +1200,14 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
},
|
},
|
||||||
Self::Abs(ref c) => {
|
Self::Abs(ref c) => {
|
||||||
let mut result = c.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let mut result = c.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
|
|
||||||
result.map(|v| v.abs())?;
|
result.map(|v| v.abs())?;
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
},
|
},
|
||||||
Self::Sign(ref c) => {
|
Self::Sign(ref c) => {
|
||||||
let result = c.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
let result = c.resolve_internal(leaf_to_output_fn, node_mapping_fn, context)?;
|
||||||
Ok(L::sign_from(&result)?)
|
Ok(L::sign_from(&result)?)
|
||||||
},
|
},
|
||||||
Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
|
Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use selectors::matching::{ElementSelectorFlags, MatchingForInvalidation, Selecto
|
|||||||
use selectors::{Element, OpaqueElement};
|
use selectors::{Element, OpaqueElement};
|
||||||
use servo_arc::{Arc, ArcBorrow};
|
use servo_arc::{Arc, ArcBorrow};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use style::values::generics::length::AnchorResolutionResult;
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
@@ -152,11 +151,13 @@ use style::values::computed::font::{
|
|||||||
FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily,
|
FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily,
|
||||||
};
|
};
|
||||||
use style::values::computed::length::AnchorSizeFunction;
|
use style::values::computed::length::AnchorSizeFunction;
|
||||||
|
use style::values::computed::length_percentage::CalcAnchorFunctionResolutionInfo;
|
||||||
use style::values::computed::position::AnchorFunction;
|
use style::values::computed::position::AnchorFunction;
|
||||||
use style::values::computed::{self, Context, PositionProperty, ToComputedValue};
|
use style::values::computed::{self, Context, PositionProperty, ToComputedValue};
|
||||||
use style::values::distance::ComputeSquaredDistance;
|
use style::values::distance::ComputeSquaredDistance;
|
||||||
use style::values::generics::color::ColorMixFlags;
|
use style::values::generics::color::ColorMixFlags;
|
||||||
use style::values::generics::easing::BeforeFlag;
|
use style::values::generics::easing::BeforeFlag;
|
||||||
|
use style::values::generics::length::AnchorResolutionResult;
|
||||||
use style::values::resolved;
|
use style::values::resolved;
|
||||||
use style::values::specified::gecko::IntersectionObserverRootMargin;
|
use style::values::specified::gecko::IntersectionObserverRootMargin;
|
||||||
use style::values::specified::source_size_list::SourceSizeList;
|
use style::values::specified::source_size_list::SourceSizeList;
|
||||||
@@ -8359,7 +8360,38 @@ pub extern "C" fn Servo_ResolveCalcLengthPercentage(
|
|||||||
calc: &computed::length_percentage::CalcLengthPercentage,
|
calc: &computed::length_percentage::CalcLengthPercentage,
|
||||||
basis: f32,
|
basis: f32,
|
||||||
) -> f32 {
|
) -> f32 {
|
||||||
calc.resolve(computed::Length::new(basis)).px()
|
calc.resolve(computed::Length::new(basis), None)
|
||||||
|
.unwrap()
|
||||||
|
.result
|
||||||
|
.px()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn Servo_ResolveCalcLengthPercentageWithAnchorFunctions(
|
||||||
|
calc: &computed::length_percentage::CalcLengthPercentage,
|
||||||
|
basis: f32,
|
||||||
|
side: PhysicalSide,
|
||||||
|
position_property: PositionProperty,
|
||||||
|
result: &mut f32,
|
||||||
|
percentage_used: &mut bool,
|
||||||
|
) -> bool {
|
||||||
|
let resolved = calc.resolve(
|
||||||
|
computed::Length::new(basis),
|
||||||
|
Some(CalcAnchorFunctionResolutionInfo {
|
||||||
|
side,
|
||||||
|
position_property,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let resolved = match resolved {
|
||||||
|
None => return false,
|
||||||
|
Some(v) => v,
|
||||||
|
};
|
||||||
|
|
||||||
|
*result = resolved.result.px();
|
||||||
|
*percentage_used = resolved.percentage_used;
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|||||||
Reference in New Issue
Block a user