Port the CoreText backend to use ListOfChars

This commit is contained in:
Kovid Goyal 2024-10-27 13:38:09 +05:30
parent 5e36e0a324
commit d88b7e945a
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
3 changed files with 28 additions and 24 deletions

View file

@ -326,17 +326,17 @@ static CTFontRef nerd_font(CGFloat sz) {
}
static bool ctfont_has_codepoint(const void *ctfont, char_type cp) { return glyph_id_for_codepoint_ctfont(ctfont, cp) > 0; }
static bool font_can_render_cell(CTFontRef font, CPUCell *cell) { return has_cell_text(ctfont_has_codepoint, font, cell, false); }
static bool font_can_render_cell(CTFontRef font, const ListOfChars *lc) { return has_cell_text(ctfont_has_codepoint, font, false, lc); }
static CTFontRef
manually_search_fallback_fonts(CTFontRef current_font, CPUCell *cell) {
char_type ch = cell->ch ? cell->ch : ' ';
manually_search_fallback_fonts(CTFontRef current_font, const ListOfChars *lc) {
char_type ch = lc->chars[0] ? lc->chars[0] : ' ';
const bool in_first_pua = 0xe000 <= ch && ch <= 0xf8ff;
// preferentially load from NERD fonts
if (in_first_pua) {
CTFontRef nf = nerd_font(CTFontGetSize(current_font));
if (nf) {
if (font_can_render_cell(nf, cell)) return nf;
if (font_can_render_cell(nf, lc)) return nf;
CFRelease(nf);
}
}
@ -347,7 +347,7 @@ manually_search_fallback_fonts(CTFontRef current_font, CPUCell *cell) {
CTFontDescriptorRef descriptor = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fonts, i);
CTFontRef new_font = CTFontCreateWithFontDescriptor(descriptor, CTFontGetSize(current_font), NULL);
if (!is_last_resort_font(new_font)) {
if (font_can_render_cell(new_font, cell)) {
if (font_can_render_cell(new_font, lc)) {
ans = new_font;
break;
}
@ -358,7 +358,7 @@ manually_search_fallback_fonts(CTFontRef current_font, CPUCell *cell) {
if (!ans) {
CTFontRef nf = nerd_font(CTFontGetSize(current_font));
if (nf) {
if (font_can_render_cell(nf, cell)) ans = nf;
if (font_can_render_cell(nf, lc)) ans = nf;
else CFRelease(nf);
}
}
@ -366,7 +366,7 @@ manually_search_fallback_fonts(CTFontRef current_font, CPUCell *cell) {
}
static CTFontRef
find_substitute_face(CFStringRef str, CTFontRef old_font, CPUCell *cpu_cell) {
find_substitute_face(CFStringRef str, CTFontRef old_font, const ListOfChars *lc) {
// 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
@ -378,9 +378,9 @@ find_substitute_face(CFStringRef str, CTFontRef old_font, CPUCell *cpu_cell) {
if (new_font == old_font) { CFRelease(new_font); continue; }
if (!new_font || is_last_resort_font(new_font)) {
if (new_font) CFRelease(new_font);
if (is_private_use(cpu_cell->ch)) {
if (is_private_use(lc->chars[0])) {
// CoreTexts fallback font mechanism does not work for private use characters
new_font = manually_search_fallback_fonts(old_font, cpu_cell);
new_font = manually_search_fallback_fonts(old_font, lc);
if (new_font) return new_font;
}
return NULL;
@ -418,22 +418,28 @@ apply_styles_to_fallback_font(CTFontRef original_fallback_font, bool bold, bool
}
static bool face_has_codepoint(const void *face, char_type ch) { return glyph_id_for_codepoint(face, ch) > 0; }
static struct { char *buf; size_t capacity; } ft_buffer;
static CFStringRef
lc_as_fallback(const ListOfChars *lc) {
ensure_space_for((&ft_buffer), buf, ft_buffer.buf[0], lc->count * 4 + 128, capacity, 256, false);
cell_as_utf8_for_fallback(lc, ft_buffer.buf);
return CFStringCreateWithCString(NULL, ft_buffer.buf, kCFStringEncodingUTF8);
}
PyObject*
create_fallback_face(PyObject *base_face, CPUCell* cell, bool bold, bool italic, bool emoji_presentation, FONTS_DATA_HANDLE fg) {
create_fallback_face(PyObject *base_face, const ListOfChars *lc, bool bold, bool italic, bool emoji_presentation, FONTS_DATA_HANDLE fg) {
CTFace *self = (CTFace*)base_face;
RAII_CoreFoundation(CTFontRef, new_font, NULL);
#define search_for_fallback() \
char text[64] = {0}; \
cell_as_utf8_for_fallback(cell, text); \
CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); \
CFStringRef str = lc_as_fallback(lc); \
if (str == NULL) return PyErr_NoMemory(); \
new_font = find_substitute_face(str, self->ct_font, cell); \
new_font = find_substitute_face(str, self->ct_font, lc); \
CFRelease(str);
if (emoji_presentation) {
new_font = CTFontCreateWithName((CFStringRef)@"AppleColorEmoji", self->scaled_point_sz, NULL);
if (!new_font || !glyph_id_for_codepoint_ctfont(new_font, cell->ch)) {
if (!new_font || !glyph_id_for_codepoint_ctfont(new_font, lc->chars[0])) {
if (new_font) CFRelease(new_font);
search_for_fallback();
}
@ -453,7 +459,7 @@ create_fallback_face(PyObject *base_face, CPUCell* cell, bool bold, bool italic,
}
if (!ans) {
ans = (PyObject*)ct_face(new_font, NULL);
if (ans && !has_cell_text(face_has_codepoint, ans, cell, global_state.debug_font_fallback)) {
if (ans && !has_cell_text(face_has_codepoint, ans, global_state.debug_font_fallback, lc)) {
Py_CLEAR(ans);
Py_RETURN_NONE;
}
@ -697,7 +703,7 @@ static struct RenderBuffers buffers = {0};
static void
finalize(void) {
free(buffers.render_buf); free(buffers.glyphs); free(buffers.boxes); free(buffers.positions);
free(ft_buffer.buf); free(buffers.render_buf); free(buffers.glyphs); free(buffers.boxes); free(buffers.positions);
memset(&buffers, 0, sizeof(struct RenderBuffers));
if (all_fonts_collection_data) CFRelease(all_fonts_collection_data);
if (window_title_font) CFRelease(window_title_font);

View file

@ -235,16 +235,14 @@ cell_as_unicode_for_fallback(const ListOfChars *lc, Py_UCS4 *buf) {
}
size_t
cell_as_utf8_for_fallback(CPUCell *cell, TextCache *tc, char *buf) {
RAII_ListOfChars(lc);
text_in_cell(cell, tc, &lc);
char_type ch = lc.chars[0] ? lc.chars[0] : ' ';
cell_as_utf8_for_fallback(const ListOfChars *lc, char *buf) {
char_type ch = lc->chars[0] ? lc->chars[0] : ' ';
bool include_cc = true;
if (ch == '\t') { ch = ' '; include_cc = false; }
size_t n = encode_utf8(ch, buf);
if (include_cc) {
for (unsigned i = 1; i < lc.count; i++) {
char_type ch = lc.chars[i];
for (unsigned i = 1; i < lc->count; i++) {
char_type ch = lc->chars[i];
if (ch != VS15 && ch != VS16) n += encode_utf8(ch, buf + n);
}
}

View file

@ -95,7 +95,7 @@ bool line_startswith_url_chars(Line*, bool);
bool line_as_ansi(Line *self, ANSIBuf *output, const GPUCell**, index_type start_at, index_type stop_before, char_type prefix_char) __attribute__((nonnull));
unsigned int line_length(Line *self);
size_t cell_as_unicode_for_fallback(const ListOfChars *lc, Py_UCS4 *buf);
size_t cell_as_utf8_for_fallback(CPUCell *cell, TextCache *tc, char *buf);
size_t cell_as_utf8_for_fallback(const ListOfChars *lc, char *buf);
PyObject* unicode_in_range(const Line *self, const index_type start, const index_type limit, const bool include_cc, const bool add_trailing_newline, const bool skip_zero_cells);
PyObject* line_as_unicode(Line *, bool);