summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2007-12-17 01:14:27 -0500
committerCarl Worth <cworth@cworth.org>2008-01-09 11:22:50 -0800
commit69549125feb24118ad35403a4be647f8bb692e86 (patch)
tree6425d3a3d08f1843cf082a202950486211c16388
parent8776061068fba967dbafb43fac3af7df90464cb8 (diff)
[cairo-xlib] Support scale fonts with glyphs of multiple formats (#13479)
We maintain three Xrender glyphsets per scaled font, one for each of A1, A8, and ARGB32. This is required to correctly support fonts with bitmaps for some glyphs but not all. (cherry picked from commit 805b668260c47e6d3d854361fcc53f12bd2a57e1)
-rw-r--r--src/cairo-xlib-surface.c179
1 files changed, 136 insertions, 43 deletions
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index e76bc92dc..298617fc7 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -1076,6 +1076,7 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
break;
case CAIRO_EXTEND_REFLECT:
case CAIRO_EXTEND_PAD:
+ default:
status = CAIRO_INT_STATUS_UNSUPPORTED;
}
if (status)
@@ -2428,11 +2429,22 @@ cairo_xlib_surface_get_height (cairo_surface_t *abstract_surface)
return surface->height;
}
-typedef struct _cairo_xlib_surface_font_private {
- Display *dpy;
+enum {
+ GLYPHSET_INDEX_ARGB32,
+ GLYPHSET_INDEX_A8,
+ GLYPHSET_INDEX_A1,
+ NUM_GLYPHSETS
+};
+
+typedef struct _cairo_xlib_font_glyphset_info {
GlyphSet glyphset;
cairo_format_t format;
XRenderPictFormat *xrender_format;
+} cairo_xlib_font_glyphset_info_t;
+
+typedef struct _cairo_xlib_surface_font_private {
+ Display *dpy;
+ cairo_xlib_font_glyphset_info_t glyphset_info[NUM_GLYPHSETS];
} cairo_xlib_surface_font_private_t;
static void
@@ -2450,17 +2462,23 @@ _cairo_xlib_surface_remove_scaled_font (Display *dpy,
CAIRO_MUTEX_UNLOCK (scaled_font->mutex);
if (font_private != NULL) {
- XRenderFreeGlyphSet (font_private->dpy, font_private->glyphset);
+ int i;
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
+ if (glyphset_info->glyphset) {
+ XRenderFreeGlyphSet (font_private->dpy, glyphset_info->glyphset);
+ }
+ }
free (font_private);
}
}
static cairo_status_t
_cairo_xlib_surface_font_init (Display *dpy,
- cairo_scaled_font_t *scaled_font,
- cairo_format_t format)
+ cairo_scaled_font_t *scaled_font)
{
cairo_xlib_surface_font_private_t *font_private;
+ int i;
font_private = malloc (sizeof (cairo_xlib_surface_font_private_t));
if (!font_private)
@@ -2475,9 +2493,18 @@ _cairo_xlib_surface_font_init (Display *dpy,
font_private->dpy = dpy;
- font_private->format = format;
- font_private->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(dpy, format);
- font_private->glyphset = XRenderCreateGlyphSet (dpy, font_private->xrender_format);
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
+ switch (i) {
+ case GLYPHSET_INDEX_ARGB32: glyphset_info->format = CAIRO_FORMAT_ARGB32; break;
+ case GLYPHSET_INDEX_A8: glyphset_info->format = CAIRO_FORMAT_A8; break;
+ case GLYPHSET_INDEX_A1: glyphset_info->format = CAIRO_FORMAT_A1; break;
+ default: ASSERT_NOT_REACHED; break;
+ }
+ glyphset_info->xrender_format = NULL;
+ glyphset_info->glyphset = None;
+ }
+
scaled_font->surface_private = font_private;
scaled_font->surface_backend = &cairo_xlib_surface_backend;
@@ -2496,10 +2523,19 @@ _cairo_xlib_surface_scaled_font_fini (cairo_scaled_font_t *scaled_font)
display = _cairo_xlib_display_get (font_private->dpy);
if (display != NULL) {
- cairo_status_t status = _cairo_xlib_display_queue_resource (display,
- XRenderFreeGlyphSet,
- font_private->glyphset);
- (void) status; /* XXX cannot propagate failure */
+ int i;
+
+ for (i = 0; i < NUM_GLYPHSETS; i++) {
+ cairo_xlib_font_glyphset_info_t *glyphset_info = &font_private->glyphset_info[i];
+ if (glyphset_info->glyphset) {
+ cairo_status_t status;
+ status = _cairo_xlib_display_queue_resource (display,
+ XRenderFreeGlyphSet,
+ glyphset_info->glyphset);
+ (void) status; /* XXX cannot propagate failure */
+ }
+ }
+
_cairo_xlib_display_destroy (display);
}
@@ -2518,6 +2554,19 @@ static void _cairo_xlib_render_free_glyphs (Display *dpy, struct _cairo_xlib_ren
&arg->glyph_index, 1);
}
+static cairo_xlib_font_glyphset_info_t *
+_cairo_xlib_scaled_glyph_get_glyphset_info (cairo_scaled_glyph_t *scaled_glyph)
+{
+ return scaled_glyph->surface_private;
+}
+
+static void
+_cairo_xlib_scaled_glyph_set_glyphset_info (cairo_scaled_glyph_t *scaled_glyph,
+ cairo_xlib_font_glyphset_info_t *glyphset_info)
+{
+ scaled_glyph->surface_private = glyphset_info;
+}
+
static void
_cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
cairo_scaled_font_t *scaled_font)
@@ -2530,7 +2579,7 @@ _cairo_xlib_surface_scaled_glyph_fini (cairo_scaled_glyph_t *scaled_glyph,
struct _cairo_xlib_render_free_glyphs *arg = malloc (sizeof (*arg));
if (arg != NULL) {
cairo_status_t status;
- arg->glyphset = font_private->glyphset;
+ arg->glyphset = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph)->glyphset;
arg->glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
status = _cairo_xlib_display_queue_work (display,
(cairo_xlib_notify_func) _cairo_xlib_render_free_glyphs,
@@ -2556,6 +2605,32 @@ _native_byte_order_lsb (void)
return *((char *) &x) == 1;
}
+static cairo_xlib_font_glyphset_info_t *
+_cairo_xlib_scaled_font_get_glyphset_info_for_format (cairo_scaled_font_t *scaled_font,
+ cairo_format_t format)
+{
+ cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
+ cairo_xlib_font_glyphset_info_t *glyphset_info;
+ int glyphset_index;
+
+ switch (format) {
+ default:
+ case CAIRO_FORMAT_RGB24:
+ case CAIRO_FORMAT_ARGB32: glyphset_index = GLYPHSET_INDEX_ARGB32; break;
+ case CAIRO_FORMAT_A8: glyphset_index = GLYPHSET_INDEX_A8; break;
+ case CAIRO_FORMAT_A1: glyphset_index = GLYPHSET_INDEX_A1; break;
+ }
+
+ glyphset_info = &font_private->glyphset_info[glyphset_index];
+
+ if (glyphset_info->glyphset == None) {
+ glyphset_info->xrender_format = _CAIRO_FORMAT_TO_XRENDER_FORMAT(font_private->dpy, glyphset_info->format);
+ glyphset_info->glyphset = XRenderCreateGlyphSet (font_private->dpy, glyphset_info->xrender_format);
+ }
+
+ return glyphset_info;
+}
+
static cairo_status_t
_cairo_xlib_surface_add_glyph (Display *dpy,
cairo_scaled_font_t *scaled_font,
@@ -2569,6 +2644,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
cairo_scaled_glyph_t *scaled_glyph = *pscaled_glyph;
cairo_image_surface_t *glyph_surface = scaled_glyph->surface;
cairo_bool_t already_had_glyph_surface;
+ cairo_xlib_font_glyphset_info_t *glyphset_info;
if (!glyph_surface) {
@@ -2588,13 +2664,15 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
}
if (scaled_font->surface_private == NULL) {
- status = _cairo_xlib_surface_font_init (dpy, scaled_font,
- glyph_surface->format);
+ status = _cairo_xlib_surface_font_init (dpy, scaled_font);
if (status)
return status;
}
font_private = scaled_font->surface_private;
+ glyphset_info = _cairo_xlib_scaled_font_get_glyphset_info_for_format (scaled_font,
+ glyph_surface->format);
+
/* If the glyph surface has zero height or width, we create
* a clear 1x1 surface, to avoid various X server bugs.
*/
@@ -2602,7 +2680,7 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
cairo_t *cr;
cairo_surface_t *tmp_surface;
- tmp_surface = cairo_image_surface_create (font_private->format, 1, 1);
+ tmp_surface = cairo_image_surface_create (glyphset_info->format, 1, 1);
cr = cairo_create (tmp_surface);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_paint (cr);
@@ -2624,11 +2702,11 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
* create a temporary surface for the glyph image with the font's
* format.
*/
- if (glyph_surface->format != font_private->format) {
+ if (glyph_surface->format != glyphset_info->format) {
cairo_t *cr;
cairo_surface_t *tmp_surface;
- tmp_surface = cairo_image_surface_create (font_private->format,
+ tmp_surface = cairo_image_surface_create (glyphset_info->format,
glyph_surface->width,
glyph_surface->height);
tmp_surface->device_transform = glyph_surface->base.device_transform;
@@ -2760,11 +2838,13 @@ _cairo_xlib_surface_add_glyph (Display *dpy,
glyph_index = _cairo_scaled_glyph_index (scaled_glyph);
- XRenderAddGlyphs (dpy, font_private->glyphset,
+ XRenderAddGlyphs (dpy, glyphset_info->glyphset,
&glyph_index, &(glyph_info), 1,
(char *) data,
glyph_surface->stride * glyph_surface->height);
+ _cairo_xlib_scaled_glyph_set_glyphset_info (scaled_glyph, glyphset_info);
+
if (data != glyph_surface->data)
free (data);
@@ -2814,6 +2894,9 @@ typedef struct {
} p;
} cairo_xlib_glyph_t;
+/* compile-time assert that cairo_xlib_glyph_t is the same size as cairo_glyph_t */
+typedef int cairo_xlib_glyph_t_size_assertion [sizeof (cairo_xlib_glyph_t) == sizeof (cairo_glyph_t) ? 1 : -1];
+
#define GLYPH_INDEX_SKIP ((unsigned long) -1)
#define STACK_ELTS_LEN ((int) (CAIRO_STACK_BUFFER_SIZE / sizeof (XGlyphElt8)))
@@ -2821,12 +2904,14 @@ static cairo_status_t
_cairo_xlib_surface_emit_glyphs_chunk (cairo_xlib_surface_t *dst,
cairo_xlib_glyph_t *glyphs,
int num_glyphs,
- int width,
- int num_elts,
cairo_scaled_font_t *scaled_font,
cairo_operator_t op,
cairo_xlib_surface_t *src,
- cairo_surface_attributes_t *attributes)
+ cairo_surface_attributes_t *attributes,
+ /* info for this chunk */
+ int num_elts,
+ int width,
+ cairo_xlib_font_glyphset_info_t *glyphset_info)
{
/* Which XRenderCompositeText function to use */
cairo_xrender_composite_text_func_t composite_text_func;
@@ -2846,8 +2931,6 @@ _cairo_xlib_surface_emit_glyphs_chunk (cairo_xlib_surface_t *dst,
int n; /* Num output glyphs in current element */
int j; /* Num output glyphs so far */
- cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
-
switch (width) {
case 1:
/* don't cast the 8-variant, to catch possible mismatches */
@@ -2892,7 +2975,7 @@ _cairo_xlib_surface_emit_glyphs_chunk (cairo_xlib_surface_t *dst,
n = 0;
}
elts[nelt].chars = char8 + size * j;
- elts[nelt].glyphset = font_private->glyphset;
+ elts[nelt].glyphset = glyphset_info->glyphset;
elts[nelt].xOff = glyphs[i].p.i.x;
elts[nelt].yOff = glyphs[i].p.i.y;
}
@@ -2918,7 +3001,7 @@ _cairo_xlib_surface_emit_glyphs_chunk (cairo_xlib_surface_t *dst,
_render_operator (op),
src->src_picture,
dst->dst_picture,
- font_private->xrender_format,
+ glyphset_info->xrender_format,
attributes->x_offset + elts[0].xOff,
attributes->y_offset + elts[0].yOff,
elts[0].xOff, elts[0].yOff,
@@ -2945,6 +3028,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
cairo_status_t status = CAIRO_STATUS_SUCCESS;
cairo_scaled_glyph_t *scaled_glyph;
cairo_fixed_t x = 0, y = 0;
+ cairo_xlib_font_glyphset_info_t *glyphset_info = NULL, *this_glyphset_info;
unsigned long max_index = 0;
int width = 1;
@@ -2995,6 +3079,19 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
continue;
}
+ /* Send unsent glyphs to the server */
+ if (scaled_glyph->surface_private == NULL) {
+ status = _cairo_xlib_surface_add_glyph (dst->dpy,
+ scaled_font,
+ &scaled_glyph);
+ if (status)
+ return status;
+ }
+
+ this_glyphset_info = _cairo_xlib_scaled_glyph_get_glyphset_info (scaled_glyph);
+ if (!glyphset_info)
+ glyphset_info = this_glyphset_info;
+
old_width = width;
/* Update max glyph index */
@@ -3010,11 +3107,17 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
/* If we will pass the max request size by adding this glyph,
* flush current glyphs. Note that we account for a
- * possible element being added below. */
- if (request_size + width > max_request_size - sz_xGlyphElt) {
+ * possible element being added below.
+ *
+ * Also flush if changing glyphsets, as Xrender limits one mask
+ * format per request, so we can either break up, or use a
+ * wide-enough mask format. We do the former.
+ */
+ if (request_size + width > max_request_size - sz_xGlyphElt ||
+ (this_glyphset_info != glyphset_info)) {
status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, i,
- old_width, num_elts,
- scaled_font, op, src, attributes);
+ scaled_font, op, src, attributes,
+ num_elts, old_width, glyphset_info);
if (status != CAIRO_STATUS_SUCCESS)
return status;
@@ -3027,7 +3130,7 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
num_elts = 0;
num_out_glyphs = 0;
x = y = 0;
-
+ glyphset_info = this_glyphset_info;
}
/* Convert absolute glyph position to relative-to-current-point
@@ -3042,16 +3145,6 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
request_size += sz_xGlyphElt;
}
- /* Send unsent glyphs to the server */
- if (scaled_glyph->surface_private == NULL) {
- status = _cairo_xlib_surface_add_glyph (dst->dpy,
- scaled_font,
- &scaled_glyph);
- if (status)
- return status;
- scaled_glyph->surface_private = (void *) 1;
- }
-
/* adjust current-position */
x = this_x + scaled_glyph->x_advance;
y = this_y + scaled_glyph->y_advance;
@@ -3062,8 +3155,8 @@ _cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
if (num_elts)
status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, num_glyphs,
- width, num_elts,
- scaled_font, op, src, attributes);
+ scaled_font, op, src, attributes,
+ num_elts, width, glyphset_info);
return status;
}