Bug 1947482: Anchor resolution takes axis, not side. r=firefox-style-system-reviewers,emilio

Differential Revision: https://phabricator.services.mozilla.com/D238962
This commit is contained in:
David Shin
2025-02-20 18:26:22 +00:00
parent 41b43cea76
commit 894d84866a
11 changed files with 66 additions and 68 deletions

View File

@@ -1548,7 +1548,7 @@ class nsLayoutUtils {
}
static nscoord ComputeCBDependentValue(nscoord aPercentBasis,
mozilla::StylePhysicalSide aSide,
mozilla::StylePhysicalAxis aAxis,
mozilla::StylePositionProperty aProp,
const AnchorResolvedInset& aInset) {
if (aInset->IsAuto()) {
@@ -1559,7 +1559,7 @@ class nsLayoutUtils {
"Have unconstrained percentage basis when percentage "
"resolution needed; this should only result from very "
"large sizes, not attempts at intrinsic size calculation");
return aInset->AsLengthPercentage().ResolveWithAnchor(aPercentBasis, aSide,
return aInset->AsLengthPercentage().ResolveWithAnchor(aPercentBasis, aAxis,
aProp);
}

View File

@@ -1676,7 +1676,7 @@ void ReflowInput::InitAbsoluteConstraints(const ReflowInput* aCBReflowInput,
} else {
offsets.IStart(cbwm) = nsLayoutUtils::ComputeCBDependentValue(
cbSize.ISize(cbwm),
ToStylePhysicalSide(cbwm.PhysicalSide(LogicalSide::IStart)),
ToStylePhysicalAxis(cbwm.PhysicalAxis(LogicalAxis::Inline)),
StylePositionProperty::Absolute, iStartOffset);
}
if (iEndIsAuto) {
@@ -1684,7 +1684,7 @@ void ReflowInput::InitAbsoluteConstraints(const ReflowInput* aCBReflowInput,
} else {
offsets.IEnd(cbwm) = nsLayoutUtils::ComputeCBDependentValue(
cbSize.ISize(cbwm),
ToStylePhysicalSide(cbwm.PhysicalSide(LogicalSide::IEnd)),
ToStylePhysicalAxis(cbwm.PhysicalAxis(LogicalAxis::Inline)),
StylePositionProperty::Absolute, iEndOffset);
}
@@ -1703,7 +1703,7 @@ void ReflowInput::InitAbsoluteConstraints(const ReflowInput* aCBReflowInput,
} else {
offsets.BStart(cbwm) = nsLayoutUtils::ComputeCBDependentValue(
cbSize.BSize(cbwm),
ToStylePhysicalSide(cbwm.PhysicalSide(LogicalSide::BStart)),
ToStylePhysicalAxis(cbwm.PhysicalAxis(LogicalAxis::Block)),
StylePositionProperty::Absolute, bStartOffset);
}
if (bEndIsAuto) {
@@ -1711,7 +1711,7 @@ void ReflowInput::InitAbsoluteConstraints(const ReflowInput* aCBReflowInput,
} else {
offsets.BEnd(cbwm) = nsLayoutUtils::ComputeCBDependentValue(
cbSize.BSize(cbwm),
ToStylePhysicalSide(cbwm.PhysicalSide(LogicalSide::BEnd)),
ToStylePhysicalAxis(cbwm.PhysicalAxis(LogicalAxis::Block)),
StylePositionProperty::Absolute, bEndOffset);
}

View File

@@ -90,6 +90,7 @@ using ComputedKeyframeValues = nsTArray<PropertyStyleAnimationValuePair>;
class ComputedStyle;
enum class LogicalAxis : uint8_t;
enum class PhysicalAxis : uint8_t;
class SeenPtrs;
class SharedFontList;
class StyleSheet;

View File

@@ -732,12 +732,12 @@ nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis,
}
nscoord StyleCalcLengthPercentage::ResolveWithAnchor(
nscoord aBasis, mozilla::StylePhysicalSide aSide,
nscoord aBasis, mozilla::StylePhysicalAxis aAxis,
mozilla::StylePositionProperty aProp) const {
float value{};
bool unused{};
bool result = Servo_ResolveCalcLengthPercentageWithAnchorFunctions(
this, CSSPixel::FromAppUnits(aBasis), aSide, aProp, &value, &unused);
this, CSSPixel::FromAppUnits(aBasis), aAxis, aProp, &value, &unused);
if (!result) {
MOZ_ASSERT_UNREACHABLE(
"Was expecting initial anchor resolution to determine validity");
@@ -802,7 +802,7 @@ nscoord LengthPercentage::Resolve(nscoord aPercentageBasis,
}
nscoord LengthPercentage::ResolveWithAnchor(
nscoord aPercentageBasis, mozilla::StylePhysicalSide aSide,
nscoord aPercentageBasis, mozilla::StylePhysicalAxis aAxis,
mozilla::StylePositionProperty aProp) const {
if (ConvertsToLength()) {
return ToLength();
@@ -815,7 +815,7 @@ nscoord LengthPercentage::ResolveWithAnchor(
return detail::DefaultPercentLengthToAppUnits(
static_cast<float>(aPercentageBasis) * percent);
}
return AsCalc().ResolveWithAnchor(aPercentageBasis, aSide, aProp);
return AsCalc().ResolveWithAnchor(aPercentageBasis, aAxis, aProp);
}
void LengthPercentage::ScaleLengthsBy(float aScale) {
@@ -1289,21 +1289,17 @@ inline gfx::Point StyleCoordinatePair<LengthPercentage>::ToGfxPoint(
y.ResolveToCSSPixels(aBasis->Height()));
}
inline StylePhysicalSide ToStylePhysicalSide(mozilla::Side aSide) {
inline StylePhysicalAxis GetStylePhysicalAxis(Side aSide) {
return aSide == mozilla::Side::eSideTop || aSide == mozilla::Side::eSideBottom
? StylePhysicalAxis::Vertical
: StylePhysicalAxis::Horizontal;
}
inline StylePhysicalAxis ToStylePhysicalAxis(PhysicalAxis aAxis) {
// TODO(dhsin): Should look into merging these two values...
static_assert(static_cast<uint8_t>(mozilla::Side::eSideTop) ==
static_cast<uint8_t>(StylePhysicalSide::Top),
"Top side doesn't match");
static_assert(static_cast<uint8_t>(mozilla::Side::eSideBottom) ==
static_cast<uint8_t>(StylePhysicalSide::Bottom),
"Bottom side doesn't match");
static_assert(static_cast<uint8_t>(mozilla::Side::eSideLeft) ==
static_cast<uint8_t>(StylePhysicalSide::Left),
"Left side doesn't match");
static_assert(static_cast<uint8_t>(mozilla::Side::eSideRight) ==
static_cast<uint8_t>(StylePhysicalSide::Right),
"Right side doesn't match");
return static_cast<StylePhysicalSide>(static_cast<uint8_t>(aSide));
// Assert for this casting lives in `nsStyleStruct.cpp` since
// `PhysicalAxis` is a forward decl here.
return static_cast<StylePhysicalAxis>(static_cast<uint8_t>(aAxis));
}
} // namespace mozilla

View File

@@ -1911,8 +1911,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetNonStaticPositionOffset(
const nsStylePosition* positionData = StylePosition();
int32_t sign = 1;
const auto positionProperty = StyleDisplay()->mPosition;
auto side = aSide;
auto coord = positionData->GetAnchorResolvedInset(side, positionProperty);
auto coord = positionData->GetAnchorResolvedInset(aSide, positionProperty);
if (coord->IsAuto()) {
if (!aResolveAuto) {
@@ -1920,8 +1919,8 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetNonStaticPositionOffset(
val->SetString("auto");
return val.forget();
}
side = NS_OPPOSITE_SIDE(side);
coord = positionData->GetAnchorResolvedInset(side, positionProperty);
coord = positionData->GetAnchorResolvedInset(NS_OPPOSITE_SIDE(aSide),
positionProperty);
sign = -1;
}
if (coord->IsAuto()) {
@@ -1941,11 +1940,8 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetNonStaticPositionOffset(
return PixelsToCSSValue(0.0f);
}
// TODO(dshin, bug 1947482): Anchor resolution only cares about the axis it's
// being resolved in, so we should be able to use `PhysicalAxis` and not worry
// about keeping track of `side`.
nscoord result = lp.ResolveWithAnchor(
percentageBase, ToStylePhysicalSide(side), positionProperty);
percentageBase, GetStylePhysicalAxis(aSide), positionProperty);
return AppUnitsToCSSValue(sign * result);
}

View File

@@ -1362,7 +1362,7 @@ StyleJustifySelf nsStylePosition::UsedJustifySelf(
AnchorResolvedInset nsStylePosition::GetAnchorResolvedInset(
Side aSide, StylePositionProperty aPosition) const {
return {mOffset.Get(aSide), aSide, aPosition};
return {mOffset.Get(aSide), GetStylePhysicalAxis(aSide), aPosition};
}
AnchorResolvedInset nsStylePosition::GetAnchorResolvedInset(
@@ -1372,15 +1372,15 @@ AnchorResolvedInset nsStylePosition::GetAnchorResolvedInset(
}
AnchorResolvedInset::AnchorResolvedInset(
const mozilla::StyleInset& aValue, mozilla::Side aSide,
const mozilla::StyleInset& aValue, mozilla::StylePhysicalAxis aAxis,
mozilla::StylePositionProperty aPosition)
: AnchorResolved<StyleInset>{FromUnresolved(aValue, aSide, aPosition)} {}
: AnchorResolved<StyleInset>{FromUnresolved(aValue, aAxis, aPosition)} {}
AnchorResolvedInset::AnchorResolvedInset(
const mozilla::StyleInset& aValue, mozilla::LogicalSide aSide,
const mozilla::StyleInset& aValue, mozilla::LogicalAxis aAxis,
mozilla::WritingMode aWM, mozilla::StylePositionProperty aPosition)
: AnchorResolved<StyleInset>{
FromUnresolved(aValue, aWM.PhysicalSide(aSide), aPosition)} {}
: AnchorResolved<StyleInset>{FromUnresolved(
aValue, ToStylePhysicalAxis(aWM.PhysicalAxis(aAxis)), aPosition)} {}
AnchorResolved<mozilla::StyleInset> AnchorResolvedInset::Invalid() {
return AnchorResolved::Evaluated(StyleInset::Auto());
@@ -1397,9 +1397,15 @@ AnchorResolved<mozilla::StyleInset> AnchorResolvedInset::Evaluated(
}
AnchorResolved<mozilla::StyleInset> AnchorResolvedInset::FromUnresolved(
const mozilla::StyleInset& aValue, mozilla::Side aSide,
const mozilla::StyleInset& aValue, mozilla::StylePhysicalAxis aAxis,
mozilla::StylePositionProperty aPosition) {
// TODO(dshin): Maybe worth pref-gating here.
static_assert(static_cast<uint8_t>(mozilla::PhysicalAxis::Vertical) ==
static_cast<uint8_t>(StylePhysicalAxis::Vertical),
"Vertical axis doesn't match");
static_assert(static_cast<uint8_t>(mozilla::PhysicalAxis::Horizontal) ==
static_cast<uint8_t>(StylePhysicalAxis::Horizontal),
"Horizontal axis doesn't match");
switch (aValue.tag) {
case StyleInset::Tag::Auto:
return AnchorResolved::Unchanged(aValue);
@@ -1410,8 +1416,7 @@ AnchorResolved<mozilla::StyleInset> AnchorResolvedInset::FromUnresolved(
float result{};
bool percentageUsed{};
if (!Servo_ResolveCalcLengthPercentageWithAnchorFunctions(
&c, 0.0, ToStylePhysicalSide(aSide), aPosition, &result,
&percentageUsed)) {
&c, 0.0, aAxis, aPosition, &result, &percentageUsed)) {
return Invalid();
}
if (percentageUsed) {
@@ -1427,8 +1432,7 @@ AnchorResolved<mozilla::StyleInset> AnchorResolvedInset::FromUnresolved(
}
case StyleInset::Tag::AnchorFunction: {
auto resolved = StyleAnchorPositioningFunctionResolution::Invalid();
Servo_ResolveAnchorFunction(&*aValue.AsAnchorFunction(),
ToStylePhysicalSide(aSide), aPosition,
Servo_ResolveAnchorFunction(&*aValue.AsAnchorFunction(), aAxis, aPosition,
&resolved);
if (resolved.IsInvalid()) {
return Invalid();

View File

@@ -740,15 +740,16 @@ class AnchorResolved {
class AnchorResolvedInset final : public AnchorResolved<mozilla::StyleInset> {
public:
AnchorResolvedInset(const mozilla::StyleInset& aValue, mozilla::Side aSide,
AnchorResolvedInset(const mozilla::StyleInset& aValue,
mozilla::StylePhysicalAxis aAxis,
mozilla::StylePositionProperty aPosition);
AnchorResolvedInset(const mozilla::StyleInset& aValue,
mozilla::LogicalSide aSide, mozilla::WritingMode aWM,
mozilla::LogicalAxis aAxis, mozilla::WritingMode aWM,
mozilla::StylePositionProperty aPosition);
private:
static AnchorResolved<mozilla::StyleInset> FromUnresolved(
const mozilla::StyleInset& aValue, mozilla::Side aSide,
const mozilla::StyleInset& aValue, mozilla::StylePhysicalAxis aAxis,
mozilla::StylePositionProperty aPosition);
static AnchorResolved<mozilla::StyleInset> Invalid();
static AnchorResolved<mozilla::StyleInset> Evaluated(

View File

@@ -27,7 +27,7 @@
use super::{Context, Length, Percentage, PositionProperty, ToComputedValue};
#[cfg(feature = "gecko")]
use crate::gecko_bindings::structs::GeckoFontMetrics;
use crate::logical_geometry::PhysicalSide;
use crate::logical_geometry::PhysicalAxis;
use crate::values::animated::{Animate, Context as AnimatedContext, Procedure, ToAnimatedValue, ToAnimatedZero};
use crate::values::distance::{ComputeSquaredDistance, SquaredDistance};
use crate::values::generics::calc::{CalcUnits, PositivePercentageBasis};
@@ -937,7 +937,7 @@ fn map_node(
match node {
CalcNode::Anchor(f) => {
context.anchor_function_used = true;
match f.resolve(info.side, info.position_property) {
match f.resolve(info.axis, info.position_property) {
AnchorResolutionResult::Invalid => return Err(()),
AnchorResolutionResult::Fallback(fb) => {
let mut inner_context = ResolveContext::default();
@@ -992,12 +992,12 @@ fn map_node(
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CalcAnchorFunctionResolutionInfo {
/// Which side we're resolving anchor functions for.
/// Which axis 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,
pub axis: PhysicalAxis,
/// `position` property of the box for which this style is being resolved.
pub position_property: PositionProperty,
}
@@ -1008,7 +1008,7 @@ impl CalcAnchorFunctionResolutionInfo {
// Makes anchor functions always invalid
position_property: PositionProperty::Static,
// Doesn't matter
side: PhysicalSide::Left,
axis: PhysicalAxis::Vertical,
}
}
}

View File

@@ -11,7 +11,7 @@ use style_traits::CssWriter;
use style_traits::SpecifiedValueInfo;
use style_traits::ToCss;
use crate::logical_geometry::PhysicalSide;
use crate::logical_geometry::PhysicalAxis;
use crate::values::animated::ToAnimatedZero;
use crate::values::generics::box_::PositionProperty;
use crate::values::generics::length::{AnchorResolutionResult, GenericAnchorSizeFunction};
@@ -381,14 +381,14 @@ impl<Percentage, LengthPercentage> GenericAnchorFunction<Percentage, LengthPerce
/// Resolve the anchor function. On failure, return reference to fallback, if exists.
pub fn resolve<'a>(
&'a self,
side: PhysicalSide,
axis: PhysicalAxis,
position_property: PositionProperty,
) -> AnchorResolutionResult<'a, LengthPercentage> {
if !position_property.is_absolutely_positioned() {
return AnchorResolutionResult::new_anchor_invalid(self.fallback.as_ref());
}
if !self.side.valid_for_side(side) {
if !self.side.valid_for_axis(axis) {
return AnchorResolutionResult::new_anchor_invalid(self.fallback.as_ref());
}
@@ -446,10 +446,10 @@ pub enum AnchorSideKeyword {
}
impl AnchorSideKeyword {
fn valid_for_side(&self, side: PhysicalSide) -> bool {
fn valid_for_axis(&self, axis: PhysicalAxis) -> bool {
match self {
Self::Left | Self::Right => side == PhysicalSide::Left || side == PhysicalSide::Right,
Self::Top | Self::Bottom => side == PhysicalSide::Top || side == PhysicalSide::Bottom,
Self::Left | Self::Right => axis == PhysicalAxis::Horizontal,
Self::Top | Self::Bottom => axis == PhysicalAxis::Vertical,
Self::Inside |
Self::Outside |
Self::Start |
@@ -490,10 +490,10 @@ pub enum AnchorSide<P> {
}
impl<P> AnchorSide<P> {
/// Is this anchor side valid for a given side?
pub fn valid_for_side(&self, side: PhysicalSide) -> bool {
/// Is this anchor side valid for a given axis?
pub fn valid_for_axis(&self, axis: PhysicalAxis) -> bool {
match self {
Self::Keyword(k) => k.valid_for_side(side),
Self::Keyword(k) => k.valid_for_axis(axis),
Self::Percentage(_) => true,
}
}

View File

@@ -330,7 +330,7 @@ include = [
"AnchorSizeFunction",
"Margin",
"PositionProperty",
"PhysicalSide",
"PhysicalAxis",
]
item_types = [
"enums",
@@ -414,7 +414,7 @@ renaming_overrides_prefixing = true
inline CSSCoord ResolveToCSSPixels(CSSCoord aBasis) const;
template<typename Rounder>
inline nscoord Resolve(nscoord aBasis, Rounder) const;
inline nscoord ResolveWithAnchor(nscoord aBasis, mozilla::StylePhysicalSide aSide, mozilla::StylePositionProperty aProp) const;
inline nscoord ResolveWithAnchor(nscoord aBasis, mozilla::StylePhysicalAxis aAxis, mozilla::StylePositionProperty aProp) const;
"""
"GenericCalcNode" = """
@@ -481,7 +481,7 @@ renaming_overrides_prefixing = true
inline nscoord Resolve(nscoord aPercentageBasis, Rounder) const;
template<typename T> inline nscoord Resolve(T aPercentageGetter) const;
inline nscoord Resolve(nscoord aPercentageBasis) const;
inline nscoord ResolveWithAnchor(nscoord aPercentageBasis, mozilla::StylePhysicalSide aSide, mozilla::StylePositionProperty aProp) const;
inline nscoord ResolveWithAnchor(nscoord aPercentageBasis, mozilla::StylePhysicalAxis aAxis, mozilla::StylePositionProperty aProp) const;
"""
"GenericLengthPercentageOrAuto" = """

View File

@@ -103,7 +103,7 @@ use style::invalidation::element::relative_selector::{
};
use style::invalidation::element::restyle_hints::RestyleHint;
use style::invalidation::stylesheets::RuleChangeKind;
use style::logical_geometry::PhysicalSide;
use style::logical_geometry::PhysicalAxis;
use style::media_queries::MediaList;
use style::parser::{Parse, ParserContext};
#[cfg(feature = "gecko_debug")]
@@ -8384,7 +8384,7 @@ pub extern "C" fn Servo_ResolveCalcLengthPercentage(
pub extern "C" fn Servo_ResolveCalcLengthPercentageWithAnchorFunctions(
calc: &computed::length_percentage::CalcLengthPercentage,
basis: f32,
side: PhysicalSide,
axis: PhysicalAxis,
position_property: PositionProperty,
result: &mut f32,
percentage_used: &mut bool,
@@ -8392,7 +8392,7 @@ pub extern "C" fn Servo_ResolveCalcLengthPercentageWithAnchorFunctions(
let resolved = calc.resolve(
computed::Length::new(basis),
Some(CalcAnchorFunctionResolutionInfo {
side,
axis,
position_property,
}),
);
@@ -9811,11 +9811,11 @@ impl AnchorPositioningFunctionResolution {
#[no_mangle]
pub extern "C" fn Servo_ResolveAnchorFunction(
func: &AnchorFunction,
side: PhysicalSide,
axis: PhysicalAxis,
prop: PositionProperty,
out: &mut AnchorPositioningFunctionResolution,
) {
*out = AnchorPositioningFunctionResolution::new(func.resolve(side, prop));
*out = AnchorPositioningFunctionResolution::new(func.resolve(axis, prop));
}
#[no_mangle]