commit 6e861d0db3e83e4c7c0aa74dc422b02d7514bbbf
parent 56907edbced39dadadc4779d62eb9dee4bedb755
Author: David Shin <dshin@mozilla.com>
Date: Thu, 18 Dec 2025 15:14:16 +0000
Bug 2006402: Properly resolve auto inset/margin in nsComputedDOMStyle with anchor positioning. r=layout-anchor-positioning-reviewers,firefox-style-system-reviewers,emilio
Differential Revision: https://phabricator.services.mozilla.com/D276908
Diffstat:
4 files changed, 159 insertions(+), 14 deletions(-)
diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h
@@ -400,10 +400,7 @@ already_AddRefed<nsComputedDOMStyle> NS_NewComputedDOMStyle(
inline AnchorPosResolutionParams AnchorPosResolutionParams::From(
const nsComputedDOMStyle* aComputedDOMStyle) {
- // TODO(dshin): Fix this up.
- AutoResolutionOverrideParams overrides;
- overrides.mPositionAreaInUse =
- !aComputedDOMStyle->StylePosition()->mPositionArea.IsNone();
+ AutoResolutionOverrideParams overrides{aComputedDOMStyle->mOuterFrame};
return {aComputedDOMStyle->mOuterFrame,
aComputedDOMStyle->StyleDisplay()->mPosition, nullptr, overrides};
}
diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp
@@ -306,14 +306,16 @@ bool AnchorPosResolutionParams::AutoResolutionOverrideParams::OverriddenToZero(
}
}
-AnchorPosResolutionParams::AutoResolutionOverrideParams::
- AutoResolutionOverrideParams(
- const nsIFrame* aFrame,
- const mozilla::AnchorPosResolutionCache* aCache) {
+static AnchorPosResolutionParams::AutoResolutionOverrideParams
+GetAutoResolutionOverrideParams(const nsIFrame* aFrame,
+ bool aDefaultAnchorValid) {
+ if (!aFrame) {
+ return {};
+ }
nsIFrame* parent = aFrame->GetParent();
- if (!parent || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) || !aCache ||
- !aCache->mDefaultAnchorCache.mAnchor) {
- return;
+ if (!parent || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) ||
+ !aDefaultAnchorValid) {
+ return {};
}
const auto* stylePos = aFrame->StylePosition();
@@ -328,11 +330,35 @@ AnchorPosResolutionParams::AutoResolutionOverrideParams::
const auto horizontalLogicalAxis =
cbwm.IsVertical() ? LogicalAxis::Block : LogicalAxis::Inline;
- mHAnchorCenter = checkAxis(horizontalLogicalAxis);
- mVAnchorCenter = checkAxis(GetOrthogonalAxis(horizontalLogicalAxis));
- mPositionAreaInUse = !stylePos->mPositionArea.IsNone();
+ AnchorPosResolutionParams::AutoResolutionOverrideParams result;
+ result.mHAnchorCenter = checkAxis(horizontalLogicalAxis);
+ result.mVAnchorCenter = checkAxis(GetOrthogonalAxis(horizontalLogicalAxis));
+ result.mPositionAreaInUse = !stylePos->mPositionArea.IsNone();
+ return result;
}
+AnchorPosResolutionParams::AutoResolutionOverrideParams::
+ AutoResolutionOverrideParams(
+ const nsIFrame* aFrame, const mozilla::AnchorPosResolutionCache* aCache)
+ : AutoResolutionOverrideParams{GetAutoResolutionOverrideParams(
+ aFrame, aCache && aCache->mDefaultAnchorCache.mAnchor)} {}
+
+AnchorPosResolutionParams::AutoResolutionOverrideParams::
+ AutoResolutionOverrideParams(const nsIFrame* aFrame)
+ : AutoResolutionOverrideParams{
+ GetAutoResolutionOverrideParams(aFrame, [&]() {
+ if (!aFrame) {
+ return false;
+ }
+ const auto* references =
+ aFrame->GetProperty(nsIFrame::AnchorPosReferences());
+ if (!references || !references->mDefaultAnchorName) {
+ // It is presumed that this is called on a reflowed frame.
+ return false;
+ }
+ return references->Lookup(references->mDefaultAnchorName)->isSome();
+ }())} {}
+
AnchorResolvedMargin AnchorResolvedMarginHelper::ResolveAnchor(
const StyleMargin& aValue, StylePhysicalAxis aAxis,
const AnchorPosResolutionParams& aParams) {
diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h
@@ -42,6 +42,7 @@ class nsComputedDOMStyle;
namespace mozilla {
class ComputedStyle;
struct AnchorPosResolutionCache;
+class AnchorPosReferenceData;
struct IntrinsicSize;
struct SizeComputationInput;
@@ -390,6 +391,7 @@ struct AnchorPosResolutionParams {
AutoResolutionOverrideParams(
const nsIFrame* aFrame,
const mozilla::AnchorPosResolutionCache* aCache);
+ explicit AutoResolutionOverrideParams(const nsIFrame* aFrame);
bool OverriddenToZero(mozilla::StylePhysicalAxis aAxis) const;
};
diff --git a/testing/web-platform/tests/css/css-anchor-position/auto-inset-margin-getComputedStyle.html b/testing/web-platform/tests/css/css-anchor-position/auto-inset-margin-getComputedStyle.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Tests that getComputedStyle() returns auto insets and margins 0 when position-area or anchor-center is used with valid default anchor</title>
+<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#position-area">
+<link rel="help" href="https://drafts.csswg.org/css-anchor-position-1/#anchor-pos">
+<link rel="author" name="David Shin" href="mailto:dshin@mozilla.com">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+.abs-cb {
+ width: 60px;
+ height: 60px;
+ border: 5px solid;
+ position: relative;
+ anchor-scope: all;
+ display: inline-block;
+ /* Nudge static position against padding box. */
+ padding: 10px;
+}
+
+.anchor {
+ anchor-name: --a;
+ position: absolute;
+ left: 20px;
+ top: 20px;
+ width: 20px;
+ height: 20px;
+ background: pink;
+}
+
+.positioned {
+ position: absolute;
+ background: purple;
+ width: 20px;
+ height: 20px;
+}
+
+.margin-auto > .positioned {
+ inset: 0;
+ margin: auto;
+}
+
+.inset-auto > .positioned {
+ inset: auto;
+}
+
+.pa {
+ position-area: bottom right;
+}
+
+.jac {
+ justify-self: anchor-center;
+}
+
+.aac {
+ align-self: anchor-center;
+}
+
+.valid-anchor > .positioned {
+ position-anchor: --a;
+}
+</style>
+<div id=insetValidAnchor class="abs-cb inset-auto valid-anchor">
+ <div class=anchor></div>
+ <div class="positioned pa"></div>
+ <div class="positioned jac"></div>
+ <div class="positioned aac"></div>
+</div
+><div id=insetInvalidAnchor class="abs-cb inset-auto">
+ <div class=anchor></div>
+ <div class="positioned pa"></div>
+ <div class="positioned jac"></div>
+ <div class="positioned aac"></div>
+</div><br>
+<div id=marginValidAnchor class="abs-cb margin-auto valid-anchor">
+ <div class=anchor></div>
+ <div class="positioned pa"></div>
+ <div class="positioned jac"></div>
+ <div class="positioned aac"></div>
+</div
+><div id=marginInvalidAnchor class="abs-cb margin-auto">
+ <div class=anchor></div>
+ <div class="positioned pa"></div>
+ <div class="positioned jac"></div>
+ <div class="positioned aac"></div>
+</div>
+<script>
+function assert_zero(e, f, props, t) {
+ test(() => {
+ const s = getComputedStyle(e);
+ for (const prop of props) {
+ f(s.getPropertyValue(prop), "0px");
+ }
+ }, t);
+}
+
+const horizontalInsets = ['left', 'right'];
+const verticalInsets = ['top', 'bottom'];
+const allInsets = horizontalInsets.concat(verticalInsets);
+
+assert_zero(insetValidAnchor.querySelector('.pa'), assert_equals, allInsets, "position-area with valid anchor sets insets to zero");
+assert_zero(insetValidAnchor.querySelector('.jac'), assert_equals, horizontalInsets, "justify-self: anchor-center with valid anchor sets insets to zero");
+assert_zero(insetValidAnchor.querySelector('.aac'), assert_equals, verticalInsets, "align-self: anchor-center with valid anchor sets insets to zero");
+
+assert_zero(insetInvalidAnchor.querySelector('.pa'), assert_not_equals, allInsets, "position-area with invalid anchor does not set insets to zero");
+assert_zero(insetInvalidAnchor.querySelector('.jac'), assert_not_equals, horizontalInsets, "justify-self: anchor-center with invalid anchor does not set insets to zero");
+assert_zero(insetInvalidAnchor.querySelector('.aac'), assert_not_equals, verticalInsets, "align-self: anchor-center with invalid anchor does not set insets to zero");
+
+const horizontalMargins = ['margin-left', 'margin-right'];
+const verticalMargins = ['margin-top', 'margin-bottom'];
+const allMargins = horizontalMargins.concat(verticalMargins);
+
+assert_zero(marginValidAnchor.querySelector('.pa'), assert_equals, allMargins, "position-area with valid anchor sets margins to zero");
+assert_zero(marginValidAnchor.querySelector('.jac'), assert_equals, horizontalMargins, "justify-self: anchor-center with valid anchor sets margins to zero");
+assert_zero(marginValidAnchor.querySelector('.aac'), assert_equals, verticalMargins, "align-self: anchor-center with valid anchor sets margins to zero");
+
+assert_zero(marginInvalidAnchor.querySelector('.pa'), assert_not_equals, allMargins, "position-area with invalid anchor does not set margins to zero");
+assert_zero(marginInvalidAnchor.querySelector('.jac'), assert_not_equals, horizontalMargins, "justify-self: anchor-center with invalid anchor does not set margins to zero");
+assert_zero(marginInvalidAnchor.querySelector('.aac'), assert_not_equals, verticalMargins, "align-self: anchor-center with invalid anchor does not set margins to zero");
+</script>