tor-browser

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

commit 4bc276362491d28731154efdf229b95463e4ef29
parent 26fd9020d71577fa82471cde3b0004e0415b7c5d
Author: Jonathan Kew <jkew@mozilla.com>
Date:   Sat,  4 Oct 2025 09:10:54 +0000

Bug 1991689 - Cache advances of text ranges measured by TextRenderedRun::GetClipEdges in the root SVGTextFrame to accelerate ReflowSVG. r=firefox-svg-reviewers,longsonr

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

Diffstat:
Mgfx/thebes/gfxTextRun.h | 4++++
Mlayout/svg/SVGTextFrame.cpp | 63++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mlayout/svg/SVGTextFrame.h | 27+++++++++++++++++++++++++++
3 files changed, 81 insertions(+), 13 deletions(-)

diff --git a/gfx/thebes/gfxTextRun.h b/gfx/thebes/gfxTextRun.h @@ -163,6 +163,10 @@ class gfxTextRun : public gfxShapedText { Range(uint32_t aStart, uint32_t aEnd) : start(aStart), end(aEnd) {} explicit Range(const gfxTextRun* aTextRun) : Range(0, aTextRun->GetLength()) {} + + bool Intersects(const Range& aOther) const { + return start < aOther.end && end > aOther.start; + } }; // All coordinates are in layout/app units diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp @@ -409,13 +409,14 @@ struct TextRenderedRun { * paint it. See the comments documenting the member variables below * for descriptions of the arguments. */ - TextRenderedRun(nsTextFrame* aFrame, const gfxPoint& aPosition, - float aLengthAdjustScaleFactor, double aRotate, - float aFontSizeScaleFactor, nscoord aBaseline, + TextRenderedRun(nsTextFrame* aFrame, SVGTextFrame* aSVGTextFrame, + const gfxPoint& aPosition, float aLengthAdjustScaleFactor, + double aRotate, float aFontSizeScaleFactor, nscoord aBaseline, uint32_t aTextFrameContentOffset, uint32_t aTextFrameContentLength, uint32_t aTextElementCharIndex) : mFrame(aFrame), + mRoot(aSVGTextFrame), mPosition(aPosition), mLengthAdjustScaleFactor(aLengthAdjustScaleFactor), mRotate(static_cast<float>(aRotate)), @@ -662,6 +663,11 @@ struct TextRenderedRun { nsTextFrame* mFrame; /** + * The SVGTextFrame to which our text frame belongs. + */ + SVGTextFrame* mRoot; + + /** * The point in user space that the text is positioned at. * * For a horizontal run: @@ -962,15 +968,43 @@ void TextRenderedRun::GetClipEdges(nscoord& aVisIStartEdge, // characters. Range frameRange = ConvertOriginalToSkipped(it, frameOffset, frameLength); - // Measure the advance width in the text run between the start of - // frame's content and the start of the rendered run's content, - nscoord startEdge = textRun->GetAdvanceWidth( - Range(frameRange.start, runRange.start), &provider); + // Get the advance of aRange, using the aCachedRange if available to + // accelerate textrun measurement. + auto MeasureUsingCache = [&](SVGTextFrame::CachedMeasuredRange& aCachedRange, + const Range& aRange) -> nscoord { + if (aRange.Intersects(aCachedRange.mRange)) { + // We only need to measure the differences between the cached range and + // aRange. + // TODO: check whether this will in fact involve less measurement! + if (aRange.start < aCachedRange.mRange.start) { + aCachedRange.mAdvance += textRun->GetAdvanceWidth( + Range(aRange.start, aCachedRange.mRange.start), &provider); + } else if (aRange.start > aCachedRange.mRange.start) { + aCachedRange.mAdvance -= textRun->GetAdvanceWidth( + Range(aCachedRange.mRange.start, aRange.start), &provider); + } + if (aRange.end > aCachedRange.mRange.end) { + aCachedRange.mAdvance += textRun->GetAdvanceWidth( + Range(aCachedRange.mRange.end, aRange.end), &provider); + } else if (aRange.end < aCachedRange.mRange.end) { + aCachedRange.mAdvance -= textRun->GetAdvanceWidth( + Range(aRange.end, aCachedRange.mRange.end), &provider); + } + } else { + // Just measure the range, and cache the result. + aCachedRange.mAdvance = textRun->GetAdvanceWidth(aRange, &provider); + } + aCachedRange.mRange = aRange; + return aCachedRange.mAdvance; + }; - // and between the end of the rendered run's content and the end - // of the frame's content. + mRoot->SetCurrentFrameForCaching(mFrame); + nscoord startEdge = + MeasureUsingCache(mRoot->CachedRange(SVGTextFrame::WhichRange::Before), + Range(frameRange.start, runRange.start)); nscoord endEdge = - textRun->GetAdvanceWidth(Range(runRange.end, frameRange.end), &provider); + MeasureUsingCache(mRoot->CachedRange(SVGTextFrame::WhichRange::After), + Range(runRange.end, frameRange.end)); if (textRun->IsRightToLeft()) { aVisIStartEdge = endEdge; @@ -1900,9 +1934,9 @@ TextRenderedRun TextRenderedRunIterator::Next() { } } - mCurrent = TextRenderedRun(frame, pt, Root()->mLengthAdjustScaleFactor, - rotate, mFontSizeScaleFactor, baseline, offset, - length, charIndex); + mCurrent = TextRenderedRun( + frame, Root(), pt, Root()->mLengthAdjustScaleFactor, rotate, + mFontSizeScaleFactor, baseline, offset, length, charIndex); return mCurrent; } @@ -5108,6 +5142,9 @@ void SVGTextFrame::DoReflow() { RemoveStateBits(NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); } + // Forget any cached measurements of one of our children. + mFrameForCachedRanges = nullptr; + nsPresContext* presContext = PresContext(); nsIFrame* kid = PrincipalChildList().FirstChild(); if (!kid) { diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h @@ -586,6 +586,33 @@ class SVGTextFrame final : public SVGDisplayContainerFrame { * lengthAdjust="spacingAndGlyphs". */ float mLengthAdjustScaleFactor = 1.0f; + + public: + struct CachedMeasuredRange { + Range mRange; + nscoord mAdvance; + }; + + void SetCurrentFrameForCaching(const nsTextFrame* aFrame) { + if (mFrameForCachedRanges != aFrame) { + PodArrayZero(mCachedRanges); + mFrameForCachedRanges = aFrame; + } + } + + enum WhichRange { + Before, + After, + CachedRangeCount, + }; + + CachedMeasuredRange& CachedRange(WhichRange aWhichRange) { + return mCachedRanges[aWhichRange]; + } + + private: + const nsTextFrame* mFrameForCachedRanges = nullptr; + CachedMeasuredRange mCachedRanges[CachedRangeCount]; }; } // namespace mozilla