mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-22 14:39:24 -05:00
Fix combining character handling in Pango.
The top-level loop in gtkwin.c which draws text was expecting that the right way to draw a printing character plus combining characters was to overprint them one by one on top of each other. This is an OK assumption for X bitmap fonts, but in Pango, it works very badly - most obviously because asking Pango to display a combining char on its own causes it to print a dotted circle representing the base char, but also because surely there will be character combinations where Pango wants to do something more sophisticated than just printing them each at a standard offset, and it would be a shame not to let it. So I've moved the previous overprinting loop down into the x11font subclass of the unifont mechanism. The top-level gtkwin.c drawing code now calls a new method unifont_draw_combining, which in the X11 case does the same loop as before, but in the Pango case, just passes a whole base+combinings string to Pango in one go and lets it do the best job it can.
This commit is contained in:
parent
431f8db862
commit
854fae843b
186
unix/gtkfont.c
186
unix/gtkfont.c
@ -83,6 +83,9 @@ struct unifont_vtable {
|
|||||||
void (*draw_text)(unifont_drawctx *ctx, unifont *font,
|
void (*draw_text)(unifont_drawctx *ctx, unifont *font,
|
||||||
int x, int y, const wchar_t *string, int len,
|
int x, int y, const wchar_t *string, int len,
|
||||||
int wide, int bold, int cellwidth);
|
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,
|
void (*enum_fonts)(GtkWidget *widget,
|
||||||
fontsel_add_entry callback, void *callback_ctx);
|
fontsel_add_entry callback, void *callback_ctx);
|
||||||
char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size,
|
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,
|
static void x11font_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||||
int x, int y, const wchar_t *string, int len,
|
int x, int y, const wchar_t *string, int len,
|
||||||
int wide, int bold, int cellwidth);
|
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,
|
static unifont *x11font_create(GtkWidget *widget, const char *name,
|
||||||
int wide, int bold,
|
int wide, int bold,
|
||||||
int shadowoffset, int shadowalways);
|
int shadowoffset, int shadowalways);
|
||||||
@ -206,6 +212,7 @@ static const struct unifont_vtable x11font_vtable = {
|
|||||||
x11font_destroy,
|
x11font_destroy,
|
||||||
x11font_has_glyph,
|
x11font_has_glyph,
|
||||||
x11font_draw_text,
|
x11font_draw_text,
|
||||||
|
x11font_draw_combining,
|
||||||
x11font_enum_fonts,
|
x11font_enum_fonts,
|
||||||
x11font_canonify_fontname,
|
x11font_canonify_fontname,
|
||||||
x11font_scale_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,
|
static void x11font_enum_fonts(GtkWidget *widget,
|
||||||
fontsel_add_entry callback, void *callback_ctx)
|
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,
|
static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||||
int x, int y, const wchar_t *string, int len,
|
int x, int y, const wchar_t *string, int len,
|
||||||
int wide, int bold, int cellwidth);
|
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,
|
static unifont *pangofont_create(GtkWidget *widget, const char *name,
|
||||||
int wide, int bold,
|
int wide, int bold,
|
||||||
int shadowoffset, int shadowalways);
|
int shadowoffset, int shadowalways);
|
||||||
@ -1157,6 +1182,7 @@ static const struct unifont_vtable pangofont_vtable = {
|
|||||||
pangofont_destroy,
|
pangofont_destroy,
|
||||||
pangofont_has_glyph,
|
pangofont_has_glyph,
|
||||||
pangofont_draw_text,
|
pangofont_draw_text,
|
||||||
|
pangofont_draw_combining,
|
||||||
pangofont_enum_fonts,
|
pangofont_enum_fonts,
|
||||||
pangofont_canonify_fontname,
|
pangofont_canonify_fontname,
|
||||||
pangofont_scale_fontname,
|
pangofont_scale_fontname,
|
||||||
@ -1384,9 +1410,10 @@ static void pango_cairo_draw_layout(unifont_drawctx *ctx,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
|
static void pangofont_draw_internal(unifont_drawctx *ctx, unifont *font,
|
||||||
int x, int y, const wchar_t *string, int len,
|
int x, int y, const wchar_t *string,
|
||||||
int wide, int bold, int cellwidth)
|
int len, int wide, int bold, int cellwidth,
|
||||||
|
int combining)
|
||||||
{
|
{
|
||||||
struct pangofont *pfont = (struct pangofont *)font;
|
struct pangofont *pfont = (struct pangofont *)font;
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
@ -1463,45 +1490,55 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
|
|||||||
* them to do that.
|
* them to do that.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
if (combining) {
|
||||||
* 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) != desired) {
|
|
||||||
/*
|
/*
|
||||||
* If this character is a right-to-left one, or has an
|
* For a character with combining stuff, we just dump the
|
||||||
* unusual width, then we must display it on its own.
|
* whole lot in one go, and expect it to take up just one
|
||||||
|
* character cell.
|
||||||
*/
|
*/
|
||||||
|
clen = utflen;
|
||||||
|
n = 1;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Try to amalgamate a contiguous string of characters
|
* Start by extracting a single UTF-8 character from the
|
||||||
* with the expected sensible width, for the common case
|
* string.
|
||||||
* in which we're using a monospaced font and everything
|
|
||||||
* works as expected.
|
|
||||||
*/
|
*/
|
||||||
while (clen < utflen) {
|
clen = 1;
|
||||||
int oldclen = clen;
|
while (clen < utflen &&
|
||||||
clen++; /* skip UTF-8 introducer byte */
|
(unsigned char)utfptr[clen] >= 0x80 &&
|
||||||
while (clen < utflen &&
|
(unsigned char)utfptr[clen] < 0xC0)
|
||||||
(unsigned char)utfptr[clen] >= 0x80 &&
|
clen++;
|
||||||
(unsigned char)utfptr[clen] < 0xC0)
|
n = 1;
|
||||||
clen++;
|
|
||||||
n++;
|
if (is_rtl(string[0]) ||
|
||||||
if (pangofont_char_width(layout, pfont,
|
pangofont_char_width(layout, pfont, string[n-1],
|
||||||
string[n-1], utfptr + oldclen,
|
utfptr, clen) != desired) {
|
||||||
clen - oldclen) != desired) {
|
/*
|
||||||
clen = oldclen;
|
* If this character is a right-to-left one, or has an
|
||||||
n--;
|
* unusual width, then we must display it on its own.
|
||||||
break;
|
*/
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1528,6 +1565,37 @@ static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
|
|||||||
g_object_unref(layout);
|
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
|
* Dummy size value to be used when converting a
|
||||||
* PangoFontDescription of a scalable font to a string for
|
* PangoFontDescription of a scalable font to a string for
|
||||||
@ -1873,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);
|
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
|
* Multiple-font wrapper. This is a type of unifont which encapsulates
|
||||||
* up to two other unifonts, permitting missing glyphs in the main
|
* up to two other unifonts, permitting missing glyphs in the main
|
||||||
@ -1889,6 +1965,10 @@ void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
|
|||||||
static void multifont_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 x, int y, const wchar_t *string, int len,
|
||||||
int wide, int bold, int cellwidth);
|
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);
|
static void multifont_destroy(unifont *font);
|
||||||
|
|
||||||
struct multifont {
|
struct multifont {
|
||||||
@ -1903,6 +1983,7 @@ static const struct unifont_vtable multifont_vtable = {
|
|||||||
multifont_destroy,
|
multifont_destroy,
|
||||||
NULL,
|
NULL,
|
||||||
multifont_draw_text,
|
multifont_draw_text,
|
||||||
|
multifont_draw_combining,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
@ -1963,9 +2044,15 @@ static void multifont_destroy(unifont *font)
|
|||||||
sfree(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 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;
|
struct multifont *mfont = (struct multifont *)font;
|
||||||
unifont *f;
|
unifont *f;
|
||||||
@ -1987,13 +2074,30 @@ static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x,
|
|||||||
*/
|
*/
|
||||||
f = ok ? mfont->main : mfont->fallback;
|
f = ok ? mfont->main : mfont->fallback;
|
||||||
if (f)
|
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;
|
string += i;
|
||||||
len -= 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)
|
#if GTK_CHECK_VERSION(2,0,0)
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
|
@ -136,6 +136,12 @@ void unifont_destroy(unifont *font);
|
|||||||
void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
|
void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||||
int x, int y, const wchar_t *string, int len,
|
int x, int y, const wchar_t *string, int len,
|
||||||
int wide, int bold, int cellwidth);
|
int wide, int bold, int cellwidth);
|
||||||
|
/* Same as unifont_draw_text, but expects 'string' to contain one
|
||||||
|
* normal char plus combining chars, and overdraws them all in the
|
||||||
|
* same character cell. */
|
||||||
|
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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function behaves exactly like the low-level unifont_create,
|
* This function behaves exactly like the low-level unifont_create,
|
||||||
|
@ -3397,7 +3397,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
|
|||||||
{
|
{
|
||||||
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
|
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
|
||||||
struct gui_data *inst = dctx->inst;
|
struct gui_data *inst = dctx->inst;
|
||||||
int ncombining, combining;
|
int ncombining;
|
||||||
int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold;
|
int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold;
|
||||||
int monochrome =
|
int monochrome =
|
||||||
gdk_visual_get_depth(gtk_widget_get_visual(inst->area)) == 1;
|
gdk_visual_get_depth(gtk_widget_get_visual(inst->area)) == 1;
|
||||||
@ -3494,11 +3494,20 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
|
|||||||
rlen*widefactor*inst->font_width, inst->font_height);
|
rlen*widefactor*inst->font_width, inst->font_height);
|
||||||
|
|
||||||
draw_set_colour(dctx, nfg);
|
draw_set_colour(dctx, nfg);
|
||||||
for (combining = 0; combining < ncombining; combining++) {
|
if (ncombining > 1) {
|
||||||
|
assert(len == 1);
|
||||||
|
unifont_draw_combining(&dctx->uctx, inst->fonts[fontid],
|
||||||
|
x*inst->font_width+inst->window_border,
|
||||||
|
(y*inst->font_height+inst->window_border+
|
||||||
|
inst->fonts[0]->ascent),
|
||||||
|
text, ncombining, widefactor > 1,
|
||||||
|
bold, inst->font_width);
|
||||||
|
} else {
|
||||||
unifont_draw_text(&dctx->uctx, inst->fonts[fontid],
|
unifont_draw_text(&dctx->uctx, inst->fonts[fontid],
|
||||||
x*inst->font_width+inst->window_border,
|
x*inst->font_width+inst->window_border,
|
||||||
y*inst->font_height+inst->window_border+inst->fonts[0]->ascent,
|
(y*inst->font_height+inst->window_border+
|
||||||
text + combining, len, widefactor > 1,
|
inst->fonts[0]->ascent),
|
||||||
|
text, len, widefactor > 1,
|
||||||
bold, inst->font_width);
|
bold, inst->font_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user