X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=unix%2Fgtkfont.c;h=2f7e4a6172e96eb2b87cd6b92777befcd3732716;hb=48eafd66aa274c32fc8169a0d36619663905c210;hp=2099c8332acd90e81904cc73a9f8444a43763f36;hpb=49ff9f480e973060c0c7215868fae53db096ce2d;p=PuTTY.git diff --git a/unix/gtkfont.c b/unix/gtkfont.c index 2099c833..2f7e4a61 100644 --- a/unix/gtkfont.c +++ b/unix/gtkfont.c @@ -83,6 +83,9 @@ struct unifont_vtable { void (*draw_text)(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); + void (*draw_combining)(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth); void (*enum_fonts)(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx); char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size, @@ -107,6 +110,9 @@ static int x11font_has_glyph(unifont *font, wchar_t glyph); static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); +static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, int cellwidth); static unifont *x11font_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); @@ -206,6 +212,7 @@ static const struct unifont_vtable x11font_vtable = { x11font_destroy, x11font_has_glyph, x11font_draw_text, + x11font_draw_combining, x11font_enum_fonts, x11font_canonify_fontname, x11font_scale_fontname, @@ -868,6 +875,20 @@ static void x11font_draw_text(unifont_drawctx *ctx, unifont *font, } } +static void x11font_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, int cellwidth) +{ + /* + * For server-side fonts, there's no sophisticated system for + * combining characters intelligently, so the best we can do is to + * overprint them on each other in the obvious way. + */ + int i; + for (i = 0; i < len; i++) + x11font_draw_text(ctx, font, x, y, string+i, 1, wide, bold, cellwidth); +} + static void x11font_enum_fonts(GtkWidget *widget, fontsel_add_entry callback, void *callback_ctx) { @@ -1112,6 +1133,10 @@ static int pangofont_has_glyph(unifont *font, wchar_t glyph); static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); +static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth); static unifont *pangofont_create(GtkWidget *widget, const char *name, int wide, int bold, int shadowoffset, int shadowalways); @@ -1157,6 +1182,7 @@ static const struct unifont_vtable pangofont_vtable = { pangofont_destroy, pangofont_has_glyph, pangofont_draw_text, + pangofont_draw_combining, pangofont_enum_fonts, pangofont_canonify_fontname, pangofont_scale_fontname, @@ -1338,10 +1364,10 @@ static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont, /* * Here we check whether a character has the same width as the * character cell it'll be drawn in. Because profiling showed that - * pango_layout_get_pixel_extents() was a huge bottleneck when we - * were calling it every time we needed to know this, we instead - * call it only on characters we don't already know about, and - * cache the results. + * asking Pango for text sizes was a huge bottleneck when we were + * calling it every time we needed to know this, we instead call + * it only on characters we don't already know about, and cache + * the results. */ if ((unsigned)uchr >= pfont->nwidthcache) { @@ -1354,7 +1380,7 @@ static int pangofont_char_width(PangoLayout *layout, struct pangofont *pfont, if (pfont->widthcache[uchr] < 0) { PangoRectangle rect; pango_layout_set_text(layout, utfchr, utflen); - pango_layout_get_pixel_extents(layout, NULL, &rect); + pango_layout_get_extents(layout, NULL, &rect); pfont->widthcache[uchr] = rect.width; } @@ -1384,9 +1410,10 @@ static void pango_cairo_draw_layout(unifont_drawctx *ctx, } #endif -static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, - int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) +static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, int cellwidth, + int combining) { struct pangofont *pfont = (struct pangofont *)font; PangoLayout *layout; @@ -1437,6 +1464,7 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, utfptr = utfstring; while (utflen > 0) { int clen, n; + int desired = cellwidth * PANGO_SCALE; /* * We want to display every character from this string in @@ -1462,45 +1490,55 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, * them to do that. */ - /* - * Start by extracting a single UTF-8 character from the - * string. - */ - clen = 1; - while (clen < utflen && - (unsigned char)utfptr[clen] >= 0x80 && - (unsigned char)utfptr[clen] < 0xC0) - clen++; - n = 1; - - if (is_rtl(string[0]) || - pangofont_char_width(layout, pfont, string[n-1], - utfptr, clen) != cellwidth) { + if (combining) { /* - * If this character is a right-to-left one, or has an - * unusual width, then we must display it on its own. + * For a character with combining stuff, we just dump the + * whole lot in one go, and expect it to take up just one + * character cell. */ + clen = utflen; + n = 1; } else { /* - * Try to amalgamate a contiguous string of characters - * with the expected sensible width, for the common case - * in which we're using a monospaced font and everything - * works as expected. + * Start by extracting a single UTF-8 character from the + * string. */ - while (clen < utflen) { - int oldclen = clen; - clen++; /* skip UTF-8 introducer byte */ - while (clen < utflen && - (unsigned char)utfptr[clen] >= 0x80 && - (unsigned char)utfptr[clen] < 0xC0) - clen++; - n++; - if (pangofont_char_width(layout, pfont, - string[n-1], utfptr + oldclen, - clen - oldclen) != cellwidth) { - clen = oldclen; - n--; - break; + clen = 1; + while (clen < utflen && + (unsigned char)utfptr[clen] >= 0x80 && + (unsigned char)utfptr[clen] < 0xC0) + clen++; + n = 1; + + if (is_rtl(string[0]) || + pangofont_char_width(layout, pfont, string[n-1], + utfptr, clen) != desired) { + /* + * If this character is a right-to-left one, or has an + * unusual width, then we must display it on its own. + */ + } else { + /* + * Try to amalgamate a contiguous string of characters + * with the expected sensible width, for the common case + * in which we're using a monospaced font and everything + * works as expected. + */ + while (clen < utflen) { + int oldclen = clen; + clen++; /* skip UTF-8 introducer byte */ + while (clen < utflen && + (unsigned char)utfptr[clen] >= 0x80 && + (unsigned char)utfptr[clen] < 0xC0) + clen++; + n++; + if (pangofont_char_width(layout, pfont, + string[n-1], utfptr + oldclen, + clen - oldclen) != desired) { + clen = oldclen; + n--; + break; + } } } } @@ -1527,6 +1565,37 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, g_object_unref(layout); } +static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth) +{ + pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold, + cellwidth, FALSE); +} + +static void pangofont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth) +{ + wchar_t *tmpstring = NULL; + if (mk_wcwidth(string[0]) == 0) { + /* + * If we've been told to draw a sequence of _only_ combining + * characters, prefix a space so that they have something to + * combine with. + */ + tmpstring = snewn(len+1, wchar_t); + memcpy(tmpstring+1, string, len * sizeof(wchar_t)); + tmpstring[0] = L' '; + string = tmpstring; + len++; + } + pangofont_draw_internal(ctx, font, x, y, string, len, wide, bold, + cellwidth, TRUE); + sfree(tmpstring); +} + /* * Dummy size value to be used when converting a * PangoFontDescription of a scalable font to a string for @@ -1872,6 +1941,14 @@ void unifont_draw_text(unifont_drawctx *ctx, unifont *font, font->vt->draw_text(ctx, font, x, y, string, len, wide, bold, cellwidth); } +void unifont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth) +{ + font->vt->draw_combining(ctx, font, x, y, string, len, wide, bold, + cellwidth); +} + /* ---------------------------------------------------------------------- * Multiple-font wrapper. This is a type of unifont which encapsulates * up to two other unifonts, permitting missing glyphs in the main @@ -1888,6 +1965,10 @@ void unifont_draw_text(unifont_drawctx *ctx, unifont *font, static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, int wide, int bold, int cellwidth); +static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth); static void multifont_destroy(unifont *font); struct multifont { @@ -1902,6 +1983,7 @@ static const struct unifont_vtable multifont_vtable = { multifont_destroy, NULL, multifont_draw_text, + multifont_draw_combining, NULL, NULL, NULL, @@ -1962,9 +2044,15 @@ static void multifont_destroy(unifont *font) sfree(font); } -static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, +typedef void (*unifont_draw_func_t)(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth); + +static void multifont_draw_main(unifont_drawctx *ctx, unifont *font, int x, int y, const wchar_t *string, int len, - int wide, int bold, int cellwidth) + int wide, int bold, int cellwidth, + int cellinc, unifont_draw_func_t draw) { struct multifont *mfont = (struct multifont *)font; unifont *f; @@ -1986,13 +2074,30 @@ static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, */ f = ok ? mfont->main : mfont->fallback; if (f) - unifont_draw_text(ctx, f, x, y, string, i, wide, bold, cellwidth); + draw(ctx, f, x, y, string, i, wide, bold, cellwidth); string += i; len -= i; - x += i * cellwidth; + x += i * cellinc; } } +static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x, + int y, const wchar_t *string, int len, + int wide, int bold, int cellwidth) +{ + multifont_draw_main(ctx, font, x, y, string, len, wide, bold, + cellwidth, cellwidth, unifont_draw_text); +} + +static void multifont_draw_combining(unifont_drawctx *ctx, unifont *font, + int x, int y, const wchar_t *string, + int len, int wide, int bold, + int cellwidth) +{ + multifont_draw_main(ctx, font, x, y, string, len, wide, bold, + cellwidth, 0, unifont_draw_combining); +} + #if GTK_CHECK_VERSION(2,0,0) /* ---------------------------------------------------------------------- @@ -2250,7 +2355,7 @@ static void unifontsel_setup_stylelist(unifontsel_internal *fs, gtk_list_store_append(fs->style_model, &iter); gtk_list_store_set(fs->style_model, &iter, 0, currstyle, 1, minpos, 2, maxpos+1, - 3, TRUE, -1); + 3, TRUE, 4, PANGO_WEIGHT_NORMAL, -1); listindex++; } if (info) { @@ -2259,7 +2364,7 @@ static void unifontsel_setup_stylelist(unifontsel_internal *fs, gtk_list_store_append(fs->style_model, &iter); gtk_list_store_set(fs->style_model, &iter, 0, info->charset, 1, -1, 2, -1, - 3, FALSE, -1); + 3, FALSE, 4, PANGO_WEIGHT_BOLD, -1); listindex++; } currcs = info->charset; @@ -3099,19 +3204,21 @@ unifontsel *unifontsel_new(const char *wintitle) #endif /* - * The Style list box can contain insensitive elements - * (character set headings for server-side fonts), so we add - * an extra column to the list store to hold that information. + * The Style list box can contain insensitive elements (character + * set headings for server-side fonts), so we add an extra column + * to the list store to hold that information. Also, since GTK3 at + * least doesn't seem to display insensitive elements differently + * by default, we add a further column to change their style. */ - model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, - G_TYPE_BOOLEAN); + model = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT, + G_TYPE_BOOLEAN, G_TYPE_INT); w = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(w), FALSE); gtk_label_set_mnemonic_widget(GTK_LABEL(label), w); gtk_widget_show(w); column = gtk_tree_view_column_new_with_attributes ("Style", gtk_cell_renderer_text_new(), - "text", 0, "sensitive", 3, (char *)NULL); + "text", 0, "sensitive", 3, "weight", 4, (char *)NULL); gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); gtk_tree_view_append_column(GTK_TREE_VIEW(w), column); g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(w))),