From 96c93fa25248cb05d9cf9b3452a67d8a19536e7c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 6 Feb 2018 11:11:22 +0530 Subject: [PATCH] Add support for emoji presentation when choosing fallback fonts --- kitty/config.py | 1 - kitty/core_text.m | 18 +++++++++++------- kitty/fontconfig.c | 11 +++++------ kitty/fonts.c | 29 +++++++++++------------------ kitty/fonts.h | 2 +- kitty/kitty.conf | 6 ------ kitty/state.c | 1 - kitty/state.h | 1 - 8 files changed, 28 insertions(+), 41 deletions(-) diff --git a/kitty/config.py b/kitty/config.py index 166cad8e4..4410d4cc8 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -283,7 +283,6 @@ type_map = { 'inactive_tab_font_style': tab_font_style, 'inactive_text_alpha': unit_float, 'url_style': url_style, - 'prefer_color_emoji': to_bool, 'copy_on_select': to_bool, 'tab_bar_edge': tab_bar_edge, } diff --git a/kitty/core_text.m b/kitty/core_text.m index d3ae0962b..200a60d46 100644 --- a/kitty/core_text.m +++ b/kitty/core_text.m @@ -178,14 +178,18 @@ find_substitute_face(CFStringRef str, CTFontRef old_font) { } PyObject* -create_fallback_face(PyObject *base_face, Cell* cell, bool UNUSED bold, bool UNUSED italic) { +create_fallback_face(PyObject *base_face, Cell* cell, bool UNUSED bold, bool UNUSED italic, bool emoji_presentation) { CTFace *self = (CTFace*)base_face; - char text[256] = {0}; - cell_as_utf8(cell, true, text, ' '); - CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); - if (str == NULL) return PyErr_NoMemory(); - CTFontRef new_font = find_substitute_face(str, self->ct_font); - CFRelease(str); + CTFontRef new_font; + if (emoji_presentation) new_font = CTFontCreateWithName((CFStringRef)@"AppleColorEmoji", self->scaled_point_sz, NULL); + else { + char text[256] = {0}; + cell_as_utf8(cell, true, text, ' '); + CFStringRef str = CFStringCreateWithCString(NULL, text, kCFStringEncodingUTF8); + if (str == NULL) return PyErr_NoMemory(); + new_font = find_substitute_face(str, self->ct_font); + CFRelease(str); + } if (new_font == NULL) return NULL; return (PyObject*)ct_face(new_font); } diff --git a/kitty/fontconfig.c b/kitty/fontconfig.c index 905089082..4886ca766 100644 --- a/kitty/fontconfig.c +++ b/kitty/fontconfig.c @@ -189,15 +189,14 @@ end: } PyObject* -create_fallback_face(PyObject UNUSED *base_face, Cell* cell, bool bold, bool italic) { +create_fallback_face(PyObject UNUSED *base_face, Cell* cell, bool bold, bool italic, bool emoji_presentation) { PyObject *ans = NULL; FcPattern *pat = FcPatternCreate(); if (pat == NULL) return PyErr_NoMemory(); - bool emoji = (cell->attrs & WIDTH_MASK) == 2 && is_emoji(cell->ch); - AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)(emoji ? "emoji" : "monospace"), "family"); - if (!emoji && bold) { AP(FcPatternAddInteger, FC_WEIGHT, FC_WEIGHT_BOLD, "weight"); } - if (!emoji && italic) { AP(FcPatternAddInteger, FC_SLANT, FC_SLANT_ITALIC, "slant"); } - if (emoji) { AP(FcPatternAddBool, FC_COLOR, OPT(prefer_color_emoji), "color"); } + AP(FcPatternAddString, FC_FAMILY, (const FcChar8*)(emoji_presentation ? "emoji" : "monospace"), "family"); + if (!emoji_presentation && bold) { AP(FcPatternAddInteger, FC_WEIGHT, FC_WEIGHT_BOLD, "weight"); } + if (!emoji_presentation && italic) { AP(FcPatternAddInteger, FC_SLANT, FC_SLANT_ITALIC, "slant"); } + if (emoji_presentation) { AP(FcPatternAddBool, FC_COLOR, true, "color"); } size_t num = cell_as_unicode(cell, true, char_buf, ' '); add_charset(pat, num); PyObject *d = _fc_match(pat); diff --git a/kitty/fonts.c b/kitty/fonts.c index df0e43153..4c770b8ad 100644 --- a/kitty/fonts.c +++ b/kitty/fonts.c @@ -65,7 +65,7 @@ typedef struct { // Map glyphs to sprite map co-ords SpritePosition sprite_map[1024]; SpecialGlyphCache special_glyph_cache[SPECIAL_GLYPH_CACHE_SIZE]; - bool bold, italic; + bool bold, italic, emoji_presentation; } Font; typedef struct { @@ -250,12 +250,12 @@ desc_to_face(PyObject *desc) { static inline bool -init_font(Font *f, PyObject *descriptor, bool bold, bool italic, bool is_face) { +init_font(Font *f, PyObject *descriptor, bool bold, bool italic, bool is_face, bool emoji_presentation) { PyObject *face; if (is_face) { face = descriptor; Py_INCREF(face); } else { face = desc_to_face(descriptor); if (face == NULL) return false; } f->face = face; - f->bold = bold; f->italic = italic; + f->bold = bold; f->italic = italic; f->emoji_presentation = emoji_presentation; return true; } @@ -340,7 +340,7 @@ has_cell_text(Font *self, Cell *cell) { static inline ssize_t -load_fallback_font(Cell *cell, bool bold, bool italic) { +load_fallback_font(Cell *cell, bool bold, bool italic, bool emoji_presentation) { if (fonts.fallback_fonts_count > 100) { fprintf(stderr, "Too many fallback fonts\n"); return MISSING_FONT; } ssize_t f; @@ -348,7 +348,7 @@ load_fallback_font(Cell *cell, bool bold, bool italic) { else f = italic ? fonts.italic_font_idx : fonts.medium_font_idx; if (f < 0) f = fonts.medium_font_idx; - PyObject *face = create_fallback_face(fonts.fonts[f].face, cell, bold, italic); + PyObject *face = create_fallback_face(fonts.fonts[f].face, cell, bold, italic, emoji_presentation); if (face == NULL) { PyErr_Print(); return MISSING_FONT; } if (face == Py_None) { Py_DECREF(face); return MISSING_FONT; } set_size_for_face(face, cell_height, true); @@ -356,7 +356,7 @@ load_fallback_font(Cell *cell, bool bold, bool italic) { ensure_space_for(&fonts, fonts, Font, fonts.fonts_count + 1, fonts_capacity, 5, true); ssize_t ans = fonts.first_fallback_font_idx + fonts.fallback_fonts_count; Font *af = &fonts.fonts[ans]; - if (!init_font(af, face, bold, italic, true)) fatal("Out of memory"); + if (!init_font(af, face, bold, italic, true, emoji_presentation)) fatal("Out of memory"); Py_DECREF(face); fonts.fallback_fonts_count++; fonts.fonts_count++; @@ -368,24 +368,17 @@ static inline ssize_t fallback_font(Cell *cell) { bool bold = (cell->attrs >> BOLD_SHIFT) & 1; bool italic = (cell->attrs >> ITALIC_SHIFT) & 1; - - // Load the emoji fallback font first as on Linux there are a bunch of - // non-color fonts that provide some emoji glyphs. - if (fonts.fallback_fonts_count < 1) { - Cell c = {0}; - c.ch = 0x1f648; // 🙈 - load_fallback_font(&c, false, false); - } + bool emoji_presentation = (cell->attrs & WIDTH_MASK) == 2 && is_emoji(cell->ch) && cell->cc_idx[0] != mark_for_codepoint(0xfe0e); // Check if one of the existing fallback fonts has this text for (size_t i = 0, j = fonts.first_fallback_font_idx; i < fonts.fallback_fonts_count; i++, j++) { Font *ff = fonts.fonts +j; - if (ff->bold == bold && ff->italic == italic && has_cell_text(ff, cell)) { + if (ff->bold == bold && ff->italic == italic && ff->emoji_presentation == emoji_presentation && has_cell_text(ff, cell)) { return j; } } - return load_fallback_font(cell, bold, italic); + return load_fallback_font(cell, bold, italic, emoji_presentation); } static inline ssize_t @@ -882,7 +875,7 @@ set_font(PyObject UNUSED *m, PyObject *args) { for (size_t i = 0; i < fonts.fonts_count; i++) del_font(fonts.fonts + i); ensure_space_for(&fonts, fonts, Font, num_fonts, fonts_capacity, 5, true); fonts.fonts_count = 1; -#define A(attr, bold, italic) { if(attr) { if (!init_font(&fonts.fonts[fonts.fonts_count], attr, bold, italic, false)) return NULL; fonts.attr##_font_idx = fonts.fonts_count++; } else fonts.attr##_font_idx = -1; } +#define A(attr, bold, italic) { if(attr) { if (!init_font(&fonts.fonts[fonts.fonts_count], attr, bold, italic, false, false)) return NULL; fonts.attr##_font_idx = fonts.fonts_count++; } else fonts.attr##_font_idx = -1; } A(medium, false, false); A(bold, true, false); A(italic, false, true); A(bi, true, true); #undef A @@ -894,7 +887,7 @@ set_font(PyObject UNUSED *m, PyObject *args) { PyObject *face; int bold, italic; if (!PyArg_ParseTuple(PyTuple_GET_ITEM(smf, i), "Opp", &face, &bold, &italic)) return NULL; - if (!init_font(fonts.fonts + fonts.fonts_count++, face, bold != 0, italic != 0, false)) return NULL; + if (!init_font(fonts.fonts + fonts.fonts_count++, face, bold != 0, italic != 0, false, false)) return NULL; } for (size_t i = 0; i < fonts.symbol_maps_count; i++) { unsigned int left, right, font_idx; diff --git a/kitty/fonts.h b/kitty/fonts.h index 58616cc26..b761da465 100644 --- a/kitty/fonts.h +++ b/kitty/fonts.h @@ -21,7 +21,7 @@ hb_font_t* harfbuzz_font_for_face(PyObject*); bool set_size_for_face(PyObject*, unsigned int, bool); void cell_metrics(PyObject*, unsigned int*, unsigned int*, unsigned int*, unsigned int*, unsigned int*); bool render_glyphs_in_cells(PyObject *f, bool bold, bool italic, hb_glyph_info_t *info, hb_glyph_position_t *positions, unsigned int num_glyphs, pixel *canvas, unsigned int cell_width, unsigned int cell_height, unsigned int num_cells, unsigned int baseline, bool *was_colored); -PyObject* create_fallback_face(PyObject *base_face, Cell* cell, bool bold, bool italic); +PyObject* create_fallback_face(PyObject *base_face, Cell* cell, bool bold, bool italic, bool emoji_presentation); PyObject* specialize_font_descriptor(PyObject *base_descriptor); PyObject* face_from_path(const char *path, int index); PyObject* face_from_descriptor(PyObject*); diff --git a/kitty/kitty.conf b/kitty/kitty.conf index 81678bc4f..c69a4c1d8 100644 --- a/kitty/kitty.conf +++ b/kitty/kitty.conf @@ -382,9 +382,3 @@ macos_option_as_alt yes # The number is a percentage of maximum volume. # See man XBell for details. x11_bell_volume 80 - -# Prefer color emoji fonts when available. Note that this only works -# on systems such as Linux that use fontconfig. On other OSes, the emoji -# font used is system dependent. It can be overriden using symbol_map in the kitty -# configuration. -prefer_color_emoji yes diff --git a/kitty/state.c b/kitty/state.c index ba7e20fc7..45815cdca 100644 --- a/kitty/state.c +++ b/kitty/state.c @@ -331,7 +331,6 @@ PYWRAP1(set_options) { #define S(name, convert) { GA(name); global_state.opts.name = convert(ret); Py_DECREF(ret); if (PyErr_Occurred()) return NULL; } S(visual_bell_duration, PyFloat_AsDouble); S(enable_audio_bell, PyObject_IsTrue); - S(prefer_color_emoji, PyObject_IsTrue); S(focus_follows_mouse, PyObject_IsTrue); S(cursor_blink_interval, PyFloat_AsDouble); S(cursor_stop_blinking_after, PyFloat_AsDouble); diff --git a/kitty/state.h b/kitty/state.h index 4ca8a0fe6..a0f3cd0b4 100644 --- a/kitty/state.h +++ b/kitty/state.h @@ -24,7 +24,6 @@ typedef struct { double repaint_delay, input_delay; bool focus_follows_mouse; bool macos_option_as_alt, macos_hide_titlebar; - bool prefer_color_emoji; int adjust_line_height_px, adjust_column_width_px; float adjust_line_height_frac, adjust_column_width_frac; int x11_bell_volume;