Workaround for broken CTFontCreateForString
This commit is contained in:
parent
f5040532c5
commit
98e93cb4bd
@ -123,6 +123,24 @@ ft_face(CTFontRef font, float pt_sz, float xdpi, float ydpi) {
|
||||
return ans;
|
||||
}
|
||||
|
||||
static inline CTFontRef
|
||||
find_substitute_face(CFStringRef str, CTFontRef old_font) {
|
||||
// CTFontCreateForString returns the original font when there are combining
|
||||
// diacritics in the font and the base character is in the original font,
|
||||
// so we have to check each character individually
|
||||
CFIndex len = CFStringGetLength(str), start = 0, amt = len;
|
||||
while (start < len) {
|
||||
CTFontRef new_font = CTFontCreateForString(old_font, str, CFRangeMake(start, amt));
|
||||
if (amt == len && len != 1) amt = 1;
|
||||
else start++;
|
||||
if (new_font == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to find fallback CTFont"); return NULL; }
|
||||
if (new_font == old_font) { CFRelease(new_font); continue; }
|
||||
return new_font;
|
||||
}
|
||||
PyErr_SetString(PyExc_ValueError, "CoreText returned the same font as a fallback font");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
face_for_text(PyObject UNUSED *self, PyObject UNUSED *args) {
|
||||
char *text;
|
||||
@ -133,9 +151,9 @@ face_for_text(PyObject UNUSED *self, PyObject UNUSED *args) {
|
||||
CTFontRef font = PyLong_AsVoidPtr(lp);
|
||||
CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8);
|
||||
if (str == NULL) return PyErr_NoMemory();
|
||||
CFRange range = CFRangeMake(0, CFStringGetLength(str));
|
||||
CTFontRef new_font = CTFontCreateForString(font, str, range);
|
||||
if (new_font == NULL) { PyErr_SetString(PyExc_ValueError, "Failed to find fallback CTFont"); CFRelease(str); return NULL; }
|
||||
CTFontRef new_font = find_substitute_face(str, font);
|
||||
CFRelease(str);
|
||||
if (new_font == NULL) return NULL;
|
||||
return ft_face(new_font, pt_sz, xdpi, ydpi);
|
||||
}
|
||||
|
||||
|
||||
@ -231,13 +231,13 @@ def test_render_string(text='Hello, world!', family='monospace', size=144.0, dpi
|
||||
|
||||
def test_fallback_font(qtext=None, bold=False, italic=False):
|
||||
set_font_family(override_dpi=(96.0, 96.0))
|
||||
for text in (qtext, '你好', 'He\u0347\u0305', '\U0001F929'):
|
||||
if text:
|
||||
f = get_fallback_font(text, bold, italic)
|
||||
try:
|
||||
print(text, f)
|
||||
except UnicodeEncodeError:
|
||||
sys.stdout.buffer.write((text + ' %s\n' % f).encode('utf-8'))
|
||||
trials = (qtext,) if qtext else ('你好', 'He\u0347\u0305', '\U0001F929')
|
||||
for text in trials:
|
||||
f = get_fallback_font(text, bold, italic)
|
||||
try:
|
||||
print(text, f)
|
||||
except UnicodeEncodeError:
|
||||
sys.stdout.buffer.write((text + ' %s\n' % f).encode('utf-8'))
|
||||
|
||||
|
||||
def showcase():
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user