From 8b0ba16043ae080d38f200ff3e5becbdcb5ff982 Mon Sep 17 00:00:00 2001 From: Ben Wagner Date: Wed, 13 Oct 2021 18:39:24 -0400 Subject: [PATCH] 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 Commit-Queue: Ben Wagner --- src/ports/SkTypeface_win_dw.cpp | 70 ++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 19 deletions(-) diff --git a/src/ports/SkTypeface_win_dw.cpp b/src/ports/SkTypeface_win_dw.cpp index 595767a25a..d15f431e37 100644 --- a/src/ports/SkTypeface_win_dw.cpp +++ b/src/ports/SkTypeface_win_dw.cpp @@ -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(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(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 DWriteFontTypeface::onMakeClone(const SkFontArguments& args) c std::unique_ptr 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(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(glyph), maxGlyph); - glyphToUnicode[glyph] = c; // Always use lowest-index unichar. - --remainingGlyphCount; + std::unique_ptr 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); } }