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:
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) {