2491
#define N_STACK_BUF 1024
2493
static cairo_status_t
2494
_cairo_xlib_surface_show_glyphs8 (cairo_xlib_surface_t *dst,
2495
cairo_operator_t op,
2496
cairo_xlib_surface_t *src,
2497
int src_x_offset, int src_y_offset,
2498
const cairo_glyph_t *glyphs,
2500
cairo_scaled_font_t *scaled_font)
2502
cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
2503
XGlyphElt8 *elts = NULL;
2504
XGlyphElt8 stack_elts [N_STACK_BUF];
2507
char stack_chars [N_STACK_BUF];
2511
int lastX = 0, lastY = 0;
2513
/* Acquire arrays of suitable sizes. */
2514
if (num_glyphs < N_STACK_BUF) {
2516
chars = stack_chars;
2518
elts = malloc (num_glyphs * sizeof (XGlyphElt8) +
2519
num_glyphs * sizeof (unsigned char));
2521
return CAIRO_STATUS_NO_MEMORY;
2523
chars = (char *) (elts + num_glyphs);
2526
for (i = 0; i < num_glyphs; ++i) {
2527
chars[i] = glyphs[i].index;
2528
elts[i].chars = &(chars[i]);
2530
elts[i].glyphset = font_private->glyphset;
2531
thisX = (int) floor (glyphs[i].x + 0.5);
2532
thisY = (int) floor (glyphs[i].y + 0.5);
2533
elts[i].xOff = thisX - lastX;
2534
elts[i].yOff = thisY - lastY;
2539
XRenderCompositeText8 (dst->dpy,
2540
_render_operator (op),
2543
font_private->xrender_format,
2544
src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff,
2545
elts[0].xOff, elts[0].yOff,
2548
if (elts != stack_elts)
2551
return CAIRO_STATUS_SUCCESS;
2554
static cairo_status_t
2555
_cairo_xlib_surface_show_glyphs16 (cairo_xlib_surface_t *dst,
2556
cairo_operator_t op,
2557
cairo_xlib_surface_t *src,
2558
int src_x_offset, int src_y_offset,
2559
const cairo_glyph_t *glyphs,
2561
cairo_scaled_font_t *scaled_font)
2563
cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
2564
XGlyphElt16 *elts = NULL;
2565
XGlyphElt16 stack_elts [N_STACK_BUF];
2567
unsigned short *chars = NULL;
2568
unsigned short stack_chars [N_STACK_BUF];
2572
int lastX = 0, lastY = 0;
2574
/* Acquire arrays of suitable sizes. */
2575
if (num_glyphs < N_STACK_BUF) {
2577
chars = stack_chars;
2579
elts = malloc (num_glyphs * sizeof (XGlyphElt16) +
2580
num_glyphs * sizeof (unsigned short));
2582
return CAIRO_STATUS_NO_MEMORY;
2584
chars = (unsigned short *) (elts + num_glyphs);
2587
for (i = 0; i < num_glyphs; ++i) {
2588
chars[i] = glyphs[i].index;
2589
elts[i].chars = &(chars[i]);
2591
elts[i].glyphset = font_private->glyphset;
2592
thisX = (int) floor (glyphs[i].x + 0.5);
2593
thisY = (int) floor (glyphs[i].y + 0.5);
2594
elts[i].xOff = thisX - lastX;
2595
elts[i].yOff = thisY - lastY;
2600
XRenderCompositeText16 (dst->dpy,
2601
_render_operator (op),
2604
font_private->xrender_format,
2605
src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff,
2606
elts[0].xOff, elts[0].yOff,
2609
if (elts != stack_elts)
2612
return CAIRO_STATUS_SUCCESS;
2615
static cairo_status_t
2616
_cairo_xlib_surface_show_glyphs32 (cairo_xlib_surface_t *dst,
2617
cairo_operator_t op,
2618
cairo_xlib_surface_t *src,
2619
int src_x_offset, int src_y_offset,
2620
const cairo_glyph_t *glyphs,
2622
cairo_scaled_font_t *scaled_font)
2624
cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
2625
XGlyphElt32 *elts = NULL;
2626
XGlyphElt32 stack_elts [N_STACK_BUF];
2628
unsigned int *chars = NULL;
2629
unsigned int stack_chars [N_STACK_BUF];
2633
int lastX = 0, lastY = 0;
2635
/* Acquire arrays of suitable sizes. */
2636
if (num_glyphs < N_STACK_BUF) {
2638
chars = stack_chars;
2640
elts = malloc (num_glyphs * sizeof (XGlyphElt32) +
2641
num_glyphs * sizeof (unsigned int));
2643
return CAIRO_STATUS_NO_MEMORY;
2645
chars = (unsigned int *) (elts + num_glyphs);
2648
for (i = 0; i < num_glyphs; ++i) {
2649
chars[i] = glyphs[i].index;
2650
elts[i].chars = &(chars[i]);
2652
elts[i].glyphset = font_private->glyphset;
2653
thisX = (int) floor (glyphs[i].x + 0.5);
2654
thisY = (int) floor (glyphs[i].y + 0.5);
2655
elts[i].xOff = thisX - lastX;
2656
elts[i].yOff = thisY - lastY;
2661
XRenderCompositeText32 (dst->dpy,
2662
_render_operator (op),
2665
font_private->xrender_format,
2666
src_x_offset + elts[0].xOff, src_y_offset + elts[0].yOff,
2667
elts[0].xOff, elts[0].yOff,
2670
if (elts != stack_elts)
2673
return CAIRO_STATUS_SUCCESS;
2676
typedef cairo_status_t (*cairo_xlib_surface_show_glyphs_func_t)
2677
(cairo_xlib_surface_t *, cairo_operator_t, cairo_xlib_surface_t *, int, int,
2678
const cairo_glyph_t *, int, cairo_scaled_font_t *);
2528
typedef void (*cairo_xrender_composite_text_func_t)
2533
_Xconst XRenderPictFormat *maskFormat,
2538
_Xconst XGlyphElt8 *elts,
2541
/* Build a struct of the same size of cairo_glyph_t that can be used both as
2542
* an input glyph with double coordinates, and as "working" glyph with
2543
* integer from-current-point offsets. */
2545
unsigned long index;
2556
} cairo_xlib_glyph_t;
2558
#define GLYPH_INDEX_SKIP ((unsigned long) -1)
2559
#define STACK_ELTS_LEN ((int) (CAIRO_STACK_BUFFER_SIZE / sizeof (XGlyphElt8)))
2561
static cairo_status_t
2562
_cairo_xlib_surface_emit_glyphs_chunk (cairo_xlib_surface_t *dst,
2563
cairo_xlib_glyph_t *glyphs,
2567
cairo_scaled_font_t *scaled_font,
2568
cairo_operator_t op,
2569
cairo_xlib_surface_t *src,
2570
cairo_surface_attributes_t *attributes)
2572
/* Which XRenderCompositeText function to use */
2573
cairo_xrender_composite_text_func_t composite_text_func;
2576
/* Element buffer stuff */
2578
XGlyphElt8 stack_elts[STACK_ELTS_LEN];
2580
/* Reuse the input glyph array for output char generation */
2581
char *char8 = (char *) glyphs;
2582
unsigned short *char16 = (unsigned short *) glyphs;
2583
unsigned int *char32 = (unsigned int *) glyphs;
2586
int nelt; /* Element index */
2587
int n; /* Num output glyphs in current element */
2588
int j; /* Num output glyphs so far */
2590
cairo_xlib_surface_font_private_t *font_private = scaled_font->surface_private;
2594
/* don't cast the 8-variant, to catch possible mismatches */
2595
composite_text_func = XRenderCompositeText8;
2596
size = sizeof (char);
2599
composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText16;
2600
size = sizeof (unsigned short);
2604
composite_text_func = (cairo_xrender_composite_text_func_t) XRenderCompositeText32;
2605
size = sizeof (unsigned int);
2608
/* Allocate element array */
2609
if (num_elts <= STACK_ELTS_LEN) {
2612
elts = malloc (num_elts * sizeof (XGlyphElt8));
2614
return CAIRO_STATUS_NO_MEMORY;
2621
for (i = 0; i < num_glyphs; i++) {
2623
/* Skip glyphs marked so */
2624
if (glyphs[i].index == GLYPH_INDEX_SKIP)
2627
/* Start a new element for first output glyph, and for glyphs with
2628
* unexpected position */
2629
if (!j || glyphs[i].p.i.x || glyphs[i].p.i.y) {
2631
elts[nelt].nchars = n;
2635
elts[nelt].chars = char8 + size * j;
2636
elts[nelt].glyphset = font_private->glyphset;
2637
elts[nelt].xOff = glyphs[i].p.i.x;
2638
elts[nelt].yOff = glyphs[i].p.i.y;
2642
case 1: char8 [j] = (char) glyphs[i].index; break;
2643
case 2: char16[j] = (unsigned short) glyphs[i].index; break;
2645
case 4: char32[j] = (unsigned int) glyphs[i].index; break;
2653
elts[nelt].nchars = n;
2658
composite_text_func (dst->dpy,
2659
_render_operator (op),
2662
font_private->xrender_format,
2663
attributes->x_offset + elts[0].xOff,
2664
attributes->y_offset + elts[0].yOff,
2665
elts[0].xOff, elts[0].yOff,
2666
(XGlyphElt8 *) elts, nelt);
2668
if (elts != stack_elts)
2671
return CAIRO_STATUS_SUCCESS;
2674
#undef STACK_ELTS_LEN
2676
static cairo_status_t
2677
_cairo_xlib_surface_emit_glyphs (cairo_xlib_surface_t *dst,
2678
cairo_xlib_glyph_t *glyphs,
2680
cairo_scaled_font_t *scaled_font,
2681
cairo_operator_t op,
2682
cairo_xlib_surface_t *src,
2683
cairo_surface_attributes_t *attributes)
2686
cairo_status_t status = CAIRO_STATUS_SUCCESS;
2687
cairo_scaled_glyph_t *scaled_glyph;
2688
cairo_fixed_t x = 0, y = 0;
2690
unsigned long max_index = 0;
2693
int num_out_glyphs = 0;
2695
int max_request_size = XMaxRequestSize (dst->dpy)
2696
- MAX (sz_xRenderCompositeGlyphs8Req,
2697
MAX(sz_xRenderCompositeGlyphs16Req,
2698
sz_xRenderCompositeGlyphs32Req));
2699
int request_size = 0;
2701
_cairo_xlib_surface_ensure_dst_picture (dst);
2703
for (i = 0; i < num_glyphs; i++) {
2707
status = _cairo_scaled_glyph_lookup (scaled_font,
2709
CAIRO_SCALED_GLYPH_INFO_SURFACE |
2710
CAIRO_SCALED_GLYPH_INFO_METRICS,
2712
if (status != CAIRO_STATUS_SUCCESS)
2715
this_x = _cairo_lround (glyphs[i].p.d.x);
2716
this_y = _cairo_lround (glyphs[i].p.d.y);
2720
* We skip any initial size-zero glyphs to avoid an X server bug (present
2721
* in at least Xorg 7.1 without EXA) which stops rendering glyphs after
2722
* the first zero-size glyph. However, we don't skip all size-zero
2723
* glyphs, since that will force a new element at every space. We
2724
* skip initial size-zero glyphs and hope that it's enough. Since
2725
* Xft never exposed that bug, this assumption should be correct.
2727
* We also skip any glyphs that have troublesome coordinates. We want
2728
* to make sure that (glyph2.x - (glyph1.x + glyph1.width)) fits in
2729
* a signed 16bit integer, otherwise it will overflow in the render
2731
* To ensure this, we'll make sure that (glyph2.x - glyph1.x) fits in
2732
* a signed 15bit integer. The trivial option would be to allow
2733
* coordinates -8192..8192, but that's kinda dull. It probably will
2734
* take a decade or so to get monitors 8192x4096 or something. A
2735
* negative value of -8192 on the other hand, is absolutely useless.
2736
* Note that we do want to allow some negative positions. The glyph
2737
* may start off the screen but part of it make it to the screen.
2738
* Anyway, we will allow positions in the range -1024..15359. That
2739
* will buy us a few more years before this stops working.
2741
if ((!num_out_glyphs && !(scaled_glyph->surface->width && scaled_glyph->surface->height)) ||
2742
(((this_x+1024)|(this_y+1024))&~0x3fffu)) {
2743
glyphs[i].index = GLYPH_INDEX_SKIP;
2749
/* Update max glyph index */
2750
if (glyphs[i].index > max_index) {
2751
max_index = glyphs[i].index;
2752
if (max_index >= 65536)
2754
else if (max_index >= 256)
2756
if (width != old_width)
2757
request_size += (width - old_width) * num_out_glyphs;
2760
/* If we will pass the max request size by adding this glyph,
2761
* flush current glyphs. Note that we account for a
2762
* possible element being added below. */
2763
if (request_size + width > max_request_size - sz_xGlyphElt) {
2764
status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, i,
2765
old_width, num_elts,
2766
scaled_font, op, src, attributes);
2767
if (status != CAIRO_STATUS_SUCCESS)
2773
max_index = glyphs[i].index;
2774
width = max_index < 256 ? 1 : max_index < 65536 ? 2 : 4;
2782
/* Convert absolute glyph position to relative-to-current-point
2784
glyphs[i].p.i.x = this_x - x;
2785
glyphs[i].p.i.y = this_y - y;
2787
/* Start a new element for the first glyph, or for any glyph that
2788
* has unexpected position */
2789
if (!num_out_glyphs || glyphs[i].p.i.x || glyphs[i].p.i.y) {
2791
request_size += sz_xGlyphElt;
2794
/* Send unsent glyphs to the server */
2795
if (scaled_glyph->surface_private == NULL) {
2796
_cairo_xlib_surface_add_glyph (dst->dpy, scaled_font, scaled_glyph);
2797
scaled_glyph->surface_private = (void *) 1;
2800
/* adjust current-position */
2801
x = this_x + scaled_glyph->x_advance;
2802
y = this_y + scaled_glyph->y_advance;
2805
request_size += width;
2809
status = _cairo_xlib_surface_emit_glyphs_chunk (dst, glyphs, num_glyphs,
2811
scaled_font, op, src, attributes);
2816
#undef GLYPH_INDEX_SKIP
2680
2818
static cairo_int_status_t
2681
2819
_cairo_xlib_surface_show_glyphs (void *abstract_dst,
2682
2820
cairo_operator_t op,
2683
2821
cairo_pattern_t *src_pattern,
2684
const cairo_glyph_t *glyphs,
2822
cairo_glyph_t *glyphs,
2685
2823
int num_glyphs,
2686
2824
cairo_scaled_font_t *scaled_font)