tor-browser

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

commit c66676ce8f63cfed777b4369b51bf4a43ff747bb
parent f077deaade2d2bd1dafd3647a59bdaf7ff1ee4db
Author: David Shin <dshin@mozilla.com>
Date:   Thu, 18 Dec 2025 18:44:12 +0000

Bug 2006402: Ensure that we override auto insets/margins only when there's position-area/anchor-center + valid default anchor. r=layout-anchor-positioning-reviewers,firefox-style-system-reviewers,layout-reviewers,emilio

Reuse the `anchor-center` check code, that checks for the validity of default
anchor, and reuse the `position-area` resolution logic, where `auto` values get
mapped to 0 at resolution time.

Differential Revision: https://phabricator.services.mozilla.com/D276905

Diffstat:
Mlayout/generic/ReflowInput.cpp | 57++++++++++++---------------------------------------------
Mlayout/generic/ReflowInput.h | 5-----
Mlayout/generic/nsIFrame.cpp | 2+-
Mlayout/generic/nsIFrame.h | 13++-----------
Mlayout/style/nsComputedDOMStyle.h | 7+++++--
Mlayout/style/nsStyleStruct.cpp | 89++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mlayout/style/nsStyleStruct.h | 83+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mservo/ports/geckolib/glue.rs | 4+---
Dtesting/web-platform/meta/css/css-anchor-position/position-area-basic.html.ini | 3---
9 files changed, 141 insertions(+), 122 deletions(-)

diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp @@ -43,23 +43,13 @@ using namespace mozilla::layout; AnchorPosResolutionParams AnchorPosResolutionParams::From( const mozilla::SizeComputationInput* aSizingInput, bool aIgnorePositionArea) { - const mozilla::StylePositionArea posArea = - aIgnorePositionArea - ? mozilla::StylePositionArea{} - : aSizingInput->mFrame->StylePosition()->mPositionArea; - bool inlineUsesAnchorCenter = false; - bool blockUsesAnchorCenter = false; - - ComputeAnchorCenterUsage(aSizingInput->mFrame, - aSizingInput->mAnchorPosResolutionCache, - inlineUsesAnchorCenter, blockUsesAnchorCenter); - - return {aSizingInput->mFrame, - aSizingInput->mFrame->StyleDisplay()->mPosition, - posArea, - aSizingInput->mAnchorPosResolutionCache, - inlineUsesAnchorCenter, - blockUsesAnchorCenter}; + auto override = AutoResolutionOverrideParams{ + aSizingInput->mFrame, aSizingInput->mAnchorPosResolutionCache}; + if (aIgnorePositionArea) { + override.mPositionAreaInUse = false; + } + return {aSizingInput->mFrame, aSizingInput->mFrame->StyleDisplay()->mPosition, + aSizingInput->mAnchorPosResolutionCache, override}; } static bool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent) { @@ -68,32 +58,6 @@ static bool CheckNextInFlowParenthood(nsIFrame* aFrame, nsIFrame* aParent) { return frameNext && parentNext && frameNext->GetParent() == parentNext; } -void ComputeAnchorCenterUsage( - const nsIFrame* aFrame, - mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache, - bool& aInlineUsesAnchorCenter, bool& aBlockUsesAnchorCenter) { - aInlineUsesAnchorCenter = false; - aBlockUsesAnchorCenter = false; - nsIFrame* parent = aFrame->GetParent(); - if (!parent || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) || - !aAnchorPosResolutionCache || - !aAnchorPosResolutionCache->mDefaultAnchorCache.mAnchor) { - return; - } - - const auto* stylePos = aFrame->StylePosition(); - - auto checkAxis = [&](LogicalAxis aAxis) { - StyleAlignFlags alignment = - stylePos->UsedSelfAlignment(aAxis, parent->Style()); - return (alignment & ~StyleAlignFlags::FLAG_BITS) == - StyleAlignFlags::ANCHOR_CENTER; - }; - - aInlineUsesAnchorCenter = checkAxis(LogicalAxis::Inline); - aBlockUsesAnchorCenter = checkAxis(LogicalAxis::Block); -} - /** * Adjusts the margin for a list (ol, ul), if necessary, depending on * font inflation settings. Unfortunately, because bullets from a list are @@ -1755,8 +1719,11 @@ void ReflowInput::InitAbsoluteConstraints(const ReflowInput* aCBReflowInput, bool bStartIsAuto = bStartOffset->IsAuto(); bool bEndIsAuto = bEndOffset->IsAuto(); - mFlags.mIAnchorCenter = anchorResolutionParams.mBaseParams.mIAnchorCenter; - mFlags.mBAnchorCenter = anchorResolutionParams.mBaseParams.mBAnchorCenter; + // TODO(dshin): Needed anymore? + mFlags.mIAnchorCenter = anchorResolutionParams.mBaseParams + .mAutoResolutionOverrideParams.mIAnchorCenter; + mFlags.mBAnchorCenter = anchorResolutionParams.mBaseParams + .mAutoResolutionOverrideParams.mBAnchorCenter; // For anchor-center with both insets auto, insets need to be kept as 0 // so hypothetical position should be skipped. diff --git a/layout/generic/ReflowInput.h b/layout/generic/ReflowInput.h @@ -982,9 +982,4 @@ struct ReflowInput : public SizeComputationInput { } // namespace mozilla -void ComputeAnchorCenterUsage( - const nsIFrame* aFrame, - mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache, - bool& aInlineUsesAnchorCenter, bool& aBlockUsesAnchorCenter); - #endif // mozilla_ReflowInput_h diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp @@ -7229,7 +7229,7 @@ LogicalSize nsIFrame::ComputeAbsolutePosAutoSize( const auto* stylePos = StylePosition(); const auto anchorResolutionParams = AnchorPosOffsetResolutionParams::UseCBFrameSize( - AnchorPosResolutionParams::From(this)); + AnchorPosResolutionParams::From(&aSizingInput)); const auto& styleISize = aSizeOverrides.mStyleISize ? AnchorResolvedSizeHelper::Overridden(*aSizeOverrides.mStyleISize) diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h @@ -5911,17 +5911,8 @@ inline nsIFrame* nsFrameList::BackwardFrameTraversal::Prev(nsIFrame* aFrame) { inline AnchorPosResolutionParams AnchorPosResolutionParams::From( const nsIFrame* aFrame, mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache) { - bool inlineUsesAnchorCenter = false; - bool blockUsesAnchorCenter = false; - ComputeAnchorCenterUsage(aFrame, aAnchorPosResolutionCache, - inlineUsesAnchorCenter, blockUsesAnchorCenter); - - return {aFrame, - aFrame->StyleDisplay()->mPosition, - aFrame->StylePosition()->mPositionArea, - aAnchorPosResolutionCache, - inlineUsesAnchorCenter, - blockUsesAnchorCenter}; + return {aFrame, aFrame->StyleDisplay()->mPosition, aAnchorPosResolutionCache, + AutoResolutionOverrideParams{aFrame, aAnchorPosResolutionCache}}; } #endif /* nsIFrame_h___ */ diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h @@ -400,9 +400,12 @@ 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(); return {aComputedDOMStyle->mOuterFrame, - aComputedDOMStyle->StyleDisplay()->mPosition, - aComputedDOMStyle->StylePosition()->mPositionArea}; + aComputedDOMStyle->StyleDisplay()->mPosition, nullptr, overrides}; } #endif /* nsComputedDOMStyle_h__ */ diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp @@ -13,6 +13,7 @@ #include <algorithm> +#include "AnchorPositioningUtils.h" #include "CounterStyleManager.h" #include "ImageLoader.h" #include "imgIContainer.h" @@ -286,6 +287,75 @@ static StyleRect<T> StyleRectWithAllSides(const T& aSide) { return {aSide, aSide, aSide, aSide}; } +bool AnchorPosResolutionParams::AutoResolutionOverrideParams::OverriddenToZero( + StylePhysicalAxis aAxis, const nsIFrame* aFrame) const { + if (!aFrame || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) { + return false; + } + const auto* cb = aFrame->GetParent(); + const auto cbwm = cb->GetWritingMode(); + const auto logicalAxis = [&]() { + if (cbwm.IsVertical()) { + return aAxis == StylePhysicalAxis::Vertical ? LogicalAxis::Inline + : LogicalAxis::Block; + } + return aAxis == StylePhysicalAxis::Horizontal ? LogicalAxis::Inline + : LogicalAxis::Block; + }(); + return OverriddenToZero(logicalAxis); +} + +bool AnchorPosResolutionParams::AutoResolutionOverrideParams::OverriddenToZero( + Side aSide, const nsIFrame* aFrame) const { + return OverriddenToZero(aSide == Side::eSideBottom || aSide == Side::eSideTop + ? StylePhysicalAxis::Vertical + : StylePhysicalAxis::Horizontal, + aFrame); +} + +bool AnchorPosResolutionParams::AutoResolutionOverrideParams::OverriddenToZero( + LogicalAxis aAxis) const { + if (mPositionAreaInUse) { + // If `position-area` is used "Any auto inset properties resolve to 0": + // https://drafts.csswg.org/css-anchor-position-1/#valdef-position-area-position-area + return true; + } + + // If `anchor-center` is used with a valid anchor, "auto inset + // properties resolve to 0" on that axis: + // https://drafts.csswg.org/css-anchor-position-1/#anchor-center + switch (aAxis) { + case LogicalAxis::Block: + return mBAnchorCenter; + case LogicalAxis::Inline: + return mIAnchorCenter; + } +} + +AnchorPosResolutionParams::AutoResolutionOverrideParams:: + AutoResolutionOverrideParams( + const nsIFrame* aFrame, + const mozilla::AnchorPosResolutionCache* aCache) { + nsIFrame* parent = aFrame->GetParent(); + if (!parent || !aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) || !aCache || + !aCache->mDefaultAnchorCache.mAnchor) { + return; + } + + const auto* stylePos = aFrame->StylePosition(); + + auto checkAxis = [&](LogicalAxis aAxis) { + StyleAlignFlags alignment = + stylePos->UsedSelfAlignment(aAxis, parent->Style()); + return (alignment & ~StyleAlignFlags::FLAG_BITS) == + StyleAlignFlags::ANCHOR_CENTER; + }; + + mIAnchorCenter = checkAxis(LogicalAxis::Inline); + mBAnchorCenter = checkAxis(LogicalAxis::Block); + mPositionAreaInUse = !stylePos->mPositionArea.IsNone(); +} + AnchorResolvedMargin AnchorResolvedMarginHelper::ResolveAnchor( const StyleMargin& aValue, StylePhysicalAxis aAxis, const AnchorPosResolutionParams& aParams) { @@ -1328,25 +1398,6 @@ StyleSelfAlignment nsStylePosition::UsedJustifySelf( return {StyleAlignFlags::NORMAL}; } -bool AnchorResolvedInsetHelper::SideUsesAnchorCenter( - mozilla::Side aSide, const AnchorPosOffsetResolutionParams& aParams) { - const nsIFrame* frame = aParams.mBaseParams.mFrame; - if (!frame) { - return false; - } - const nsIFrame* parent = frame->GetParent(); - if (!parent) { - return false; - } - - WritingMode wm = parent->GetWritingMode(); - LogicalSide logicalSide = wm.LogicalSideForPhysicalSide(aSide); - LogicalAxis axis = GetAxis(logicalSide); - - return axis == LogicalAxis::Inline ? aParams.mBaseParams.mIAnchorCenter - : aParams.mBaseParams.mBAnchorCenter; -} - AnchorResolvedInset AnchorResolvedInsetHelper::ResolveAnchor( const mozilla::StyleInset& aValue, mozilla::StylePhysicalSide aSide, const AnchorPosOffsetResolutionParams& aParams) { diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h @@ -378,21 +378,35 @@ using AnchorResolvedMargin = // Base set of parameters required to resolve a reference to an anchor. struct AnchorPosResolutionParams { + struct AutoResolutionOverrideParams { + // TODO(dshin): Probably just make it physical + // Whether anchor-center is being used on the inline axis. + bool mIAnchorCenter = false; + // Whether anchor-center is being used on the block axis. + bool mBAnchorCenter = false; + // Whether position-area is being used. + bool mPositionAreaInUse = false; + + AutoResolutionOverrideParams() = default; + AutoResolutionOverrideParams( + const nsIFrame* aFrame, + const mozilla::AnchorPosResolutionCache* aCache); + + bool OverriddenToZero(mozilla::StylePhysicalAxis aAxis, + const nsIFrame* aFrame) const; + bool OverriddenToZero(mozilla::Side aSide, const nsIFrame* aFrame) const; + bool OverriddenToZero(mozilla::LogicalAxis aAxis) const; + }; // Frame of the anchor positioned element. // If nullptr, skips anchor lookup and returns invalid, resolving fallbacks. const nsIFrame* mFrame; // Position property of the element in question. mozilla::StylePositionProperty mPosition; - // position-area property of the element in question. - mozilla::StylePositionArea mPositionArea; // Cache data used for anchor resolution. mozilla::AnchorPosResolutionCache* const mCache; - // Whether anchor-center is being used with a valid anchor on the inline axis. - // When true, auto insets in the inline axis resolve to 0. - bool mIAnchorCenter = false; - // Whether anchor-center is being used with a valid anchor on the block axis. - // When true, auto insets in the block axis resolve to 0. - bool mBAnchorCenter = false; + // Set of parameters that override `auto` values to 0, if the default + // anchor is valid. + AutoResolutionOverrideParams mAutoResolutionOverrideParams; // Helper functions for creating anchor resolution parameters. // Defined in corresponding header files. @@ -416,16 +430,18 @@ struct AnchorResolvedMarginHelper { static AnchorResolvedMargin FromUnresolved( const mozilla::StyleMargin& aValue, mozilla::StylePhysicalAxis aAxis, const AnchorPosResolutionParams& aParams) { - if (aValue.HasAnchorPositioningFunction()) { - return ResolveAnchor(aValue, aAxis, aParams); - } - // For `position-area` values other than `none`, the used value of `auto` - // margin properties resolves to 0: - // <https://drafts.csswg.org/css-anchor-position-1/#valdef-position-area-position-area> - if (aValue.IsAuto() && !aParams.mPositionArea.IsNone()) { + auto resolved = [&]() { + if (aValue.HasAnchorPositioningFunction()) { + return ResolveAnchor(aValue, aAxis, aParams); + } + return AnchorResolvedMargin::NonOwning(&aValue); + }(); + if (resolved->IsAuto() && + aParams.mAutoResolutionOverrideParams.OverriddenToZero( + aAxis, aParams.mFrame)) { return Zero(); } - return AnchorResolvedMargin::NonOwning(&aValue); + return resolved; } private: @@ -780,24 +796,28 @@ struct AnchorResolvedInsetHelper { return value; } + static const mozilla::StyleInset& ZeroValue() { + static const auto value = mozilla::StyleInset::LengthPercentage( + mozilla::StyleLengthPercentage::Zero()); + return value; + } + static AnchorResolvedInset FromUnresolved( const mozilla::StyleInset& aValue, mozilla::Side aSide, const AnchorPosOffsetResolutionParams& aParams) { - if (aValue.HasAnchorPositioningFunction()) { - return ResolveAnchor(aValue, mozilla::ToStylePhysicalSide(aSide), - aParams); - } - // If `position-area` is used "Any auto inset properties resolve to 0": - // https://drafts.csswg.org/css-anchor-position-1/#valdef-position-area-position-area - // If `anchor-center` is used with a valid anchor, "auto inset - // properties resolve to 0": - // https://drafts.csswg.org/css-anchor-position-1/#anchor-center - if (aValue.IsAuto() && (!aParams.mBaseParams.mPositionArea.IsNone() || - SideUsesAnchorCenter(aSide, aParams))) { - return AnchorResolvedInset::UniquelyOwning( - new mozilla::StyleInset(mozilla::LengthPercentage::Zero())); + auto resolved = [&]() { + if (aValue.HasAnchorPositioningFunction()) { + return ResolveAnchor(aValue, mozilla::ToStylePhysicalSide(aSide), + aParams); + } + return AnchorResolvedInset::NonOwning(&aValue); + }(); + if (resolved->IsAuto() && + aParams.mBaseParams.mAutoResolutionOverrideParams.OverriddenToZero( + aSide, aParams.mBaseParams.mFrame)) { + return AnchorResolvedInset::NonOwning(&ZeroValue()); } - return AnchorResolvedInset::NonOwning(&aValue); + return resolved; } private: @@ -805,9 +825,6 @@ struct AnchorResolvedInsetHelper { return AnchorResolvedInset::NonOwning(&AutoValue()); } - static bool SideUsesAnchorCenter( - mozilla::Side aSide, const AnchorPosOffsetResolutionParams& aParams); - static AnchorResolvedInset ResolveAnchor( const mozilla::StyleInset& aValue, mozilla::StylePhysicalSide aSide, const AnchorPosOffsetResolutionParams& aParams); diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs @@ -10799,10 +10799,8 @@ fn offset_params_from_base_params( mBaseParams: AnchorPosResolutionParams { mFrame: params.mFrame, mPosition: params.mPosition, - mPositionArea: params.mPositionArea, mCache: params.mCache, - mIAnchorCenter: params.mIAnchorCenter, - mBAnchorCenter: params.mBAnchorCenter, + mAutoResolutionOverrideParams: params.mAutoResolutionOverrideParams, }, } } diff --git a/testing/web-platform/meta/css/css-anchor-position/position-area-basic.html.ini b/testing/web-platform/meta/css/css-anchor-position/position-area-basic.html.ini @@ -1,3 +0,0 @@ -[position-area-basic.html] - [Offsets for: span-all top] - expected: FAIL