tor-browser

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

commit 878d1288a77241ee489677b28a2d8799bc8627fc
parent 2a1d70136b8cdd09919940f398782660742b7236
Author: Jonathan Kew <jkew@mozilla.com>
Date:   Thu,  2 Oct 2025 10:02:01 +0000

Bug 1991943 - Try to skip some text-autospace work if no CJK glyph runs are present. r=layout-reviewers,dshin,TYLin

For the GlyphRuns in a given gfxTextRun, we already track whether they are
associated with a CJK script, so we can use this knowledge to potentially
avoid some auto-spacing work when the textrun is known to be CJK-free. This
extends the previous idea of checking whether the character buffer is 2-byte,
and should let us skip the character-class processing in more cases.

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

Diffstat:
Mlayout/generic/nsTextFrame.cpp | 42++++++++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 12 deletions(-)

diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp @@ -4054,6 +4054,18 @@ static Maybe<TextAutospace::CharClass> GetPrecedingCharClassFromFrameTree( return Nothing(); } +static bool HasCJKGlyphRun(const gfxTextRun* aTextRun) { + uint32_t numGlyphRuns; + const gfxTextRun::GlyphRun* run = aTextRun->GetGlyphRuns(&numGlyphRuns); + while (numGlyphRuns-- > 0) { + if (run->mIsCJK) { + return true; + } + run++; + } + return false; +} + void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs) const { @@ -4065,16 +4077,9 @@ void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, return; } - // Find our offset into the original+transformed string - gfxSkipCharsIterator start(mStart); - start.SetSkippedOffset(aRange.start); - // First, compute the word spacing, letter spacing, and text-autospace // spacing. if (mWordSpacing || mLetterSpacing || mTextAutospace) { - // Iterate over non-skipped characters - nsSkipCharsRunIterator run( - start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length()); bool newlineIsSignificant = mTextStyle->NewlineIsSignificant(mFrame); // Which letter-spacing model are we using? // 0 - Gecko legacy model, spacing added to trailing side of letter @@ -4101,6 +4106,10 @@ void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, after = mLetterSpacing - before; break; } + + // Find our offset into the original+transformed string + gfxSkipCharsIterator start(mStart); + start.SetSkippedOffset(aRange.start); bool atStart = mStartOfLineOffset == start.GetSkippedOffset() && !mFrame->IsInSVGTextSubtree(); @@ -4143,6 +4152,14 @@ void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, return prevClass.valueOr(CharClass::Other); }; + // If text-autospace is enabled, we may be able to skip some processing if + // there are no CJK glyphs in the textrun, so check for their presence. + bool textIncludesCJK = mTextAutospace && mCharacterDataBuffer.Is2b() && + HasCJKGlyphRun(mTextRun); + + // Iterate over non-skipped characters + nsSkipCharsRunIterator run( + start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length()); while (run.NextRun()) { uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start; gfxSkipCharsIterator iter = run.GetPos(); @@ -4169,18 +4186,19 @@ void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, uint32_t runOffset = iter.GetSkippedOffset() - aRange.start; aSpacing[runOffset].mAfter += mWordSpacing; } - // Add text-autospace spacing only at cluster starts. Always check - // 2-byte text; for 1-byte, check only at the frame start (a preceding - // content might be an ideograph requiring autospacing). + // Add text-autospace spacing only at cluster starts. Always check the + // character classes if the textrun includes CJK; otherwise, check only + // at the frame start (as preceding content might be an ideograph + // requiring autospacing). if (mTextAutospace && - (mCharacterDataBuffer.Is2b() || + (textIncludesCJK || run.GetOriginalOffset() + i == mFrame->GetContentOffset()) && mTextRun->IsClusterStart(run.GetSkippedOffset() + i)) { const char32_t currScalar = mCharacterDataBuffer.ScalarValueAt(run.GetOriginalOffset() + i); const auto currClass = TextAutospace::GetCharClass(currScalar); - // It is rare for the current class to be is a combining mark, as + // It is rare for the current class to be a combining mark, as // combining marks are not cluster starts. We still check in case a // stray mark appears at the start of a frame. if (currClass != CharClass::CombiningMark) {