tor-browser

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

commit e6479485e316c7f203a252f7492de0a0469e9a44
parent e7f0af00dbe76b831d710e00e15a7b5631c0c984
Author: David Shin <dshin@mozilla.com>
Date:   Thu, 30 Oct 2025 22:27:11 +0000

Bug 1968745: Pass short-lived cache into anchor resolution. r=jwatt

... So that we can store default anchor related data for a reflow to use for
determining if we need to compensate for scroll.

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

Diffstat:
Mlayout/base/AnchorPositioningUtils.h | 18++++++++++++++++++
Mlayout/generic/AbsoluteContainingBlock.cpp | 29++++++++++++++++-------------
Mlayout/generic/AbsoluteContainingBlock.h | 17++++++++---------
Mlayout/generic/ReflowInput.cpp | 28++++++++++++++--------------
Mlayout/generic/ReflowInput.h | 16++++++++--------
Mlayout/generic/nsIFrame.h | 4++--
Mlayout/style/GeckoBindings.cpp | 20++++++++++++++------
Mlayout/style/nsStyleStruct.h | 9++++-----
Mservo/ports/geckolib/glue.rs | 2+-
9 files changed, 85 insertions(+), 58 deletions(-)

diff --git a/layout/base/AnchorPositioningUtils.h b/layout/base/AnchorPositioningUtils.h @@ -83,6 +83,24 @@ class AnchorPosReferenceData { struct StylePositionArea; class WritingMode; +struct AnchorPosDefaultAnchorCache { + // Default anchor element's corresponding frame. + const nsIFrame* mAnchor = nullptr; + // Scroll container for the default anchor. + const nsIFrame* mScrollContainer = nullptr; +}; + +// Cache data used by anchor resolution. To be populated on abspos reflow, +// whenever the frame makes any anchor reference. +struct AnchorPosResolutionCache { + // Storage for referenced anchors. Designed to be long-lived (i.e. beyond + // a reflow cycle). + AnchorPosReferenceData* mReferenceData = nullptr; + // Cached data for default anchor resolution. Designed to be short-lived, + // so it can contain e.g. frame pointers. + AnchorPosDefaultAnchorCache mDefaultAnchorCache; +}; + enum class StylePositionTryFallbacksTryTacticKeyword : uint8_t; using StylePositionTryFallbacksTryTactic = CopyableTArray<StylePositionTryFallbacksTryTacticKeyword>; diff --git a/layout/generic/AbsoluteContainingBlock.cpp b/layout/generic/AbsoluteContainingBlock.cpp @@ -177,10 +177,12 @@ void AbsoluteContainingBlock::Reflow(nsContainerFrame* aDelegatingFrame, aFlags.contains(AbsPosReflowFlag::CBHeightChanged); nsOverflowContinuationTracker tracker(aDelegatingFrame, true); for (nsIFrame* kidFrame : mAbsoluteFrames) { - AnchorPosReferenceData* anchorPosReferenceData = nullptr; + Maybe<AnchorPosResolutionCache> anchorPosResolutionCache; if (kidFrame->HasAnchorPosReference()) { - anchorPosReferenceData = kidFrame->SetOrUpdateDeletableProperty( - nsIFrame::AnchorPosReferences()); + anchorPosResolutionCache = Some(AnchorPosResolutionCache{}); + anchorPosResolutionCache->mReferenceData = + kidFrame->SetOrUpdateDeletableProperty( + nsIFrame::AnchorPosReferences()); } else { kidFrame->RemoveProperty(nsIFrame::AnchorPosReferences()); } @@ -188,7 +190,7 @@ void AbsoluteContainingBlock::Reflow(nsContainerFrame* aDelegatingFrame, bool kidNeedsReflow = reflowAll || kidFrame->IsSubtreeDirty() || FrameDependsOnContainer(kidFrame, cbWidthChanged, cbHeightChanged, - anchorPosReferenceData); + anchorPosResolutionCache.ptrOr(nullptr)); if (kidFrame->IsSubtreeDirty()) { MaybeMarkAncestorsAsHavingDescendantDependentOnItsStaticPos( kidFrame, aDelegatingFrame); @@ -229,7 +231,8 @@ void AbsoluteContainingBlock::Reflow(nsContainerFrame* aDelegatingFrame, nsReflowStatus kidStatus; ReflowAbsoluteFrame(aDelegatingFrame, aPresContext, aReflowInput, aContainingBlock, aFlags, kidFrame, kidStatus, - aOverflowAreas, anchorPosReferenceData); + aOverflowAreas, + anchorPosResolutionCache.ptrOr(nullptr)); MOZ_ASSERT(!kidStatus.IsInlineBreakBefore(), "ShouldAvoidBreakInside should prevent this from happening"); nsIFrame* nextFrame = kidFrame->GetNextInFlow(); @@ -305,7 +308,7 @@ static inline bool IsFixedOffset(const AnchorResolvedInset& aInset) { bool AbsoluteContainingBlock::FrameDependsOnContainer( nsIFrame* f, bool aCBWidthChanged, bool aCBHeightChanged, - AnchorPosReferenceData* anchorPosReferenceData) { + AnchorPosResolutionCache* aAnchorPosResolutionCache) { const nsStylePosition* pos = f->StylePosition(); // See if f's position might have changed because it depends on a // placeholder's position. @@ -320,7 +323,7 @@ bool AbsoluteContainingBlock::FrameDependsOnContainer( const nsStyleMargin* margin = f->StyleMargin(); WritingMode wm = f->GetWritingMode(); const auto anchorResolutionParams = - AnchorPosResolutionParams::From(f, anchorPosReferenceData); + AnchorPosResolutionParams::From(f, aAnchorPosResolutionCache); if (wm.IsVertical() ? aCBHeightChanged : aCBWidthChanged) { // See if f's inline-size might have changed. // If margin-inline-start/end, padding-inline-start/end, @@ -868,7 +871,7 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( const ReflowInput& aReflowInput, const nsRect& aOriginalContainingBlockRect, AbsPosReflowFlags aFlags, nsIFrame* aKidFrame, nsReflowStatus& aStatus, OverflowAreas* aOverflowAreas, - AnchorPosReferenceData* aAnchorPosReferenceData) { + AnchorPosResolutionCache* aAnchorPosResolutionCache) { MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!"); #ifdef DEBUG @@ -939,7 +942,7 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( // TODO(emilio): Right now fallback only applies to position-area, which only // makes a difference with a default anchor... Generalize it? - if (aAnchorPosReferenceData) { + if (aAnchorPosResolutionCache) { bool found = false; uint32_t index = aKidFrame->GetProperty( nsIFrame::LastSuccessfulPositionFallback(), &found); @@ -967,9 +970,9 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( positionArea = currentFallback->AsPositionArea(); } - if (!positionArea.IsNone()) { + if (!positionArea.IsNone() && aAnchorPosResolutionCache) { const auto defaultAnchorInfo = AnchorPositioningUtils::GetDefaultAnchor( - aKidFrame, false, aAnchorPosReferenceData); + aKidFrame, false, aAnchorPosResolutionCache->mReferenceData); if (defaultAnchorInfo.mRect) { return AnchorPositioningUtils:: AdjustAbsoluteContainingBlockRectForPositionArea( @@ -1056,7 +1059,7 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( ReflowInput kidReflowInput(aPresContext, aReflowInput, aKidFrame, availSize.ConvertTo(wm, outerWM), Some(cbSize.ConvertTo(wm, outerWM)), initFlags, - {}, {}, aAnchorPosReferenceData); + {}, {}, aAnchorPosResolutionCache); if (nscoord kidAvailBSize = kidReflowInput.AvailableBSize(); kidAvailBSize != NS_UNCONSTRAINEDSIZE) { @@ -1111,7 +1114,7 @@ void AbsoluteContainingBlock::ReflowAbsoluteFrame( const auto anchorResolutionParams = AnchorPosOffsetResolutionParams::ExplicitCBFrameSize( AnchorPosResolutionParams::From(aKidFrame, - aAnchorPosReferenceData), + aAnchorPosResolutionCache), &cbSize); const bool iInsetAuto = stylePos diff --git a/layout/generic/AbsoluteContainingBlock.h b/layout/generic/AbsoluteContainingBlock.h @@ -110,7 +110,7 @@ class AbsoluteContainingBlock { */ bool FrameDependsOnContainer( nsIFrame* aFrame, bool aCBWidthChanged, bool aCBHeightChanged, - AnchorPosReferenceData* aAnchorPosReferenceData = nullptr); + mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr); /** * After an abspos child's size is known, this method can be used to @@ -145,14 +145,13 @@ class AbsoluteContainingBlock { LogicalMargin& aMargin, LogicalMargin& aOffsets); - void ReflowAbsoluteFrame(nsIFrame* aDelegatingFrame, - nsPresContext* aPresContext, - const ReflowInput& aReflowInput, - const nsRect& aOriginalContainingBlockRect, - AbsPosReflowFlags aFlags, nsIFrame* aKidFrame, - nsReflowStatus& aStatus, - OverflowAreas* aOverflowAreas, - AnchorPosReferenceData* aAnchorPosReferenceData); + void ReflowAbsoluteFrame( + nsIFrame* aDelegatingFrame, nsPresContext* aPresContext, + const ReflowInput& aReflowInput, + const nsRect& aOriginalContainingBlockRect, AbsPosReflowFlags aFlags, + nsIFrame* aKidFrame, nsReflowStatus& aStatus, + OverflowAreas* aOverflowAreas, + mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr); /** * Mark our absolute frames dirty. diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp @@ -109,10 +109,10 @@ static nscoord FontSizeInflationListMarginAdjustment(const nsIFrame* aFrame) { SizeComputationInput::SizeComputationInput( nsIFrame* aFrame, gfxContext* aRenderingContext, - AnchorPosReferenceData* aAnchorPosReferenceData) + AnchorPosResolutionCache* aAnchorPosResolutionCache) : mFrame(aFrame), mRenderingContext(aRenderingContext), - mAnchorPosReferenceData(aAnchorPosReferenceData), + mAnchorPosResolutionCache(aAnchorPosResolutionCache), mWritingMode(aFrame->GetWritingMode()), mIsThemed(aFrame->IsThemed()), mComputedMargin(mWritingMode), @@ -180,9 +180,9 @@ ReflowInput::ReflowInput(nsPresContext* aPresContext, InitFlags aFlags, const StyleSizeOverrides& aSizeOverrides, ComputeSizeFlags aComputeSizeFlags, - AnchorPosReferenceData* aAnchorPosReferenceData) + AnchorPosResolutionCache* aAnchorPosResolutionCache) : SizeComputationInput(aFrame, aParentReflowInput.mRenderingContext, - aAnchorPosReferenceData), + aAnchorPosResolutionCache), mParentReflowInput(&aParentReflowInput), mFloatManager(aParentReflowInput.mFloatManager), mLineLayout(mFrame->IsLineParticipant() ? aParentReflowInput.mLineLayout @@ -212,7 +212,7 @@ ReflowInput::ReflowInput(nsPresContext* aPresContext, bool* aFixed = nullptr) -> nscoord { nscoord limit = NS_UNCONSTRAINEDSIZE; const auto* pos = aFrame->StylePosition(); - // Don't add to referenced anchors, since this function is called for + // Don't add to anchor resolution cache, since this function is called for // other frames. const auto anchorResolutionParams = AnchorPosResolutionParams::From(aFrame); @@ -365,13 +365,13 @@ nscoord SizeComputationInput::ComputeISizeValue( contentEdgeToBoxSizing.ISize(wm); return mFrame - ->ComputeISizeValue( - mRenderingContext, wm, aContainingBlockSize, contentEdgeToBoxSizing, - boxSizingToMarginEdgeISize, aSize, - *mFrame->StylePosition()->BSize( - wm, - AnchorPosResolutionParams::From(mFrame, mAnchorPosReferenceData)), - mFrame->GetAspectRatio()) + ->ComputeISizeValue(mRenderingContext, wm, aContainingBlockSize, + contentEdgeToBoxSizing, boxSizingToMarginEdgeISize, + aSize, + *mFrame->StylePosition()->BSize( + wm, AnchorPosResolutionParams::From( + mFrame, mAnchorPosResolutionCache)), + mFrame->GetAspectRatio()) .mISize; } @@ -527,7 +527,7 @@ void ReflowInput::Init(nsPresContext* aPresContext, nsIFrame* containingBlk = mFrame; while (containingBlk) { const nsStylePosition* stylePos = containingBlk->StylePosition(); - // It's for containing block, so don't add to referenced anchors + // It's for containing block, so don't add to anchor resolution cache const auto containingBlkAnchorResolutionParams = AnchorPosResolutionParams::From(containingBlk); const auto bSizeCoord = @@ -2945,7 +2945,7 @@ bool SizeComputationInput::ComputeMargin(WritingMode aCBWM, } LogicalMargin m(aCBWM); const auto anchorResolutionParams = - AnchorPosResolutionParams::From(mFrame, mAnchorPosReferenceData); + AnchorPosResolutionParams::From(mFrame, mAnchorPosResolutionCache); for (const LogicalSide side : LogicalSides::All) { m.Side(side, aCBWM) = nsLayoutUtils::ComputeCBDependentValue( aPercentBasis, diff --git a/layout/generic/ReflowInput.h b/layout/generic/ReflowInput.h @@ -68,8 +68,8 @@ struct SizeComputationInput { // Rendering context to use for measurement. gfxContext* mRenderingContext; - // Cache of referenced anchors for this computation. - AnchorPosReferenceData* mAnchorPosReferenceData = nullptr; + // Cache for anchor resolution in this computation. + AnchorPosResolutionCache* mAnchorPosResolutionCache = nullptr; nsMargin ComputedPhysicalMargin() const { return mComputedMargin.GetPhysicalMargin(mWritingMode); @@ -132,7 +132,7 @@ struct SizeComputationInput { // Callers using this constructor must call InitOffsets on their own. SizeComputationInput( nsIFrame* aFrame, gfxContext* aRenderingContext, - AnchorPosReferenceData* aAnchorPosReferenceData = nullptr); + AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr); SizeComputationInput(nsIFrame* aFrame, gfxContext* aRenderingContext, WritingMode aContainingBlockWritingMode, @@ -626,9 +626,9 @@ struct ReflowInput : public SizeComputationInput { * call nsIFrame::ComputeSize() internally. * @param aComputeSizeFlags A set of flags used when we call * nsIFrame::ComputeSize() internally. - * @param aAnchorPosReferenceData A cache of referenced anchors to be - * populated (If specified) for this reflowed frame. Should live for the - * lifetime of this ReflowInput. + * @param aAnchorResolutionCache A cache of referenced anchors to be populated + * (If specified) for this reflowed frame. Should live for the lifetime + * of this ReflowInput. */ ReflowInput(nsPresContext* aPresContext, const ReflowInput& aParentReflowInput, nsIFrame* aFrame, @@ -637,7 +637,7 @@ struct ReflowInput : public SizeComputationInput { InitFlags aFlags = {}, const StyleSizeOverrides& aSizeOverrides = {}, ComputeSizeFlags aComputeSizeFlags = {}, - AnchorPosReferenceData* aAnchorPosReferenceData = nullptr); + AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr); /** * This method initializes various data members. It is automatically called by @@ -985,7 +985,7 @@ inline AnchorPosResolutionParams AnchorPosResolutionParams::From( aIgnorePositionArea ? mozilla::StylePositionArea{} : aRI->mStylePosition->mPositionArea; return {aRI->mFrame, aRI->mStyleDisplay->mPosition, posArea, - aRI->mAnchorPosReferenceData}; + aRI->mAnchorPosResolutionCache}; } #endif // mozilla_ReflowInput_h diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h @@ -5921,9 +5921,9 @@ inline nsIFrame* nsFrameList::BackwardFrameTraversal::Prev(nsIFrame* aFrame) { inline AnchorPosResolutionParams AnchorPosResolutionParams::From( const nsIFrame* aFrame, - mozilla::AnchorPosReferenceData* aAnchorPosReferenceData) { + mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache) { return {aFrame, aFrame->StyleDisplay()->mPosition, - aFrame->StylePosition()->mPositionArea, aAnchorPosReferenceData}; + aFrame->StylePosition()->mPositionArea, aAnchorPosResolutionCache}; } #endif /* nsIFrame_h___ */ diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp @@ -1897,6 +1897,14 @@ static Maybe<AnchorPosInfo> GetAnchorPosRect( aCBRectIsvalid, entry); } +static AnchorPosReferenceData* GetReferenceData( + const AnchorPosResolutionParams& aParams) { + if (!aParams.mCache) { + return nullptr; + } + return aParams.mCache->mReferenceData; +} + bool Gecko_GetAnchorPosOffset(const AnchorPosOffsetResolutionParams* aParams, const nsAtom* aAnchorName, StylePhysicalSide aPropSide, @@ -1911,9 +1919,9 @@ bool Gecko_GetAnchorPosOffset(const AnchorPosOffsetResolutionParams* aParams, // Note: No exit on null anchorName: Instead, GetAnchorPosRect may return the // containing block. - const auto info = GetAnchorPosRect( - aParams->mBaseParams.mFrame, anchorName, !aParams->mCBSize, - aParams->mBaseParams.mAnchorPosReferenceData); + const auto info = GetAnchorPosRect(aParams->mBaseParams.mFrame, anchorName, + !aParams->mCBSize, + GetReferenceData(aParams->mBaseParams)); if (info.isNothing()) { return false; } @@ -2004,9 +2012,9 @@ bool Gecko_GetAnchorPosSize(const AnchorPosResolutionParams* aParams, } const auto size = [&]() -> Maybe<nsSize> { Maybe<AnchorPosResolutionData>* entry = nullptr; - if (aParams->mAnchorPosReferenceData) { - const auto result = - aParams->mAnchorPosReferenceData->InsertOrModify(anchorName, false); + auto* referencedAnchors = GetReferenceData(*aParams); + if (referencedAnchors) { + const auto result = referencedAnchors->InsertOrModify(anchorName, false); if (result.mAlreadyResolved) { MOZ_ASSERT(result.mEntry, "Entry exists but null?"); return result.mEntry->map( diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h @@ -43,7 +43,7 @@ namespace mozilla { class ComputedStyle; struct IntrinsicSize; struct ReflowInput; -class AnchorPosReferenceData; +struct AnchorPosResolutionCache; } // namespace mozilla @@ -390,15 +390,14 @@ struct AnchorPosResolutionParams { mozilla::StylePositionProperty mPosition; // position-area property of the element in question. mozilla::StylePositionArea mPositionArea; - // Storage for anchor reference data. To be populated on abspos reflow, - // whenever the frame makes any anchor reference. - mozilla::AnchorPosReferenceData* const mAnchorPosReferenceData = nullptr; + // Cache data used for anchor resolution. + mozilla::AnchorPosResolutionCache* const mCache; // Helper functions for creating anchor resolution parameters. // Defined in corresponding header files. static inline AnchorPosResolutionParams From( const nsIFrame* aFrame, - mozilla::AnchorPosReferenceData* aAnchorPosReferenceData = nullptr); + mozilla::AnchorPosResolutionCache* aAnchorPosResolutionCache = nullptr); static inline AnchorPosResolutionParams From( const mozilla::ReflowInput* aRI, bool aIgnorePositionArea = false); static inline AnchorPosResolutionParams From( diff --git a/servo/ports/geckolib/glue.rs b/servo/ports/geckolib/glue.rs @@ -10722,7 +10722,7 @@ fn offset_params_from_base_params( mFrame: params.mFrame, mPosition: params.mPosition, mPositionArea: params.mPositionArea, - mAnchorPosReferenceData: params.mAnchorPosReferenceData, + mCache: params.mCache, }, } }