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".
|
||||
pub fn resolve(&self, origin_color: Option<&AbsoluteColor>) -> Result<Option<ValueType>, ()> {
|
||||
struct EmptyContext;
|
||||
Ok(match self {
|
||||
ColorComponent::None => None,
|
||||
ColorComponent::Value(value) => Some(value.clone()),
|
||||
@@ -123,7 +124,7 @@ impl<ValueType: ColorComponentType> ColorComponent<ValueType> {
|
||||
},
|
||||
ColorComponent::Calc(node) => {
|
||||
let Ok(resolved_leaf) = node.resolve_map(
|
||||
|leaf| {
|
||||
|leaf, _| {
|
||||
Ok(match leaf {
|
||||
Leaf::ColorComponent(channel_keyword) => match origin_color {
|
||||
Some(origin_color) => {
|
||||
@@ -136,7 +137,8 @@ impl<ValueType: ColorComponentType> ColorComponent<ValueType> {
|
||||
l => l.clone(),
|
||||
})
|
||||
},
|
||||
|_| Err(()),
|
||||
|_, _| Ok(None),
|
||||
&mut EmptyContext,
|
||||
) else {
|
||||
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::distance::{ComputeSquaredDistance, SquaredDistance};
|
||||
use crate::values::generics::calc::{
|
||||
AnchorPositioningResolver, GenericCalcAnchorFunction, GenericCalcAnchorSizeFunction, CalcUnits,
|
||||
AnchorPositioningResolver, CalcUnits, GenericCalcAnchorFunction, GenericCalcAnchorSizeFunction,
|
||||
PositivePercentageBasis,
|
||||
};
|
||||
use crate::values::generics::length::AnchorResolutionResult;
|
||||
@@ -492,7 +492,7 @@ impl LengthPercentage {
|
||||
match self.unpack() {
|
||||
Unpacked::Length(l) => l,
|
||||
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() {
|
||||
Unpacked::Length(l) => Percentage(l.px() / basis.px()),
|
||||
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,
|
||||
}
|
||||
|
||||
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 {
|
||||
/// 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]
|
||||
pub fn resolve(&self, basis: Length) -> Length {
|
||||
// unwrap() is fine because the conversion below is infallible.
|
||||
if let CalcLengthPercentageLeaf::Length(px) = self
|
||||
.node
|
||||
.resolve_map(|leaf| {
|
||||
Ok(if let CalcLengthPercentageLeaf::Percentage(p) = leaf {
|
||||
CalcLengthPercentageLeaf::Length(Length::new(basis.px() * p.0))
|
||||
pub fn resolve(
|
||||
&self,
|
||||
basis: Length,
|
||||
anchor_resolution_info: Option<CalcAnchorFunctionResolutionInfo>,
|
||||
) -> Option<CalcLengthPercentageResolution> {
|
||||
let mut context = ResolveContext::default();
|
||||
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 {
|
||||
leaf.clone()
|
||||
})
|
||||
}, |node| {
|
||||
match node {
|
||||
CalcNode::Anchor(f) => {
|
||||
if let Some(fallback) = f.fallback.as_ref() {
|
||||
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(()),
|
||||
// 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.
|
||||
debug_assert!(context.anchor_function_used, "Anchor function not used but failed resolution?");
|
||||
Some(CalcLengthPercentageResolution{
|
||||
result: Length::zero(),
|
||||
percentage_used: false,
|
||||
})
|
||||
}
|
||||
})
|
||||
.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.
|
||||
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.
|
||||
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
|
||||
F: FnMut(&L) -> Result<L, ()>,
|
||||
NF: FnMut(&CalcNode<L>) -> Result<CalcNode<L>, ()>,
|
||||
F: FnMut(&L, &mut C) -> Result<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
|
||||
F: FnMut(&L) -> Result<L, ()>,
|
||||
NF: FnMut(&CalcNode<L>) -> Result<CalcNode<L>, ()>,
|
||||
F: FnMut(&L, &mut C) -> Result<L, ()>,
|
||||
NF: FnMut(&CalcNode<L>, &mut C) -> Result<Option<CalcNode<L>>, ()>,
|
||||
{
|
||||
let node = node_mapping_fn(self).ok();
|
||||
match node.as_ref().unwrap_or(self) {
|
||||
Self::Leaf(l) => leaf_to_output_fn(l),
|
||||
let result = node_mapping_fn(self, context)?;
|
||||
let node = result.as_ref().unwrap_or(self);
|
||||
match node {
|
||||
Self::Leaf(l) => leaf_to_output_fn(l, context),
|
||||
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())?;
|
||||
Ok(result)
|
||||
},
|
||||
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)?;
|
||||
Ok(result)
|
||||
},
|
||||
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) {
|
||||
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.
|
||||
result = result.try_op(&right, |left, right| left + right)?;
|
||||
}
|
||||
@@ -954,10 +974,12 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||
Ok(result)
|
||||
},
|
||||
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) {
|
||||
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.
|
||||
match result.as_number() {
|
||||
Some(left) => {
|
||||
@@ -983,14 +1005,16 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||
Ok(result)
|
||||
},
|
||||
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()? {
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
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.
|
||||
if !result.is_same_unit_as(&candidate) {
|
||||
@@ -1015,9 +1039,10 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||
Ok(result)
|
||||
},
|
||||
Self::Clamp { min, center, max } => {
|
||||
let min = min.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
||||
let center = center.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
||||
let max = max.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, 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) {
|
||||
return Err(());
|
||||
@@ -1050,8 +1075,9 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||
value,
|
||||
step,
|
||||
} => {
|
||||
let mut value = value.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
||||
let step = step.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
||||
let mut value =
|
||||
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) {
|
||||
return Err(());
|
||||
@@ -1136,8 +1162,10 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||
divisor,
|
||||
op,
|
||||
} => {
|
||||
let mut dividend = dividend.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
||||
let divisor = divisor.resolve_internal(leaf_to_output_fn, node_mapping_fn)?;
|
||||
let mut dividend =
|
||||
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) {
|
||||
return Err(());
|
||||
@@ -1150,11 +1178,13 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||
Ok(dividend)
|
||||
},
|
||||
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))?;
|
||||
|
||||
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) {
|
||||
return Err(());
|
||||
@@ -1170,14 +1200,14 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
|
||||
Ok(result)
|
||||
},
|
||||
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())?;
|
||||
|
||||
Ok(result)
|
||||
},
|
||||
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)?)
|
||||
},
|
||||
Self::Anchor(_) | Self::AnchorSize(_) => Err(()),
|
||||
|
||||
@@ -16,7 +16,6 @@ use selectors::matching::{ElementSelectorFlags, MatchingForInvalidation, Selecto
|
||||
use selectors::{Element, OpaqueElement};
|
||||
use servo_arc::{Arc, ArcBorrow};
|
||||
use smallvec::SmallVec;
|
||||
use style::values::generics::length::AnchorResolutionResult;
|
||||
use std::collections::BTreeSet;
|
||||
use std::fmt::Write;
|
||||
use std::iter;
|
||||
@@ -152,11 +151,13 @@ use style::values::computed::font::{
|
||||
FamilyName, FontFamily, FontFamilyList, FontStretch, FontStyle, FontWeight, GenericFontFamily,
|
||||
};
|
||||
use style::values::computed::length::AnchorSizeFunction;
|
||||
use style::values::computed::length_percentage::CalcAnchorFunctionResolutionInfo;
|
||||
use style::values::computed::position::AnchorFunction;
|
||||
use style::values::computed::{self, Context, PositionProperty, ToComputedValue};
|
||||
use style::values::distance::ComputeSquaredDistance;
|
||||
use style::values::generics::color::ColorMixFlags;
|
||||
use style::values::generics::easing::BeforeFlag;
|
||||
use style::values::generics::length::AnchorResolutionResult;
|
||||
use style::values::resolved;
|
||||
use style::values::specified::gecko::IntersectionObserverRootMargin;
|
||||
use style::values::specified::source_size_list::SourceSizeList;
|
||||
@@ -8359,7 +8360,38 @@ pub extern "C" fn Servo_ResolveCalcLengthPercentage(
|
||||
calc: &computed::length_percentage::CalcLengthPercentage,
|
||||
basis: 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]
|
||||
|
||||
Reference in New Issue
Block a user