mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-05-10 06:02:10 -05:00
GTK: purely server-side X bitmap font rendering with Cairo
This is a fairly radical change of how X bitmap fonts are handled when using Cairo for rendering. Before, we would download each glyph to the client on first use and then composite those glyphs into the terminal's backing surface. This worked pretty well when we were keeping an image of the whole screen on the client anyway, but once I'd pushed all the other Cairo rendering onto the X server, it meant that the character bitmaps had to be repeatedly pushed to the X server. The new arrangement just renders each string into a temporary Pixmap using the usual X text-drawing calls and then asks Cairo to paste it into the main backing Pixmap. It's tempting to draw the text straight into the backing Pixmap, but that would require dealing directly with X colour management. This way, we get to leave colours in the hands of Cairo (and hence the Render extension). There are still fragments of the old system around. Those should go in the next commit.
This commit is contained in:
parent
08bc670304
commit
9bd1b234a0
133
unix/unifont.c
133
unix/unifont.c
@ -685,70 +685,41 @@ static void x11font_cairo_setup(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void x11font_cairo_cache_glyph(
|
|
||||||
Display *disp, x11font_individual *xfi, int glyphindex)
|
|
||||||
{
|
|
||||||
if (xfi->nglyphs <= glyphindex) {
|
|
||||||
/* Round up to the next multiple of 256 on the general
|
|
||||||
* principle that Unicode characters come in contiguous blocks
|
|
||||||
* often used together */
|
|
||||||
int old_nglyphs = xfi->nglyphs;
|
|
||||||
xfi->nglyphs = (glyphindex + 0x100) & ~0xFF;
|
|
||||||
xfi->glyphcache = sresize(xfi->glyphcache, xfi->nglyphs,
|
|
||||||
struct cairo_cached_glyph);
|
|
||||||
|
|
||||||
while (old_nglyphs < xfi->nglyphs) {
|
|
||||||
xfi->glyphcache[old_nglyphs].surface = NULL;
|
|
||||||
old_nglyphs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cairo_surface_mark_dirty(xfi->pixmap_surface);
|
|
||||||
xfi->glyphcache[glyphindex].surface = cairo_image_surface_create(
|
|
||||||
CAIRO_FORMAT_A1, xfi->pixwidth, xfi->pixheight);
|
|
||||||
cairo_t *cr = cairo_create(xfi->glyphcache[glyphindex].surface);
|
|
||||||
cairo_set_source_surface(cr, xfi->pixmap_surface, 0, 0);
|
|
||||||
cairo_paint(cr);
|
|
||||||
cairo_destroy(cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void x11font_cairo_draw_glyph(unifont_drawctx *ctx,
|
|
||||||
x11font_individual *xfi, int x, int y,
|
|
||||||
int glyphindex)
|
|
||||||
{
|
|
||||||
if (xfi->glyphcache[glyphindex].surface) {
|
|
||||||
cairo_pattern_t *glyph_pattern = cairo_pattern_create_for_surface(
|
|
||||||
xfi->glyphcache[glyphindex].surface);
|
|
||||||
cairo_matrix_t xfrm;
|
|
||||||
/* We really don't want bilinear interpolation of bitmap fonts. */
|
|
||||||
cairo_pattern_set_filter(glyph_pattern, CAIRO_FILTER_NEAREST);
|
|
||||||
cairo_matrix_init_translate(&xfrm, -(x - xfi->pixoriginx),
|
|
||||||
-(y - xfi->pixoriginy));
|
|
||||||
cairo_pattern_set_matrix(glyph_pattern, &xfrm);
|
|
||||||
cairo_mask(ctx->u.cairo.cr, glyph_pattern);
|
|
||||||
cairo_pattern_destroy(glyph_pattern);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void x11font_cairo_draw_16(
|
static void x11font_cairo_draw_16(
|
||||||
unifont_drawctx *ctx, x11font_individual *xfi, Display *disp,
|
unifont_drawctx *ctx, x11font_individual *xfi, Display *disp,
|
||||||
int x, int y, const void *vstring, int start, int length)
|
int x, int y, const void *vstring, int start, int length)
|
||||||
{
|
{
|
||||||
const XChar2b *string = (const XChar2b *)vstring + start;
|
const XChar2b *string = (const XChar2b *)vstring + start;
|
||||||
int i;
|
GdkWindow *widgetwin = gtk_widget_get_window(ctx->u.cairo.widget);
|
||||||
for (i = 0; i < length; i++) {
|
int widgetscr = GDK_SCREEN_XNUMBER(gdk_window_get_screen(widgetwin));
|
||||||
if (x11_font_has_glyph(xfi->xfs, string[i].byte1, string[i].byte2)) {
|
XCharStruct bounds;
|
||||||
int glyphindex = (256 * (unsigned char)string[i].byte1 +
|
int pixwidth, pixheight, direction, font_ascent, font_descent;
|
||||||
(unsigned char)string[i].byte2);
|
Pixmap pixmap;
|
||||||
if (glyphindex >= xfi->nglyphs ||
|
|
||||||
!xfi->glyphcache[glyphindex].surface) {
|
XTextExtents16(xfi->xfs, string + start, length,
|
||||||
XDrawImageString16(disp, xfi->pixmap, xfi->gc,
|
&direction, &font_ascent, &font_descent, &bounds);
|
||||||
xfi->pixoriginx, xfi->pixoriginy,
|
pixwidth = bounds.rbearing - bounds.lbearing;
|
||||||
string+i, 1);
|
pixheight = bounds.ascent + bounds.descent;
|
||||||
x11font_cairo_cache_glyph(disp, xfi, glyphindex);
|
if (pixwidth > 0 && pixheight > 0) {
|
||||||
}
|
pixmap = XCreatePixmap(disp, GDK_DRAWABLE_XID(widgetwin),
|
||||||
x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
|
pixwidth, pixheight, 1);
|
||||||
x += XTextWidth16(xfi->xfs, string+i, 1);
|
XDrawImageString16(disp, pixmap, xfi->gc,
|
||||||
}
|
-bounds.lbearing, bounds.ascent,
|
||||||
|
string+start, length);
|
||||||
|
cairo_surface_t *surface = cairo_xlib_surface_create_for_bitmap(
|
||||||
|
disp, pixmap, ScreenOfDisplay(disp, widgetscr),
|
||||||
|
pixwidth, pixheight);
|
||||||
|
cairo_pattern_t *pattern = cairo_pattern_create_for_surface(surface);
|
||||||
|
/* We really don't want bilinear interpolation of bitmap fonts. */
|
||||||
|
cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
|
||||||
|
cairo_matrix_t xfrm;
|
||||||
|
cairo_matrix_init_translate(&xfrm,
|
||||||
|
-x - bounds.lbearing, -y + bounds.ascent);
|
||||||
|
cairo_pattern_set_matrix(pattern, &xfrm);
|
||||||
|
cairo_mask(ctx->u.cairo.cr, pattern);
|
||||||
|
cairo_pattern_destroy(pattern);
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
|
XFreePixmap(disp, pixmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -757,20 +728,36 @@ static void x11font_cairo_draw_8(
|
|||||||
int x, int y, const void *vstring, int start, int length)
|
int x, int y, const void *vstring, int start, int length)
|
||||||
{
|
{
|
||||||
const char *string = (const char *)vstring + start;
|
const char *string = (const char *)vstring + start;
|
||||||
int i;
|
GdkWindow *widgetwin = gtk_widget_get_window(ctx->u.cairo.widget);
|
||||||
for (i = 0; i < length; i++) {
|
int widgetscr = GDK_SCREEN_XNUMBER(gdk_window_get_screen(widgetwin));
|
||||||
if (x11_font_has_glyph(xfi->xfs, 0, string[i])) {
|
XCharStruct bounds;
|
||||||
int glyphindex = (unsigned char)string[i];
|
int pixwidth, pixheight, direction, font_ascent, font_descent;
|
||||||
if (glyphindex >= xfi->nglyphs ||
|
Pixmap pixmap;
|
||||||
!xfi->glyphcache[glyphindex].surface) {
|
|
||||||
XDrawImageString(disp, xfi->pixmap, xfi->gc,
|
XTextExtents(xfi->xfs, string + start, length,
|
||||||
xfi->pixoriginx, xfi->pixoriginy,
|
&direction, &font_ascent, &font_descent, &bounds);
|
||||||
string+i, 1);
|
pixwidth = bounds.rbearing - bounds.lbearing;
|
||||||
x11font_cairo_cache_glyph(disp, xfi, glyphindex);
|
pixheight = bounds.ascent + bounds.descent;
|
||||||
}
|
if (pixwidth > 0 && pixheight > 0) {
|
||||||
x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
|
pixmap = XCreatePixmap(disp, GDK_DRAWABLE_XID(widgetwin),
|
||||||
x += XTextWidth(xfi->xfs, string+i, 1);
|
pixwidth, pixheight, 1);
|
||||||
}
|
XDrawImageString(disp, pixmap, xfi->gc,
|
||||||
|
-bounds.lbearing, bounds.ascent,
|
||||||
|
string+start, length);
|
||||||
|
cairo_surface_t *surface = cairo_xlib_surface_create_for_bitmap(
|
||||||
|
disp, pixmap, ScreenOfDisplay(disp, widgetscr),
|
||||||
|
pixwidth, pixheight);
|
||||||
|
cairo_pattern_t *pattern = cairo_pattern_create_for_surface(surface);
|
||||||
|
/* We really don't want bilinear interpolation of bitmap fonts. */
|
||||||
|
cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
|
||||||
|
cairo_matrix_t xfrm;
|
||||||
|
cairo_matrix_init_translate(&xfrm,
|
||||||
|
-x - bounds.lbearing, -y + bounds.ascent);
|
||||||
|
cairo_pattern_set_matrix(pattern, &xfrm);
|
||||||
|
cairo_mask(ctx->u.cairo.cr, pattern);
|
||||||
|
cairo_pattern_destroy(pattern);
|
||||||
|
cairo_surface_destroy(surface);
|
||||||
|
XFreePixmap(disp, pixmap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* DRAW_TEXT_CAIRO */
|
#endif /* DRAW_TEXT_CAIRO */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user