tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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:
Mlayout/style/nsComputedDOMStyle.h | 5+----
Mlayout/style/nsStyleStruct.cpp | 46++++++++++++++++++++++++++++++++++++----------
Mlayout/style/nsStyleStruct.h | 2++
Atesting/web-platform/tests/css/css-anchor-position/auto-inset-margin-getComputedStyle.html | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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>