mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-05-10 06:02:10 -05:00
GTK: use Cairo to read X font bitmaps from server
When using an X server-side font with Cairo rendering, PuTTY takes the rather horrible approach of rendering each glyph it uses into a depth-1 Pixmap and then copying the result into a Cairo surface that it uses every time it wants to display that glyph. Heretofore, the conversion of the Pixmap into a Cairo surface was done by downloading it using XGetImage() and then manually re-arringing the bits into a suitable form for Cairo. But Cairo has a way of turning an X Drawable (including a Pixmap) into a surface, and then it's just a case of copying one surface to another using cairo_paint(). So that's what PuTTY does now and the process is a little less unpleasant than it was.
This commit is contained in:
parent
5cf14b4f27
commit
11f4e2d8b5
@ -27,6 +27,9 @@
|
|||||||
#include "tree234.h"
|
#include "tree234.h"
|
||||||
|
|
||||||
#ifndef NOT_X_WINDOWS
|
#ifndef NOT_X_WINDOWS
|
||||||
|
#ifdef DRAW_TEXT_CAIRO
|
||||||
|
#include <cairo-xlib.h>
|
||||||
|
#endif
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
@ -131,7 +134,6 @@ static char *x11font_size_increment(unifont *font, int increment);
|
|||||||
#ifdef DRAW_TEXT_CAIRO
|
#ifdef DRAW_TEXT_CAIRO
|
||||||
struct cairo_cached_glyph {
|
struct cairo_cached_glyph {
|
||||||
cairo_surface_t *surface;
|
cairo_surface_t *surface;
|
||||||
unsigned char *bitmap;
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -165,13 +167,9 @@ typedef struct x11font_individual {
|
|||||||
* X server paraphernalia for actually downloading the glyphs.
|
* X server paraphernalia for actually downloading the glyphs.
|
||||||
*/
|
*/
|
||||||
Pixmap pixmap;
|
Pixmap pixmap;
|
||||||
|
cairo_surface_t *pixmap_surface; /* Cairo version of pixmap. */
|
||||||
GC gc;
|
GC gc;
|
||||||
int pixwidth, pixheight, pixoriginx, pixoriginy;
|
int pixwidth, pixheight, pixoriginx, pixoriginy;
|
||||||
|
|
||||||
/*
|
|
||||||
* Paraphernalia for loading the resulting bitmaps into Cairo.
|
|
||||||
*/
|
|
||||||
int rowsize, allsize, indexflip;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} x11font_individual;
|
} x11font_individual;
|
||||||
@ -535,6 +533,7 @@ static unifont *x11font_create(GtkWidget *widget, const char *name,
|
|||||||
xfont->fonts[i].glyphcache = NULL;
|
xfont->fonts[i].glyphcache = NULL;
|
||||||
xfont->fonts[i].nglyphs = 0;
|
xfont->fonts[i].nglyphs = 0;
|
||||||
xfont->fonts[i].pixmap = None;
|
xfont->fonts[i].pixmap = None;
|
||||||
|
xfont->fonts[i].pixmap_surface = NULL;
|
||||||
xfont->fonts[i].gc = None;
|
xfont->fonts[i].gc = None;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -556,13 +555,14 @@ static void x11font_destroy(unifont *font)
|
|||||||
#ifdef DRAW_TEXT_CAIRO
|
#ifdef DRAW_TEXT_CAIRO
|
||||||
if (xfont->fonts[i].gc != None)
|
if (xfont->fonts[i].gc != None)
|
||||||
XFreeGC(disp, xfont->fonts[i].gc);
|
XFreeGC(disp, xfont->fonts[i].gc);
|
||||||
|
if (xfont->fonts[i].pixmap_surface != NULL)
|
||||||
|
cairo_surface_destroy(xfont->fonts[i].pixmap_surface);
|
||||||
if (xfont->fonts[i].pixmap != None)
|
if (xfont->fonts[i].pixmap != None)
|
||||||
XFreePixmap(disp, xfont->fonts[i].pixmap);
|
XFreePixmap(disp, xfont->fonts[i].pixmap);
|
||||||
if (xfont->fonts[i].glyphcache) {
|
if (xfont->fonts[i].glyphcache) {
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < xfont->fonts[i].nglyphs; j++) {
|
for (j = 0; j < xfont->fonts[i].nglyphs; j++) {
|
||||||
cairo_surface_destroy(xfont->fonts[i].glyphcache[j].surface);
|
cairo_surface_destroy(xfont->fonts[i].glyphcache[j].surface);
|
||||||
sfree(xfont->fonts[i].glyphcache[j].bitmap);
|
|
||||||
}
|
}
|
||||||
sfree(xfont->fonts[i].glyphcache);
|
sfree(xfont->fonts[i].glyphcache);
|
||||||
}
|
}
|
||||||
@ -671,29 +671,12 @@ static void x11font_cairo_setup(
|
|||||||
xfi->pixoriginx = -xfi->xfs->min_bounds.lbearing;
|
xfi->pixoriginx = -xfi->xfs->min_bounds.lbearing;
|
||||||
xfi->pixoriginy = xfi->xfs->max_bounds.ascent;
|
xfi->pixoriginy = xfi->xfs->max_bounds.ascent;
|
||||||
|
|
||||||
xfi->rowsize = cairo_format_stride_for_width(CAIRO_FORMAT_A1,
|
|
||||||
xfi->pixwidth);
|
|
||||||
xfi->allsize = xfi->rowsize * xfi->pixheight;
|
|
||||||
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Test host endianness and use it to set xfi->indexflip,
|
|
||||||
* which is XORed into our left-shift counts in order to
|
|
||||||
* implement the CAIRO_FORMAT_A1 specification, in which
|
|
||||||
* each bitmap byte is oriented LSB-first on little-endian
|
|
||||||
* platforms and MSB-first on big-endian ones.
|
|
||||||
*
|
|
||||||
* This is the same technique Cairo itself uses to test
|
|
||||||
* endianness, so hopefully it'll work in any situation
|
|
||||||
* where Cairo is usable at all.
|
|
||||||
*/
|
|
||||||
static const int endianness_test = 1;
|
|
||||||
xfi->indexflip = (*((char *) &endianness_test) == 1) ? 0 : 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
xfi->pixmap = XCreatePixmap(
|
xfi->pixmap = XCreatePixmap(
|
||||||
disp, GDK_DRAWABLE_XID(gtk_widget_get_window(ctx->u.cairo.widget)),
|
disp, GDK_DRAWABLE_XID(gtk_widget_get_window(ctx->u.cairo.widget)),
|
||||||
xfi->pixwidth, xfi->pixheight, 1);
|
xfi->pixwidth, xfi->pixheight, 1);
|
||||||
|
xfi->pixmap_surface = cairo_xlib_surface_create_for_bitmap(
|
||||||
|
disp, xfi->pixmap, ScreenOfDisplay(disp, widgetscr),
|
||||||
|
xfi->pixwidth, xfi->pixheight);
|
||||||
gcvals.foreground = WhitePixel(disp, widgetscr);
|
gcvals.foreground = WhitePixel(disp, widgetscr);
|
||||||
gcvals.background = BlackPixel(disp, widgetscr);
|
gcvals.background = BlackPixel(disp, widgetscr);
|
||||||
gcvals.font = xfi->xfs->fid;
|
gcvals.font = xfi->xfs->fid;
|
||||||
@ -705,31 +688,6 @@ static void x11font_cairo_setup(
|
|||||||
static void x11font_cairo_cache_glyph(
|
static void x11font_cairo_cache_glyph(
|
||||||
Display *disp, x11font_individual *xfi, int glyphindex)
|
Display *disp, x11font_individual *xfi, int glyphindex)
|
||||||
{
|
{
|
||||||
XImage *image;
|
|
||||||
int x, y;
|
|
||||||
unsigned char *bitmap;
|
|
||||||
const XCharStruct *xcs = x11_char_struct(xfi->xfs, glyphindex >> 8,
|
|
||||||
glyphindex & 0xFF);
|
|
||||||
|
|
||||||
bitmap = snewn(xfi->allsize, unsigned char);
|
|
||||||
memset(bitmap, 0, xfi->allsize);
|
|
||||||
|
|
||||||
image = XGetImage(disp, xfi->pixmap, 0, 0,
|
|
||||||
xfi->pixwidth, xfi->pixheight, AllPlanes, XYPixmap);
|
|
||||||
for (y = xfi->pixoriginy - xcs->ascent;
|
|
||||||
y < xfi->pixoriginy + xcs->descent; y++) {
|
|
||||||
for (x = xfi->pixoriginx + xcs->lbearing;
|
|
||||||
x < xfi->pixoriginx + xcs->rbearing; x++) {
|
|
||||||
unsigned long pixel = XGetPixel(image, x, y);
|
|
||||||
if (pixel) {
|
|
||||||
int byteindex = y * xfi->rowsize + x/8;
|
|
||||||
int bitindex = (x & 7) ^ xfi->indexflip;
|
|
||||||
bitmap[byteindex] |= 1U << bitindex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XDestroyImage(image);
|
|
||||||
|
|
||||||
if (xfi->nglyphs <= glyphindex) {
|
if (xfi->nglyphs <= glyphindex) {
|
||||||
/* Round up to the next multiple of 256 on the general
|
/* Round up to the next multiple of 256 on the general
|
||||||
* principle that Unicode characters come in contiguous blocks
|
* principle that Unicode characters come in contiguous blocks
|
||||||
@ -741,13 +699,16 @@ static void x11font_cairo_cache_glyph(
|
|||||||
|
|
||||||
while (old_nglyphs < xfi->nglyphs) {
|
while (old_nglyphs < xfi->nglyphs) {
|
||||||
xfi->glyphcache[old_nglyphs].surface = NULL;
|
xfi->glyphcache[old_nglyphs].surface = NULL;
|
||||||
xfi->glyphcache[old_nglyphs].bitmap = NULL;
|
|
||||||
old_nglyphs++;
|
old_nglyphs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xfi->glyphcache[glyphindex].bitmap = bitmap;
|
cairo_surface_mark_dirty(xfi->pixmap_surface);
|
||||||
xfi->glyphcache[glyphindex].surface = cairo_image_surface_create_for_data(
|
xfi->glyphcache[glyphindex].surface = cairo_image_surface_create(
|
||||||
bitmap, CAIRO_FORMAT_A1, xfi->pixwidth, xfi->pixheight, xfi->rowsize);
|
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,
|
static void x11font_cairo_draw_glyph(unifont_drawctx *ctx,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user