summaryrefslogtreecommitdiffstats
path: root/src/gui_gtk_x11.c
diff options
context:
space:
mode:
authorDusan Popovic <dpx@binaryapparatus.com>2021-10-16 20:52:05 +0100
committerBram Moolenaar <Bram@vim.org>2021-10-16 20:52:05 +0100
commit4eeedc09fed0cbbb3ba48317e0a01e20cd0b4f80 (patch)
treecac81ddbe09eac705e72e2c3390749cc60a16ae0 /src/gui_gtk_x11.c
parentc89c91cafd91fbf17f431d800bbf4cafcffffe7a (diff)
patch 8.2.3524: GUI: ligatures are not usedv8.2.3524
Problem: GUI: ligatures are not used. Solution: Add the 'guiligatures' option. (Dusan Popovic, closes #8933)
Diffstat (limited to 'src/gui_gtk_x11.c')
-rw-r--r--src/gui_gtk_x11.c150
1 files changed, 136 insertions, 14 deletions
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c
index 1a3eadad72..c55d9792bb 100644
--- a/src/gui_gtk_x11.c
+++ b/src/gui_gtk_x11.c
@@ -5595,18 +5595,22 @@ draw_under(int flags, int row, int col, int cells)
int
gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags)
{
- GdkRectangle area; // area for clip mask
- PangoGlyphString *glyphs; // glyphs of current item
- int column_offset = 0; // column offset in cells
- int i;
- char_u *conv_buf = NULL; // result of UTF-8 conversion
- char_u *new_conv_buf;
- int convlen;
- char_u *sp, *bp;
- int plen;
-#if GTK_CHECK_VERSION(3,0,0)
- cairo_t *cr;
-#endif
+ char_u *conv_buf = NULL; // result of UTF-8 conversion
+ char_u *new_conv_buf;
+ int convlen;
+ char_u *sp, *bp;
+ int plen;
+ int len_sum; // return value needs to add up since we are
+ // printing substrings
+ int byte_sum; // byte position in string
+ char_u *cs; // current *s pointer
+ int needs_pango; // look ahead, 0=ascii 1=unicode/ligatures
+ int should_need_pango;
+ int slen;
+ int is_ligature;
+ int next_is_ligature;
+ int is_utf8;
+ char_u backup_ch;
if (gui.text_context == NULL || gtk_widget_get_window(gui.drawarea) == NULL)
return len;
@@ -5653,6 +5657,124 @@ gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags)
}
/*
+ * Ligature support and complex utf-8 char optimization:
+ * String received to output to screen can print using pre-cached glyphs
+ * (fast) or Pango (slow). Ligatures and multibype utf-8 must use Pango.
+ * Since we receive mixed content string, split it into logical segments
+ * that are guaranteed to go trough glyphs as much as possible. Since
+ * single ligature char prints as ascii, print it that way.
+ */
+ len_sum = 0; // return value needs to add up since we are printing
+ // substrings
+ byte_sum = 0;
+ cs = s;
+ // look ahead, 0=ascii 1=unicode/ligatures
+ needs_pango = ((*cs & 0x80) || gui.ligatures_map[*cs]);
+
+ // split string into ascii and non-ascii (ligatures + utf-8) substrings,
+ // print glyphs or use Pango
+ while (cs < s + len)
+ {
+ slen = 0;
+ while (slen < (len - byte_sum))
+ {
+ is_ligature = gui.ligatures_map[*(cs + slen)];
+ // look ahead, single ligature char between ascii is ascii
+ if (is_ligature && !needs_pango)
+ {
+ if ((slen + 1) < (len - byte_sum))
+ {
+ next_is_ligature = gui.ligatures_map[*(cs + slen + 1)];
+ if (!next_is_ligature)
+ is_ligature = 0;
+ }
+ else
+ {
+ is_ligature = 0;
+ }
+ }
+ is_utf8 = *(cs + slen) & 0x80;
+ should_need_pango = (is_ligature || is_utf8);
+ if (needs_pango != should_need_pango) // mode switch
+ break;
+ if (needs_pango)
+ {
+ if (is_ligature)
+ {
+ slen++; // ligature char by char
+ }
+ else
+ {
+ if ((*(cs + slen) & 0xC0) == 0x80)
+ {
+ // a continuation, find next 0xC0 != 0x80 but don't
+ // include it
+ while ((slen < (len - byte_sum))
+ && ((*(cs + slen) & 0xC0) == 0x80))
+ {
+ slen++;
+ }
+ }
+ else if ((*(cs + slen) & 0xE0) == 0xC0)
+ {
+ // + one byte utf8
+ slen++;
+ }
+ else if ((*(cs + slen) & 0xF0) == 0xE0)
+ {
+ // + two bytes utf8
+ slen += 2;
+ }
+ else if ((*(cs + slen) & 0xF8) == 0xF0)
+ {
+ // + three bytes utf8
+ slen += 3;
+ }
+ else
+ {
+ // this should not happen, try moving forward, Pango
+ // will catch it
+ slen++;
+ }
+ }
+ }
+ else
+ {
+ slen++; // ascii
+ }
+ }
+ // temporarily zero terminate substring, print, restore char, wrap
+ backup_ch = *(cs + slen);
+ *(cs + slen) = 0;
+ len_sum += gui_gtk2_draw_string_ext(row, col + len_sum,
+ cs, slen, flags, needs_pango);
+ *(cs + slen) = backup_ch;
+ cs += slen;
+ byte_sum += slen;
+ needs_pango = should_need_pango;
+ }
+ vim_free(conv_buf);
+ return len_sum;
+}
+
+ int
+gui_gtk2_draw_string_ext(
+ int row,
+ int col,
+ char_u *s,
+ int len,
+ int flags,
+ int force_pango)
+{
+ GdkRectangle area; // area for clip mask
+ PangoGlyphString *glyphs; // glyphs of current item
+ int column_offset = 0; // column offset in cells
+ int i;
+#if GTK_CHECK_VERSION(3,0,0)
+ cairo_t *cr;
+#endif
+
+ /*
* Restrict all drawing to the current screen line in order to prevent
* fuzzy font lookups from messing up the screen.
*/
@@ -5679,7 +5801,8 @@ gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags)
*/
if (!(flags & DRAW_ITALIC)
&& !((flags & DRAW_BOLD) && gui.font_can_bold)
- && gui.ascii_glyphs != NULL)
+ && gui.ascii_glyphs != NULL
+ && !force_pango)
{
char_u *p;
@@ -5883,7 +6006,6 @@ skipitall:
#endif
pango_glyph_string_free(glyphs);
- vim_free(conv_buf);
#if GTK_CHECK_VERSION(3,0,0)
cairo_destroy(cr);