Speed up DWriteFontTypeface::getGlyphToUnicodeMap

Use IDWriteFontFace1::GetUnicodeRanges to speed up creating the glyph to
unicode map by greatly reducing the number of codepoints to query. Also
batch up calls to GetGlyphIndices instead of calling one codepoint at a
time.

Bug: skia:12537
Change-Id: I53641d563fd7a5b670217590a505dedceabc9d21
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/459179
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Ben Wagner <bungeman@google.com>
This commit is contained in:
Ben Wagner 2021-10-13 18:39:24 -04:00 committed by SkCQ
parent 237dd2d94d
commit 8b0ba16043

View File

@ -9,7 +9,9 @@
#include "include/core/SkTypes.h"
#if defined(SK_BUILD_FOR_WIN)
// SkTypes will include Windows.h, which will pull in all of the GDI defines.
#include "src/core/SkLeanWindows.h"
// SkLeanWindows will include Windows.h, which will pull in all of the GDI defines.
// GDI #defines GetGlyphIndices to GetGlyphIndicesA or GetGlyphIndicesW, but
// IDWriteFontFace has a method called GetGlyphIndices. Since this file does
// not use GDI, undefing GetGlyphIndices makes things less confusing.
@ -120,7 +122,7 @@ public:
UINT32 stringLen;
HRBM(fStrings->GetStringLength(fIndex, &stringLen), "Could not get string length.");
SkSMallocWCHAR wString(stringLen+1);
SkSMallocWCHAR wString(static_cast<size_t>(stringLen)+1);
HRBM(fStrings->GetString(fIndex, wString.get(), stringLen+1), "Could not get string.");
HRB(sk_wchar_to_skstring(wString.get(), stringLen, &localizedString->fString));
@ -129,7 +131,7 @@ public:
UINT32 localeLen;
HRBM(fStrings->GetLocaleNameLength(fIndex, &localeLen), "Could not get locale length.");
SkSMallocWCHAR wLocale(localeLen+1);
SkSMallocWCHAR wLocale(static_cast<size_t>(localeLen)+1);
HRBM(fStrings->GetLocaleName(fIndex, wLocale.get(), localeLen+1), "Could not get locale.");
HRB(sk_wchar_to_skstring(wLocale.get(), localeLen, &localizedString->fLanguage));
@ -363,7 +365,7 @@ sk_sp<SkTypeface> DWriteFontTypeface::onMakeClone(const SkFontArguments& args) c
std::unique_ptr<SkStreamAsset> DWriteFontTypeface::onOpenStream(int* ttcIndex) const {
*ttcIndex = fDWriteFontFace->GetIndex();
UINT32 numFiles;
UINT32 numFiles = 0;
HRNM(fDWriteFontFace->GetFiles(&numFiles, nullptr),
"Could not get number of font files.");
if (numFiles != 1) {
@ -432,24 +434,54 @@ void DWriteFontTypeface::onFilterRec(SkScalerContextRec* rec) const {
///////////////////////////////////////////////////////////////////////////////
//PDF Support
static void glyph_to_unicode_map(IDWriteFontFace* fontFace, DWRITE_UNICODE_RANGE range,
UINT32* remainingGlyphCount, UINT32 numGlyphs,
SkUnichar* glyphToUnicode)
{
constexpr const int batchSize = 128;
UINT32 codepoints[batchSize];
UINT16 glyphs[batchSize];
for (UINT32 c = range.first; c <= range.last && *remainingGlyphCount != 0; c += batchSize) {
UINT32 numBatchedCodePoints = std::min<UINT32>(range.last - c + 1, batchSize);
for (UINT32 i = 0; i < numBatchedCodePoints; ++i) {
codepoints[i] = c + i;
}
HRVM(fontFace->GetGlyphIndices(codepoints, numBatchedCodePoints, glyphs),
"Failed to get glyph indexes.");
for (UINT32 i = 0; i < numBatchedCodePoints; ++i) {
UINT16 glyph = glyphs[i];
// Intermittent DW bug on Windows 10. See crbug.com/470146.
if (glyph >= numGlyphs) {
return;
}
if (0 < glyph && glyphToUnicode[glyph] == 0) {
glyphToUnicode[glyph] = c + i; // Always use lowest-index unichar.
--*remainingGlyphCount;
}
}
}
}
void DWriteFontTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const {
unsigned glyphCount = fDWriteFontFace->GetGlyphCount();
sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount);
IDWriteFontFace* fontFace = fDWriteFontFace.get();
int maxGlyph = -1;
unsigned remainingGlyphCount = glyphCount;
for (UINT32 c = 0; c < 0x10FFFF && remainingGlyphCount != 0; ++c) {
UINT16 glyph = 0;
HRVM(fontFace->GetGlyphIndices(&c, 1, &glyph), "Failed to get glyph index.");
// Intermittent DW bug on Windows 10. See crbug.com/470146.
if (glyph >= glyphCount) {
return;
IDWriteFontFace* face = fDWriteFontFace.get();
UINT32 numGlyphs = face->GetGlyphCount();
sk_bzero(glyphToUnicode, sizeof(SkUnichar) * numGlyphs);
UINT32 remainingGlyphCount = numGlyphs;
if (fDWriteFontFace1) {
IDWriteFontFace1* face1 = fDWriteFontFace1.get();
UINT32 numRanges = 0;
HRESULT hr = face1->GetUnicodeRanges(0, nullptr, &numRanges);
if (hr != E_NOT_SUFFICIENT_BUFFER && FAILED(hr)) {
HRVM(hr, "Failed to get number of ranges.");
}
if (0 < glyph && glyphToUnicode[glyph] == 0) {
maxGlyph = std::max(static_cast<int>(glyph), maxGlyph);
glyphToUnicode[glyph] = c; // Always use lowest-index unichar.
--remainingGlyphCount;
std::unique_ptr<DWRITE_UNICODE_RANGE[]> ranges(new DWRITE_UNICODE_RANGE[numRanges]);
HRVM(face1->GetUnicodeRanges(numRanges, ranges.get(), &numRanges), "Failed to get ranges.");
for (UINT32 i = 0; i < numRanges; ++i) {
glyph_to_unicode_map(face1, ranges[i], &remainingGlyphCount, numGlyphs, glyphToUnicode);
}
} else {
glyph_to_unicode_map(face, {0, 0x10FFFF}, &remainingGlyphCount, numGlyphs, glyphToUnicode);
}
}