Bug 1882790 - Use a custom ReplaceSeparators function in place of nsString::ReplaceChar during bidi resolution. r=layout-reviewers,emilio

In nsBidiPresUtils::ResolveParagraph, we replace any block or segment separators
with space characters before bidi resolution. The use of nsString::ReplaceChar
here can appear in profiles, so it seems worth having a custom accelerated version
to handle the fixed set of separator codes. My local testing indicates this runs
between 5 and 10 times faster than the general-purpose function that has to
iterate over the provided set of characters at runtime.

Differential Revision: https://phabricator.services.mozilla.com/D203125
This commit is contained in:
Jonathan Kew 2024-03-05 10:56:12 +00:00
Родитель f36f93cf6d
Коммит bf0cabbac6
1 изменённых файлов: 37 добавлений и 5 удалений

Просмотреть файл

@ -60,7 +60,8 @@ static const char16_t kLRI = 0x2066;
static const char16_t kRLI = 0x2067;
static const char16_t kFSI = 0x2068;
static const char16_t kPDI = 0x2069;
// All characters with Bidi type Segment Separator or Block Separator
// All characters with Bidi type Segment Separator or Block Separator.
// This should be kept in sync with the table in ReplaceSeparators.
static const char16_t kSeparators[] = {
char16_t('\t'), char16_t('\r'), char16_t('\n'), char16_t(0xb),
char16_t(0x1c), char16_t(0x1d), char16_t(0x1e), char16_t(0x1f),
@ -854,11 +855,32 @@ nsresult nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame) {
return ResolveParagraph(&bpd);
}
// In ResolveParagraph, we previously used ReplaceChar(kSeparators, kSpace)
// to convert separators to spaces, but this hard-coded implementation is
// substantially faster than the general-purpose ReplaceChar function.
// This must be kept in sync with the definition of kSeparators.
static inline void ReplaceSeparators(nsString& aText, size_t aStartIndex = 0) {
for (char16_t* cp = aText.BeginWriting() + aStartIndex;
cp < aText.EndWriting(); cp++) {
if (MOZ_UNLIKELY(*cp < char16_t(' '))) {
static constexpr char16_t SeparatorToSpace[32] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ' ', ' ',
' ', 0x0c, ' ', 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, ' ', ' ', ' ', ' ',
};
*cp = SeparatorToSpace[*cp];
} else if (MOZ_UNLIKELY(*cp == 0x0085 || *cp == 0x2026)) {
*cp = ' ';
}
}
}
nsresult nsBidiPresUtils::ResolveParagraph(BidiParagraphData* aBpd) {
if (aBpd->BufferLength() < 1) {
return NS_OK;
}
aBpd->mBuffer.ReplaceChar(kSeparators, kSpace);
ReplaceSeparators(aBpd->mBuffer);
int32_t runCount;
@ -2464,9 +2486,19 @@ nsresult nsBidiPresUtils::ProcessTextForRenderingContext(
nsIRenderingContextBidiProcessor processor(&aRenderingContext,
aTextRunConstructionDrawTarget,
&aFontMetrics, nsPoint(aX, aY));
nsAutoString text(aText, aLength);
text.ReplaceChar(kSeparators, ' ');
return ProcessText(text.BeginReading(), text.Length(), aBaseLevel,
nsDependentSubstring text(aText, aLength);
auto separatorIndex = text.FindCharInSet(kSeparators);
if (separatorIndex == kNotFound) {
return ProcessText(text.BeginReading(), text.Length(), aBaseLevel,
aPresContext, processor, aMode, aPosResolve,
aPosResolveCount, aWidth, aPresContext->BidiEngine());
}
// We need to replace any block or segment separators with space for bidi
// processing, so make a local copy.
nsAutoString localText(text);
ReplaceSeparators(localText, separatorIndex);
return ProcessText(localText.BeginReading(), localText.Length(), aBaseLevel,
aPresContext, processor, aMode, aPosResolve,
aPosResolveCount, aWidth, aPresContext->BidiEngine());
}