fontContainsCharacters() returns False for characters > U+FFFF even though the font actually maps them
Closed this issue · 3 comments
What the title says. I suspect the root cause is in CoreText.CTFontGetGlyphsForCharacters
possibly not supporting SMP or possibly the call to that function needs different treatment when SMP characters are in the string passed to fontContainsCharacters()
.
Steps to repro:
- Install a font that has known support for SMP characters such as Noto Sans Deseret which supports characters in the range U+10400-1044F
- Check
drawBot.fontContainsCharacters()
for a character in that range and compare to the font's cmap (e.g. fontToolsgetBestCmap()
), something like this:
import drawBot as db
from fontTools.ttLib import TTFont
db.font('NotoSansDeseret-Regular', 48)
fontpath = db.fontFilePath()
ttfont = TTFont(fontpath)
umap = ttfont['cmap'].getBestCmap()
u = 0x10400
c = chr(u)
dbFontContains = db.fontContainsCharacters(c)
inFontCmap = u in umap
print(f'{dbFontContains=}, {inFontCmap=}')
- Observe that
dbFontContains=False
andinFontCmap=True
(for U+10400; both areTrue
for BMP characters present in the font such as U+0020 or U+00A0)
Expected behavior:
fontContainsCharacters()
should return True
for any character that is mapped in the font's most comprehensive Unicode cmap subtable.
Can reproduce. The relevant code is here:
drawbot/drawBot/context/baseContext.py
Lines 1796 to 1805 in 100dbdf
It looks pretty innocent.
I wonder if somehow PyObjC does something wrong when converting the characters
argument.
After trying a few things, I think it's a PyObjC bug with CTFontGetGlyphsForCharacters
. I suspect it has to encode the string as UTF-16, but doesn't.
https://developer.apple.com/documentation/coretext/1510813-ctfontgetglyphsforcharacters?language=objc, and UniChar is a 16bit type.
Thanks @justvanrossum and @typemytype for the quick fix!