From c9d05caaaef27a8b3db9c7cf0ca47140e5f3d268 Mon Sep 17 00:00:00 2001 From: jules Date: Tue, 18 Sep 2018 12:20:11 +0100 Subject: [PATCH] Replaced win32 font kerning tables with maps to improve performance --- modules/juce_graphics/juce_graphics.cpp | 2 + .../juce_graphics/native/juce_win32_Fonts.cpp | 92 +++++++++---------- 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/modules/juce_graphics/juce_graphics.cpp b/modules/juce_graphics/juce_graphics.cpp index 2dcbc5e8bb..baed232ab1 100644 --- a/modules/juce_graphics/juce_graphics.cpp +++ b/modules/juce_graphics/juce_graphics.cpp @@ -71,6 +71,8 @@ #include #endif + #include + #ifdef JUCE_MSVC #pragma warning (pop) #endif diff --git a/modules/juce_graphics/native/juce_win32_Fonts.cpp b/modules/juce_graphics/native/juce_win32_Fonts.cpp index 7489521ff6..a210824992 100644 --- a/modules/juce_graphics/native/juce_win32_Fonts.cpp +++ b/modules/juce_graphics/native/juce_win32_Fonts.cpp @@ -469,25 +469,12 @@ private: HANDLE memoryFont = {}; float ascent = 1.0f, heightToPointsFactor = 1.0f; int defaultGlyph = -1, heightInPoints = 0; + std::unordered_map kerningPairs; - struct KerningPair + static uint64 kerningPairIndex (int glyph1, int glyph2) { - int glyph1, glyph2; - float kerning; - - bool operator== (const KerningPair& other) const noexcept - { - return glyph1 == other.glyph1 && glyph2 == other.glyph2; - } - - bool operator< (const KerningPair& other) const noexcept - { - return glyph1 < other.glyph1 - || (glyph1 == other.glyph1 && glyph2 < other.glyph2); - } - }; - - SortedSet kerningPairs; + return (((uint64) (uint32) glyph1) << 32) | (uint64) (uint32) glyph2; + } void loadFont() { @@ -531,38 +518,39 @@ private: auto dpi = (GetDeviceCaps (dc, LOGPIXELSX) + GetDeviceCaps (dc, LOGPIXELSY)) / 2.0f; heightToPointsFactor = (dpi / GetDeviceCaps (dc, LOGPIXELSY)) * heightInPoints / (float) tm.tmHeight; ascent = tm.tmAscent / (float) tm.tmHeight; - defaultGlyph = getGlyphForChar (dc, tm.tmDefaultChar); - createKerningPairs (dc, (float) tm.tmHeight); + std::unordered_map glyphsForChars; + defaultGlyph = getGlyphForChar (dc, glyphsForChars, tm.tmDefaultChar); + createKerningPairs (dc, glyphsForChars, (float) tm.tmHeight); } } - void createKerningPairs (HDC hdc, float height) + void createKerningPairs (HDC hdc, std::unordered_map& glyphsForChars, float height) { HeapBlock rawKerning; auto numKPs = GetKerningPairs (hdc, 0, 0); rawKerning.calloc (numKPs); GetKerningPairs (hdc, numKPs, rawKerning); - kerningPairs.ensureStorageAllocated ((int) numKPs); + std::unordered_map widthsForGlyphs; for (DWORD i = 0; i < numKPs; ++i) { - KerningPair kp; - kp.glyph1 = getGlyphForChar (hdc, rawKerning[i].wFirst); - kp.glyph2 = getGlyphForChar (hdc, rawKerning[i].wSecond); + auto glyph1 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wFirst); + auto glyph2 = getGlyphForChar (hdc, glyphsForChars, rawKerning[i].wSecond); + auto standardWidth = getGlyphWidth (hdc, widthsForGlyphs, glyph1); - auto standardWidth = getGlyphWidth (hdc, kp.glyph1); - kp.kerning = (standardWidth + rawKerning[i].iKernAmount) / height; - kerningPairs.add (kp); - - kp.glyph2 = -1; // add another entry for the standard width version.. - kp.kerning = standardWidth / height; - kerningPairs.add (kp); + kerningPairs[kerningPairIndex (glyph1, glyph2)] = (standardWidth + rawKerning[i].iKernAmount) / height; + kerningPairs[kerningPairIndex (glyph1, -1)] = standardWidth / height; } } - static int getGlyphForChar (HDC dc, juce_wchar character) + static int getGlyphForChar (HDC dc, std::unordered_map& cache, juce_wchar character) { + auto existing = cache.find ((int) character); + + if (existing != cache.end()) + return existing->second; + const WCHAR charToTest[] = { (WCHAR) character, 0 }; WORD index = 0; @@ -570,9 +558,22 @@ private: || index == 0xffff) return -1; + cache[(int) character] = index; return index; } + static int getGlyphWidth (HDC dc, std::unordered_map& cache, int glyphNumber) + { + auto existing = cache.find (glyphNumber); + + if (existing != cache.end()) + return existing->second; + + auto width = getGlyphWidth (dc, glyphNumber); + cache[glyphNumber] = width; + return width; + } + static int getGlyphWidth (HDC dc, int glyphNumber) { GLYPHMETRICS gm; @@ -583,26 +584,19 @@ private: float getKerning (HDC hdc, int glyph1, int glyph2) { - KerningPair kp; - kp.glyph1 = glyph1; - kp.glyph2 = glyph2; - auto index = kerningPairs.indexOf (kp); + auto pair = kerningPairs.find (kerningPairIndex (glyph1, glyph2)); - if (index < 0) - { - kp.glyph2 = -1; - index = kerningPairs.indexOf (kp); + if (pair != kerningPairs.end()) + return pair->second; - if (index < 0) - { - kp.glyph2 = -1; - kp.kerning = getGlyphWidth (hdc, kp.glyph1) / (float) tm.tmHeight; - kerningPairs.add (kp); - return kp.kerning; - } - } + auto single = kerningPairs.find (kerningPairIndex (glyph1, -1)); - return kerningPairs.getReference (index).kerning; + if (single != kerningPairs.end()) + return single->second; + + auto width = getGlyphWidth (hdc, glyph1) / (float) tm.tmHeight; + kerningPairs[kerningPairIndex (glyph1, -1)] = width; + return width; } JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsTypeface)