From c5e6c885c1d84e7e385b50d7353d26d993e6645a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Feb 2025 03:49:01 +0000 Subject: [PATCH 1/3] [coretext-font] Support non-BMP chars in get_nominal_glyph(s) Part of https://github.com/harfbuzz/harfbuzz/issues/5056 --- src/hb-coretext-font.cc | 52 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/src/hb-coretext-font.cc b/src/hb-coretext-font.cc index 910e83f57..4f5a02014 100644 --- a/src/hb-coretext-font.cc +++ b/src/hb-coretext-font.cc @@ -60,11 +60,30 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { CTFontRef ct_font = (CTFontRef) font_data; - UniChar ch = unicode; - CGGlyph cg_glyph; - if (CTFontGetGlyphsForCharacters (ct_font, &ch, &cg_glyph, 1)) + UniChar ch[2]; + CGGlyph cg_glyph[2]; + unsigned count; + + if (unicode <= 0xFFFF) { - *glyph = cg_glyph; + ch[0] = unicode; + count = 1; + } + else if (unicode <= 0x10FFFF) + { + ch[0] = (unicode >> 10) + 0xD7C0; + ch[1] = (unicode & 0x3FF) + 0xDC00; + count = 2; + } + else + { + ch[0] = 0xFFFD; + count = 1; + } + + if (CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count)) + { + *glyph = cg_glyph[0]; return true; } return false; @@ -80,6 +99,31 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED, unsigned int glyph_stride, void *user_data HB_UNUSED) { + // If any non-BMP codepoint is requested, use the slow path. + bool slow_path = false; + auto *unicode = first_unicode; + for (unsigned i = 0; i < count; i++) + { + if (*unicode > 0xFFFF) + { + slow_path = true; + break; + } + unicode = &StructAtOffset (unicode, unicode_stride); + } + + if (unlikely (slow_path)) + { + for (unsigned i = 0; i < count; i++) + { + if (!hb_coretext_get_nominal_glyph (font, font_data, *first_unicode, first_glyph, nullptr)) + return i; + first_unicode = &StructAtOffset (first_unicode, unicode_stride); + first_glyph = &StructAtOffset (first_glyph, glyph_stride); + } + return count; + } + CTFontRef ct_font = (CTFontRef) font_data; UniChar ch[MAX_GLYPHS]; From f6bf9f697e58ac14035002cb5bebe329ddc8351a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Feb 2025 03:52:13 +0000 Subject: [PATCH 2/3] [coretext-font] Do early-return in get_nominal_glyphs() Related to https://github.com/harfbuzz/harfbuzz/issues/5056 --- src/hb-coretext-font.cc | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/hb-coretext-font.cc b/src/hb-coretext-font.cc index 4f5a02014..6f74cd13c 100644 --- a/src/hb-coretext-font.cc +++ b/src/hb-coretext-font.cc @@ -136,7 +136,16 @@ hb_coretext_get_nominal_glyphs (hb_font_t *font HB_UNUSED, ch[j] = *first_unicode; first_unicode = &StructAtOffset (first_unicode, unicode_stride); } - CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c); + if (unlikely (!CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, c))) + { + // Use slow path partially and return at first failure. + for (unsigned j = 0; j < c; j++) + { + if (!hb_coretext_get_nominal_glyph (font, font_data, ch[j], first_glyph, nullptr)) + return i + j; + first_glyph = &StructAtOffset (first_glyph, glyph_stride); + } + } for (unsigned j = 0; j < c; j++) { *first_glyph = cg_glyph[j]; From fb22295311acd7379d4d06866dd9209f1a799422 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Sun, 9 Feb 2025 03:56:46 +0000 Subject: [PATCH 3/3] [coretext-font] Support non-BMP in variation-selector callback Fixes https://github.com/harfbuzz/harfbuzz/issues/5056 --- src/hb-coretext-font.cc | 50 ++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/hb-coretext-font.cc b/src/hb-coretext-font.cc index 6f74cd13c..7f12243d9 100644 --- a/src/hb-coretext-font.cc +++ b/src/hb-coretext-font.cc @@ -62,24 +62,19 @@ hb_coretext_get_nominal_glyph (hb_font_t *font HB_UNUSED, CTFontRef ct_font = (CTFontRef) font_data; UniChar ch[2]; CGGlyph cg_glyph[2]; - unsigned count; + unsigned count = 0; if (unicode <= 0xFFFF) { - ch[0] = unicode; - count = 1; + ch[count++] = unicode; } else if (unicode <= 0x10FFFF) { - ch[0] = (unicode >> 10) + 0xD7C0; - ch[1] = (unicode & 0x3FF) + 0xDC00; - count = 2; + ch[count++] = (unicode >> 10) + 0xD7C0; + ch[count++] = (unicode & 0x3FF) + 0xDC00; } else - { - ch[0] = 0xFFFD; - count = 1; - } + ch[count++] = 0xFFFD; if (CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count)) { @@ -166,13 +161,38 @@ hb_coretext_get_variation_glyph (hb_font_t *font HB_UNUSED, { CTFontRef ct_font = (CTFontRef) font_data; - UniChar ch[2] = { unicode, variation_selector }; - CGGlyph cg_glyph[2]; + UniChar ch[4]; + CGGlyph cg_glyph[4]; + unsigned count = 0; - CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, 2); + // Add Unicode, then variation selector. Ugly, but works. + // + if (unicode <= 0xFFFF) + ch[count++] = unicode; + else if (unicode <= 0x10FFFF) + { + ch[count++] = (unicode >> 10) + 0xD7C0; + ch[count++] = (unicode & 0x3FF) + 0xDC00; + } + else + ch[count++] = 0xFFFD; - if (cg_glyph[1]) - return false; + if (variation_selector <= 0xFFFF) + ch[count++] = variation_selector; + else if (variation_selector <= 0x10FFFF) + { + ch[count++] = (variation_selector >> 10) + 0xD7C0; + ch[count++] = (variation_selector & 0x3FF) + 0xDC00; + } + else + ch[count++] = 0xFFFD; + + CTFontGetGlyphsForCharacters (ct_font, ch, cg_glyph, count); + + // All except for first should be zero if we succeeded + for (unsigned i = 1; i < count; i++) + if (cg_glyph[i]) + return false; *glyph = cg_glyph[0]; return true;