From 6e766a2e81ed63ba52650e85a02238ef7b07a27b Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Sat, 16 Dec 2023 00:06:19 +0100 Subject: [PATCH] Change: Allow TrueType fonts to provide our private-use glyphs. --- src/fontcache.h | 3 ++- src/fontcache/freetypefontcache.cpp | 10 ++++++---- src/fontcache/spritefontcache.h | 2 +- src/gfx_layout_icu.cpp | 2 +- src/os/macosx/font_osx.cpp | 10 +++++----- src/os/macosx/font_osx.h | 2 +- src/os/macosx/string_osx.cpp | 6 +++--- src/os/windows/font_win32.cpp | 9 +++------ src/os/windows/font_win32.h | 2 +- src/os/windows/string_uniscribe.cpp | 8 +++++--- src/tests/mock_fontcache.h | 2 +- 11 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/fontcache.h b/src/fontcache.h index 3123c8f59f..73963011b5 100644 --- a/src/fontcache.h +++ b/src/fontcache.h @@ -108,9 +108,10 @@ public: /** * Map a character into a glyph. * @param key The character. + * @param fallback Allow fallback to the parent font. * @return The glyph ID used to draw the character. */ - virtual GlyphID MapCharToGlyph(char32_t key) = 0; + virtual GlyphID MapCharToGlyph(char32_t key, bool fallback = true) = 0; /** * Read a font table from the font. diff --git a/src/fontcache/freetypefontcache.cpp b/src/fontcache/freetypefontcache.cpp index 3e6ddd0f80..eca647d9c8 100644 --- a/src/fontcache/freetypefontcache.cpp +++ b/src/fontcache/freetypefontcache.cpp @@ -41,7 +41,7 @@ public: FreeTypeFontCache(FontSize fs, FT_Face face, int pixels); ~FreeTypeFontCache(); void ClearFontCache() override; - GlyphID MapCharToGlyph(char32_t key) override; + GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override; std::string GetFontName() override { return fmt::format("{}, {}", face->family_name, face->style_name); } bool IsBuiltInFont() override { return false; } const void *GetOSHandle() override { return &face; } @@ -276,15 +276,17 @@ const Sprite *FreeTypeFontCache::InternalGetGlyph(GlyphID key, bool aa) } -GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key) +GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback) { assert(IsPrintable(key)); - if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { + FT_UInt glyph = FT_Get_Char_Index(this->face, key); + + if (glyph == 0 && allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { return this->parent->MapCharToGlyph(key); } - return FT_Get_Char_Index(this->face, key); + return glyph; } const void *FreeTypeFontCache::InternalGetFontTable(uint32_t tag, size_t &length) diff --git a/src/fontcache/spritefontcache.h b/src/fontcache/spritefontcache.h index 628a6d08e1..e35cb1a5d6 100644 --- a/src/fontcache/spritefontcache.h +++ b/src/fontcache/spritefontcache.h @@ -29,7 +29,7 @@ public: const Sprite *GetGlyph(GlyphID key) override; uint GetGlyphWidth(GlyphID key) override; bool GetDrawGlyphShadow() override; - GlyphID MapCharToGlyph(char32_t key) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; } + GlyphID MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback = true) override { assert(IsPrintable(key)); return SPRITE_GLYPH | key; } const void *GetFontTable(uint32_t, size_t &length) override { length = 0; return nullptr; } std::string GetFontName() override { return "sprite"; } bool IsBuiltInFont() override { return true; } diff --git a/src/gfx_layout_icu.cpp b/src/gfx_layout_icu.cpp index 83dbf2584d..9cd0fbcdc1 100644 --- a/src/gfx_layout_icu.cpp +++ b/src/gfx_layout_icu.cpp @@ -193,7 +193,7 @@ void ICURun::Shape(UChar *buff, size_t buff_length) for (unsigned int i = 0; i < glyph_count; i++) { int x_advance; - if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END) { + if (buff[glyph_info[i].cluster] >= SCC_SPRITE_START && buff[glyph_info[i].cluster] <= SCC_SPRITE_END && glyph_info[i].codepoint == 0) { auto glyph = this->font->fc->MapCharToGlyph(buff[glyph_info[i].cluster]); this->glyphs.push_back(glyph); diff --git a/src/os/macosx/font_osx.cpp b/src/os/macosx/font_osx.cpp index a41af5a26f..d76fb0ef5c 100644 --- a/src/os/macosx/font_osx.cpp +++ b/src/os/macosx/font_osx.cpp @@ -180,14 +180,10 @@ void CoreTextFontCache::SetFontSize(int pixels) Debug(fontcache, 2, "Loaded font '{}' with size {}", this->font_name, pixels); } -GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key) +GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key, bool allow_fallback) { assert(IsPrintable(key)); - if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { - return this->parent->MapCharToGlyph(key); - } - /* Convert characters outside of the Basic Multilingual Plane into surrogate pairs. */ UniChar chars[2]; if (key >= 0x010000U) { @@ -202,6 +198,10 @@ GlyphID CoreTextFontCache::MapCharToGlyph(char32_t key) return glyph[0]; } + if (allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { + return this->parent->MapCharToGlyph(key); + } + return 0; } diff --git a/src/os/macosx/font_osx.h b/src/os/macosx/font_osx.h index ae1cb8feda..56d488771a 100644 --- a/src/os/macosx/font_osx.h +++ b/src/os/macosx/font_osx.h @@ -29,7 +29,7 @@ public: ~CoreTextFontCache() {} void ClearFontCache() override; - GlyphID MapCharToGlyph(char32_t key) override; + GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override; std::string GetFontName() override { return font_name; } bool IsBuiltInFont() override { return false; } const void *GetOSHandle() override { return font.get(); } diff --git a/src/os/macosx/string_osx.cpp b/src/os/macosx/string_osx.cpp index 068767b6fd..3c96bababb 100644 --- a/src/os/macosx/string_osx.cpp +++ b/src/os/macosx/string_osx.cpp @@ -189,9 +189,9 @@ static CTRunDelegateCallbacks _sprite_font_callback = { CFAttributedStringSetAttribute(str.get(), CFRangeMake(last, i.first - last), kCTForegroundColorAttributeName, color); CGColorRelease(color); - /* Install a size callback for our special sprite glyphs. */ + /* Install a size callback for our special private-use sprite glyphs in case the font does not provide them. */ for (ssize_t c = last; c < i.first; c++) { - if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END) { + if (buff[c] >= SCC_SPRITE_START && buff[c] <= SCC_SPRITE_END && i.second->fc->MapCharToGlyph(buff[c], false) == 0) { CFAutoRelease del(CTRunDelegateCreate(&_sprite_font_callback, (void *)(size_t)(buff[c] | (i.second->fc->GetSize() << 24)))); CFAttributedStringSetAttribute(str.get(), CFRangeMake(c, 1), kCTRunDelegateAttributeName, del.get()); } @@ -242,7 +242,7 @@ CoreTextParagraphLayout::CoreTextVisualRun::CoreTextVisualRun(CTRunRef run, Font CGGlyph gl[this->glyphs.size()]; CTRunGetGlyphs(run, CFRangeMake(0, 0), gl); for (size_t i = 0; i < this->glyphs.size(); i++) { - if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END) { + if (buff[this->glyph_to_char[i]] >= SCC_SPRITE_START && buff[this->glyph_to_char[i]] <= SCC_SPRITE_END && gl[i] == 0) { this->glyphs[i] = font->fc->MapCharToGlyph(buff[this->glyph_to_char[i]]); this->positions[i * 2 + 0] = pts[i].x; this->positions[i * 2 + 1] = (font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(font->fc->GetSize()))) / 2; // Align sprite font to centre diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index a05b2211a6..3602c11876 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -282,14 +282,10 @@ void Win32FontCache::ClearFontCache() return new_glyph.sprite; } -/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(char32_t key) +/* virtual */ GlyphID Win32FontCache::MapCharToGlyph(char32_t key, bool allow_fallback) { assert(IsPrintable(key)); - if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) { - return this->parent->MapCharToGlyph(key); - } - /* Convert characters outside of the BMP into surrogate pairs. */ WCHAR chars[2]; if (key >= 0x010000U) { @@ -302,7 +298,8 @@ void Win32FontCache::ClearFontCache() WORD glyphs[2] = { 0, 0 }; GetGlyphIndicesW(this->dc, chars, key >= 0x010000U ? 2 : 1, glyphs, GGI_MARK_NONEXISTING_GLYPHS); - return glyphs[0] != 0xFFFF ? glyphs[0] : 0; + if (glyphs[0] != 0xFFFF) return glyphs[0]; + return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0; } /* virtual */ const void *Win32FontCache::InternalGetFontTable(uint32_t tag, size_t &length) diff --git a/src/os/windows/font_win32.h b/src/os/windows/font_win32.h index 02a84b63fc..48459543fd 100644 --- a/src/os/windows/font_win32.h +++ b/src/os/windows/font_win32.h @@ -35,7 +35,7 @@ public: Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels); ~Win32FontCache(); void ClearFontCache() override; - GlyphID MapCharToGlyph(char32_t key) override; + GlyphID MapCharToGlyph(char32_t key, bool allow_fallback = true) override; std::string GetFontName() override { return this->fontname; } const void *GetOSHandle() override { return &this->logfont; } }; diff --git a/src/os/windows/string_uniscribe.cpp b/src/os/windows/string_uniscribe.cpp index 040101ec36..c8dc6ea1eb 100644 --- a/src/os/windows/string_uniscribe.cpp +++ b/src/os/windows/string_uniscribe.cpp @@ -194,9 +194,11 @@ static bool UniscribeShapeRun(const UniscribeParagraphLayoutFactory::CharType *b for (int i = 0; i < range.len; i++) { if (buff[range.pos + i] >= SCC_SPRITE_START && buff[range.pos + i] <= SCC_SPRITE_END) { auto pos = range.char_to_glyph[i]; - range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]); - range.offsets[pos].dv = (range.font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(range.font->fc->GetSize()))) / 2; // Align sprite font to centre - range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]); + if (range.ft_glyphs[pos] == 0) { // Font doesn't have our special glyph, so remap. + range.ft_glyphs[pos] = range.font->fc->MapCharToGlyph(buff[range.pos + i]); + range.offsets[pos].dv = (range.font->fc->GetHeight() - ScaleSpriteTrad(FontCache::GetDefaultFontHeight(range.font->fc->GetSize()))) / 2; // Align sprite font to centre + range.advances[pos] = range.font->fc->GetGlyphWidth(range.ft_glyphs[pos]); + } } } diff --git a/src/tests/mock_fontcache.h b/src/tests/mock_fontcache.h index c9eb326029..e6cee2d022 100644 --- a/src/tests/mock_fontcache.h +++ b/src/tests/mock_fontcache.h @@ -29,7 +29,7 @@ public: const Sprite *GetGlyph(GlyphID) override { return nullptr; } uint GetGlyphWidth(GlyphID) override { return this->height / 2; } bool GetDrawGlyphShadow() override { return false; } - GlyphID MapCharToGlyph(char32_t key) override { return key; } + GlyphID MapCharToGlyph(char32_t key, [[maybe_unused]] bool allow_fallback = true) override { return key; } const void *GetFontTable(uint32_t, size_t &length) override { length = 0; return nullptr; } std::string GetFontName() override { return "mock"; } bool IsBuiltInFont() override { return true; }