Home | History | Annotate | Line # | Download | only in src
      1 /*
      2  * Copyright  2000 Keith Packard
      3  *
      4  * Permission to use, copy, modify, distribute, and sell this software and its
      5  * documentation for any purpose is hereby granted without fee, provided that
      6  * the above copyright notice appear in all copies and that both that
      7  * copyright notice and this permission notice appear in supporting
      8  * documentation, and that the name of Keith Packard not be used in
      9  * advertising or publicity pertaining to distribution of the software without
     10  * specific, written prior permission.  Keith Packard makes no
     11  * representations about the suitability of this software for any purpose.  It
     12  * is provided "as is" without express or implied warranty.
     13  *
     14  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
     16  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
     18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
     19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
     20  * PERFORMANCE OF THIS SOFTWARE.
     21  */
     22 
     23 #include "xftint.h"
     24 #include <stdint.h>
     25 
     26 #define NUM_LOCAL	1024
     27 #define NUM_ELT_LOCAL	128
     28 
     29 /*
     30  * Dispatch glyph drawing to the correct XRenderCompositeString function
     31  */
     32 static void
     33 _XftCompositeString (Display           *dpy,
     34                      int               op,
     35                      Picture           src,
     36                      Picture           dst,
     37                      XRenderPictFormat *format,
     38                      GlyphSet          glyphset,
     39                      int               srcx,
     40                      int               srcy,
     41                      int               dstx,
     42                      int               dsty,
     43                      int               charwidth,
     44                      unsigned int      *chars,
     45                      int               nchars)
     46 {
     47     if (nchars == 0)
     48         return;
     49 
     50     switch (charwidth) {
     51     case 1:
     52     default:
     53 	XRenderCompositeString8 (dpy, op,
     54 				 src, dst, format, glyphset,
     55 				 srcx, srcy, dstx, dsty, (char*)chars, nchars);
     56 	break;
     57     case 2:
     58 	XRenderCompositeString16(dpy, op,
     59 				 src, dst, format, glyphset,
     60 				 srcx, srcy, dstx, dsty, (unsigned short*)chars, nchars);
     61 	break;
     62     case 4:
     63 	XRenderCompositeString32(dpy, op,
     64 				 src, dst, format, glyphset,
     65 				 srcx, srcy, dstx, dsty, (unsigned int*)chars, nchars);
     66 	break;
     67     }
     68 }
     69 
     70 /*
     71  * Use the Render extension to draw the glyphs
     72  */
     73 
     74 _X_EXPORT void
     75 XftGlyphRender (Display		*dpy,
     76 		int		op,
     77 		Picture		src,
     78 		XftFont		*pub,
     79 		Picture		dst,
     80 		int		srcx,
     81 		int		srcy,
     82 		int		x,
     83 		int		y,
     84 		_Xconst FT_UInt	*glyphs,
     85 		int		nglyphs)
     86 {
     87     XftFontInt	    *font = (XftFontInt *) pub;
     88     int		    i, j;
     89     FT_UInt	    missing[XFT_NMISSING];
     90     int		    nmissing;
     91     FT_UInt	    g, max;
     92     int		    width;
     93     int		    dstx, dsty;
     94     Glyph	    wire;
     95     XftGlyph*       glyph;
     96     char	    *char8;
     97     unsigned short  *char16;
     98     unsigned int    *char32;
     99     unsigned int    char_local[NUM_LOCAL];
    100     unsigned int    *chars;
    101     FcBool	    glyphs_loaded;
    102     size_t          size;
    103     size_t          needed;
    104 
    105     if (!font->format)
    106 	return;
    107 
    108     /*
    109      * Load missing glyphs
    110      */
    111     nmissing = 0;
    112     max = 0;
    113     glyphs_loaded = FcFalse;
    114     for (i = 0; i < nglyphs; i++)
    115     {
    116 	g = glyphs[i];
    117 	if (g > max)
    118 	    max = g;
    119 	if (XftFontCheckGlyph (dpy, pub, FcTrue, g, missing, &nmissing))
    120 	    glyphs_loaded = FcTrue;
    121     }
    122     if (nmissing)
    123 	XftFontLoadGlyphs (dpy, pub, FcTrue, missing, nmissing);
    124 
    125     if (!font->glyphset)
    126 	goto bail1;
    127     if (max < 0x100)
    128     {
    129 	width = 1;
    130 	size = sizeof (char);
    131     }
    132     else if (max < 0x10000)
    133     {
    134 	width = 2;
    135 	size = sizeof (unsigned short);
    136     }
    137     else
    138     {
    139 	width = 4;
    140 	size = sizeof (unsigned int);
    141     }
    142     chars = char_local;
    143     if ((size_t)nglyphs > SIZE_MAX / size)
    144 	goto bail1;
    145     needed = (size_t)nglyphs * size;
    146     if (needed > sizeof (char_local))
    147     {
    148 	chars = malloc (needed);
    149 	if (!chars)
    150 	    goto bail1;
    151     }
    152     dstx = x;
    153     dsty = y;
    154     char8 = (char *) chars;
    155     char16 = (unsigned short *) chars;
    156     char32 = (unsigned int *) chars;
    157     for (i = 0, j = 0; i < nglyphs; i++)
    158     {
    159 	wire = (Glyph) glyphs[i];
    160 	if (wire >= (Glyph) font->num_glyphs || !font->glyphs[wire])
    161 	    wire = 0;
    162         glyph = font->glyphs[wire];
    163 	if (glyph == NULL)
    164 	    continue;
    165 	if (glyph->picture)
    166 	{
    167 	    _XftCompositeString(dpy, op, src, dst, font->format, font->glyphset, srcx, srcy, x, y, width, chars, j);
    168 	    XRenderComposite(dpy, PictOpOver, glyph->picture, None, dst, 0, 0, 0, 0, dstx - glyph->metrics.x, dsty - glyph->metrics.y, glyph->metrics.width, glyph->metrics.height);
    169 	    dstx += glyph->metrics.xOff;
    170 	    dsty += glyph->metrics.yOff;
    171 	    x = dstx;
    172 	    y = dsty;
    173 	    j = 0;
    174 	}
    175 	else
    176 	{
    177 	    switch (width) {
    178 	    case 1: char8[j] = (char) wire; break;
    179 	    case 2: char16[j] = (unsigned short) wire; break;
    180 	    case 4: char32[j] = (unsigned int) wire; break;
    181 	    }
    182 	    dstx += glyph->metrics.xOff;
    183 	    dsty += glyph->metrics.yOff;
    184 	    ++j;
    185 	}
    186     }
    187     _XftCompositeString(dpy, op, src, dst, font->format, font->glyphset,
    188                         srcx, srcy, x, y, width, chars, j);
    189     if (chars != char_local)
    190 	free (chars);
    191 bail1:
    192     if (glyphs_loaded)
    193 	_XftFontManageMemory (dpy, pub);
    194 }
    195 
    196 /*
    197  * Dispatch glyph drawing to the correct XRenderCompositeText function
    198  */
    199 static void
    200 _XftCompositeText (Display           *dpy,
    201                    int               op,
    202                    Picture           src,
    203                    Picture           dst,
    204                    XRenderPictFormat *format,
    205                    int               srcx,
    206                    int               srcy,
    207                    int               dstx,
    208                    int               dsty,
    209                    int               eltwidth,
    210                    XGlyphElt8        *elts,
    211                    int               nelt)
    212 {
    213     if (nelt == 0)
    214         return;
    215 
    216     switch (eltwidth) {
    217     case 1:
    218     default:
    219 	XRenderCompositeText8 (dpy, op,
    220 			       src, dst, format,
    221 			       srcx, srcy, dstx, dsty,
    222 	                       (XGlyphElt8*)elts, nelt);
    223 	break;
    224     case 2:
    225 	XRenderCompositeText16(dpy, op,
    226 			       src, dst, format,
    227 			       srcx, srcy, dstx, dsty,
    228 	                       (XGlyphElt16*)elts, nelt);
    229 	break;
    230     case 4:
    231 	XRenderCompositeText32(dpy, op,
    232 			       src, dst, format,
    233 			       srcx, srcy, dstx, dsty,
    234 	                       (XGlyphElt32*)elts, nelt);
    235 	break;
    236     }
    237 }
    238 
    239 _X_EXPORT void
    240 XftGlyphSpecRender (Display		    *dpy,
    241 		    int			    op,
    242 		    Picture		    src,
    243 		    XftFont		    *pub,
    244 		    Picture		    dst,
    245 		    int			    srcx,
    246 		    int			    srcy,
    247 		    _Xconst XftGlyphSpec    *glyphs,
    248 		    int			    nglyphs)
    249 {
    250     XftFontInt	    *font = (XftFontInt *) pub;
    251     int		    i, j;
    252     FT_UInt	    missing[XFT_NMISSING];
    253     int		    nmissing;
    254     int		    n;
    255     FT_UInt	    g;
    256     XftGlyph	    *glyph;
    257     FT_UInt	    max;
    258     int		    size, width;
    259     char	    *char8;
    260     unsigned short  *char16;
    261     unsigned int    *char32;
    262     unsigned int    char_local[NUM_LOCAL];
    263     unsigned int    *chars;
    264     XGlyphElt8	    *elts;
    265     XGlyphElt8	    elts_local[NUM_ELT_LOCAL];
    266     FcBool	    glyphs_loaded;
    267     int		    nelt;
    268     int		    x, y;
    269 
    270     if (!font->format)
    271 	return;
    272     if (!nglyphs)
    273 	return;
    274 
    275     /*
    276      * Load missing glyphs
    277      */
    278     max = 0;
    279     nmissing = 0;
    280     glyphs_loaded = FcFalse;
    281     g = glyphs[0].glyph;
    282     for (i = 0; i < nglyphs; i++)
    283     {
    284 	g = glyphs[i].glyph;
    285 	if (g > max)
    286 	    max = g;
    287 	if (XftFontCheckGlyph (dpy, pub, FcTrue, g, missing, &nmissing))
    288 	    glyphs_loaded = FcTrue;
    289     }
    290     if (nmissing)
    291 	XftFontLoadGlyphs (dpy, pub, FcTrue, missing, nmissing);
    292 
    293     if (!font->glyphset)
    294 	goto bail1;
    295 
    296     /*
    297      * See what encoding size is needed
    298      */
    299     if (max < 0x100)
    300     {
    301 	size = sizeof (char);
    302 	width = 1;
    303     }
    304     else if (max < 0x10000)
    305     {
    306 	size = sizeof (unsigned short);
    307 	width = 2;
    308     }
    309     else
    310     {
    311 	size = sizeof (unsigned int);
    312 	width = 4;
    313     }
    314     chars = char_local;
    315     if (nglyphs * size > NUM_LOCAL)
    316     {
    317 	chars = malloc ((size_t)(nglyphs * size));
    318 	if (!chars)
    319 	    goto bail1;
    320     }
    321     char8 = (char *) chars;
    322     char16 = (unsigned short *) chars;
    323     char32 = (unsigned int *) chars;
    324 
    325     /*
    326      * Compute the number of glyph elts needed
    327      */
    328     nelt = 1;
    329     for (i = 0; i < nglyphs; i++)
    330     {
    331 	g = glyphs[i].glyph;
    332 	/* Substitute default for non-existent glyphs */
    333 	if (g >= font->num_glyphs || !font->glyphs[g])
    334 	    g = 0;
    335 	if (font->glyphs[g])
    336 	     break;
    337     }
    338     if (i == nglyphs)
    339 	goto bail2;
    340     glyph = font->glyphs[g];
    341     x = glyphs[i].x + glyph->metrics.xOff;
    342     y = glyphs[i].y + glyph->metrics.yOff;
    343     while (++i < nglyphs)
    344     {
    345 	g = glyphs[i].glyph;
    346 	/* Substitute default for non-existent glyphs */
    347 	if (g >= font->num_glyphs || !font->glyphs[g])
    348 	    g = 0;
    349 	/*
    350 	 * check to see if the glyph is placed where it would
    351 	 * fall using the normal spacing and if it would render
    352 	 * as a XRender glyph
    353 	 */
    354 	if ((glyph = font->glyphs[g]) && !glyph->picture)
    355 	{
    356 	    if (x != glyphs[i].x || y != glyphs[i].y)
    357 	    {
    358 		x = glyphs[i].x;
    359 		y = glyphs[i].y;
    360 		++nelt;
    361 	    }
    362 	    x += glyph->metrics.xOff;
    363 	    y += glyph->metrics.yOff;
    364 	}
    365     }
    366 
    367     elts = elts_local;
    368     if (nelt > NUM_ELT_LOCAL)
    369     {
    370 	elts = AllocGlyphElt8Array (nelt);
    371 	if (!elts)
    372 	    goto bail2;
    373     }
    374 
    375     /*
    376      * Generate the list of glyph elts or render color glyphs
    377      */
    378     nelt = 0;
    379     x = y = 0;
    380     n = 0;
    381     j = 0;
    382     for (i = 0; i < nglyphs; i++)
    383     {
    384 	g = glyphs[i].glyph;
    385 	/* Substitute default for non-existent glyphs */
    386 	if (g >= font->num_glyphs || !font->glyphs[g])
    387 	    g = 0;
    388 	if ((glyph = font->glyphs[g]))
    389 	{
    390 	    if (glyph->picture)
    391 	    {
    392                 XRenderComposite(dpy, PictOpOver, glyph->picture, None,
    393                                  dst, 0, 0, 0, 0,
    394                                  glyphs[i].x - glyph->metrics.x,
    395                                  glyphs[i].y - glyph->metrics.y,
    396                                  glyph->metrics.width,
    397                                  glyph->metrics.height);
    398                 continue;
    399 	    }
    400 	    if (!i || x != glyphs[i].x || y != glyphs[i].y)
    401 	    {
    402 		if (n)
    403 		{
    404 		    elts[nelt].nchars = n;
    405 		    nelt++;
    406 		}
    407 		elts[nelt].glyphset = font->glyphset;
    408 		elts[nelt].chars = char8 + size * j;
    409 		elts[nelt].xOff = glyphs[i].x - x;
    410 		elts[nelt].yOff = glyphs[i].y - y;
    411 		x = glyphs[i].x;
    412 		y = glyphs[i].y;
    413 		n = 0;
    414 	    }
    415 	    switch (width) {
    416 	    case 1: char8[j] = (char) g; break;
    417 	    case 2: char16[j] = (unsigned short) g; break;
    418 	    case 4: char32[j] = (unsigned int) g; break;
    419 	    }
    420 	    x += glyph->metrics.xOff;
    421 	    y += glyph->metrics.yOff;
    422 	    j++;
    423 	    n++;
    424 	}
    425     }
    426     if (n)
    427     {
    428 	elts[nelt].nchars = n;
    429 	nelt++;
    430     }
    431     _XftCompositeText(dpy, op, src, dst, font->format,
    432 		      srcx, srcy, glyphs[0].x, glyphs[0].y,
    433 		      width, elts, nelt);
    434 
    435     if (elts != elts_local)
    436 	free (elts);
    437 bail2:
    438     if (chars != char_local)
    439 	free (chars);
    440 bail1:
    441     if (glyphs_loaded)
    442 	_XftFontManageMemory (dpy, pub);
    443 }
    444 
    445 _X_EXPORT void
    446 XftCharSpecRender (Display		*dpy,
    447 		   int			op,
    448 		   Picture		src,
    449 		   XftFont		*pub,
    450 		   Picture		dst,
    451 		   int			srcx,
    452 		   int			srcy,
    453 		   _Xconst XftCharSpec	*chars,
    454 		   int			len)
    455 {
    456     XftGlyphSpec    *glyphs, glyphs_local[NUM_LOCAL];
    457     int		    i;
    458 
    459     if (len <= 0)
    460 	return;
    461 
    462     if (len <= NUM_LOCAL)
    463 	glyphs = glyphs_local;
    464     else
    465     {
    466 	glyphs = AllocGlyphSpecArray (len);
    467 	if (!glyphs)
    468 	    return;
    469     }
    470     for (i = 0; i < len; i++)
    471     {
    472 	glyphs[i].glyph = XftCharIndex(dpy, pub, chars[i].ucs4);
    473 	glyphs[i].x = chars[i].x;
    474 	glyphs[i].y = chars[i].y;
    475     }
    476 
    477     XftGlyphSpecRender (dpy, op, src, pub, dst, srcx, srcy, glyphs, len);
    478 
    479     if (glyphs != glyphs_local)
    480 	free (glyphs);
    481 }
    482 
    483 /*
    484  * Choose which format to draw text in when drawing with fonts
    485  * of different formats.  The trick is that ARGB formats aren't
    486  * compatible with A formats as PictOpAdd does the wrong thing, so
    487  * fall back to an A format when presented with an ARGB and A format
    488  */
    489 
    490 #define XftIsARGBFormat(a)  ((a)->depth == 32)
    491 
    492 static XRenderPictFormat *
    493 XftPreferFormat (Display *dpy, XRenderPictFormat *a, XRenderPictFormat *b)
    494 {
    495     XRenderPictFormat	*prefer = NULL;
    496 
    497     if (a == b)
    498 	prefer = a;
    499     else if (XftIsARGBFormat(a) != XftIsARGBFormat(b))
    500 	prefer = XRenderFindStandardFormat (dpy, PictStandardA8);
    501     else if (a->depth > b->depth)
    502 	prefer = a;
    503     else
    504 	prefer = b;
    505     return prefer;
    506 }
    507 
    508 _X_EXPORT void
    509 XftGlyphFontSpecRender (Display			    *dpy,
    510 			int			    op,
    511 			Picture			    src,
    512 			Picture			    dst,
    513 			int			    srcx,
    514 			int			    srcy,
    515 			_Xconst XftGlyphFontSpec    *glyphs,
    516 			int			    nglyphs)
    517 {
    518     int		    i, j;
    519     XftFont	    *prevPublic;
    520     XftFontInt	    *firstFont;
    521     XRenderPictFormat	*format;
    522     FT_UInt	    missing[XFT_NMISSING];
    523     int		    nmissing;
    524     int		    n;
    525     FT_UInt	    g;
    526     XftGlyph	    *glyph;
    527     FT_UInt	    max;
    528     int		    size, width;
    529     char	    *char8;
    530     unsigned short  *char16;
    531     unsigned int    *char32;
    532     unsigned int    char_local[NUM_LOCAL];
    533     unsigned int    *chars;
    534     XGlyphElt8	    *elts;
    535     XGlyphElt8	    elts_local[NUM_ELT_LOCAL];
    536     FcBool	    glyphs_loaded;
    537     int		    nelt;
    538     int		    x, y;
    539 
    540     if (!nglyphs)
    541 	return;
    542 
    543     /*
    544      * Load missing glyphs.  Have to load them
    545      * one at a time in case the font changes
    546      */
    547     max = 0;
    548     glyphs_loaded = FcFalse;
    549     g = glyphs[0].glyph;
    550     for (i = 0; i < nglyphs; i++)
    551     {
    552 	XftFont	    *pub = glyphs[i].font;
    553 	XftFontInt  *font = (XftFontInt *) pub;
    554 	g = glyphs[i].glyph;
    555 	if (g > max)
    556 	    max = g;
    557 	nmissing = 0;
    558 	if (XftFontCheckGlyph (dpy, pub, FcTrue, g, missing, &nmissing))
    559 	    glyphs_loaded = FcTrue;
    560 	if (nmissing)
    561 	    XftFontLoadGlyphs (dpy, pub, FcTrue, missing, nmissing);
    562 	if (!font->format)
    563 	    goto bail1;
    564 	if (!font->glyphset)
    565 	    goto bail1;
    566     }
    567 
    568     /*
    569      * See what encoding size is needed
    570      */
    571     if (max < 0x100)
    572     {
    573 	size = sizeof (char);
    574 	width = 1;
    575     }
    576     else if (max < 0x10000)
    577     {
    578 	size = sizeof (unsigned short);
    579 	width = 2;
    580     }
    581     else
    582     {
    583 	size = sizeof (unsigned int);
    584 	width = 4;
    585     }
    586     chars = char_local;
    587     if (nglyphs * size > NUM_LOCAL)
    588     {
    589 	chars = malloc ((size_t)(nglyphs * size));
    590 	if (!chars)
    591 	    goto bail1;
    592     }
    593     char8 = (char *) chars;
    594     char16 = (unsigned short *) chars;
    595     char32 = (unsigned int *) chars;
    596 
    597     /*
    598      * Compute the number of glyph elts needed
    599      */
    600     nelt = 1;
    601     firstFont = NULL;
    602     for (i = 0; i < nglyphs; i++)
    603     {
    604 	XftFont	    *pub = glyphs[i].font;
    605 	XftFontInt  *font = (XftFontInt *) pub;
    606 	g = glyphs[i].glyph;
    607 	/* Substitute default for non-existent glyphs */
    608 	if (g >= font->num_glyphs || !font->glyphs[g])
    609 	    g = 0;
    610 	if (font->glyphs[g])
    611 	{
    612 	    firstFont = font;
    613 	    break;
    614 	}
    615     }
    616     if (i == nglyphs || !firstFont)
    617 	goto bail2;
    618     glyph = firstFont->glyphs[g];
    619     format = firstFont->format;
    620     x = glyphs[i].x + glyph->metrics.xOff;
    621     y = glyphs[i].y + glyph->metrics.yOff;
    622     prevPublic = NULL;
    623     while (++i < nglyphs)
    624     {
    625 	XftFont	    *pub = glyphs[i].font;
    626 	XftFontInt  *font = (XftFontInt *) pub;
    627 	g = glyphs[i].glyph;
    628 	/* Substitute default for non-existent glyphs */
    629 	if (g >= font->num_glyphs || !font->glyphs[g])
    630 	    g = 0;
    631 	/*
    632 	 * check to see if the glyph is placed where it would
    633 	 * fall using the normal spacing
    634 	 */
    635 	if ((glyph = font->glyphs[g]) && !glyph->picture)
    636 	{
    637 	    if (pub != prevPublic || x != glyphs[i].x || y != glyphs[i].y)
    638 	    {
    639 		prevPublic = pub;
    640 		if (font->format != format)
    641 		    format = XftPreferFormat (dpy, font->format, format);
    642 		x = glyphs[i].x;
    643 		y = glyphs[i].y;
    644 		++nelt;
    645 	    }
    646 	    x += glyph->metrics.xOff;
    647 	    y += glyph->metrics.yOff;
    648 	}
    649     }
    650 
    651     elts = elts_local;
    652     if (nelt > NUM_ELT_LOCAL)
    653     {
    654 	elts = AllocGlyphElt8Array (nelt);
    655 	if (!elts)
    656 	    goto bail2;
    657     }
    658 
    659     /*
    660      * Generate the list of glyph elts and render color glyphs
    661      */
    662     nelt = 0;
    663     x = y = 0;
    664     n = 0;
    665     j = 0;
    666     prevPublic = NULL;
    667     for (i = 0; i < nglyphs; i++)
    668     {
    669 	XftFont	    *pub = glyphs[i].font;
    670 	XftFontInt  *font = (XftFontInt *) pub;
    671 
    672 	g = glyphs[i].glyph;
    673 	/* Substitute default for non-existent glyphs */
    674 	if (g >= font->num_glyphs || !font->glyphs[g])
    675 	    g = 0;
    676 	if ((glyph = font->glyphs[g]))
    677 	{
    678 	    if (glyph->picture)
    679 	    {
    680                 XRenderComposite(dpy, PictOpOver, glyph->picture, None,
    681                                  dst, 0, 0, 0, 0,
    682                                  glyphs[i].x - glyph->metrics.x,
    683                                  glyphs[i].y - glyph->metrics.y,
    684                                  glyph->metrics.width,
    685                                  glyph->metrics.height);
    686                 continue;
    687 	    }
    688 	    if (!i || pub != prevPublic || x != glyphs[i].x || y != glyphs[i].y)
    689 	    {
    690 		if (n)
    691 		{
    692 		    elts[nelt].nchars = n;
    693 		    nelt++;
    694 		}
    695 		elts[nelt].glyphset = font->glyphset;
    696 		elts[nelt].chars = char8 + size * j;
    697 		elts[nelt].xOff = glyphs[i].x - x;
    698 		elts[nelt].yOff = glyphs[i].y - y;
    699 		prevPublic = pub;
    700 		x = glyphs[i].x;
    701 		y = glyphs[i].y;
    702 		n = 0;
    703 	    }
    704 	    switch (width) {
    705 	    case 1: char8[j] = (char) g; break;
    706 	    case 2: char16[j] = (unsigned short) g; break;
    707 	    case 4: char32[j] = (unsigned int) g; break;
    708 	    }
    709 	    x += glyph->metrics.xOff;
    710 	    y += glyph->metrics.yOff;
    711 	    j++;
    712 	    n++;
    713 	}
    714     }
    715     if (n)
    716     {
    717 	elts[nelt].nchars = n;
    718 	nelt++;
    719     }
    720     _XftCompositeText(dpy, op, src, dst, format,
    721 		      srcx, srcy, glyphs[0].x, glyphs[0].y,
    722 		      width, elts, nelt);
    723 
    724     if (elts != elts_local)
    725 	free (elts);
    726 bail2:
    727     if (chars != char_local)
    728 	free (chars);
    729 bail1:
    730     if (glyphs_loaded)
    731 	for (i = 0; i < nglyphs; i++)
    732 	    _XftFontManageMemory (dpy, glyphs[i].font);
    733 }
    734 
    735 _X_EXPORT void
    736 XftCharFontSpecRender (Display			*dpy,
    737 		       int			op,
    738 		       Picture			src,
    739 		       Picture			dst,
    740 		       int			srcx,
    741 		       int			srcy,
    742 		       _Xconst XftCharFontSpec	*chars,
    743 		       int			len)
    744 {
    745     XftGlyphFontSpec	*glyphs, glyphs_local[NUM_LOCAL];
    746     int			i;
    747 
    748     if (len <= 0)
    749 	return;
    750 
    751     if (len <= NUM_LOCAL)
    752 	glyphs = glyphs_local;
    753     else
    754     {
    755 	glyphs = AllocGlyphFontSpecArray (len);
    756 	if (!glyphs)
    757 	    return;
    758     }
    759     for (i = 0; i < len; i++)
    760     {
    761 	glyphs[i].font = chars[i].font;
    762 	glyphs[i].glyph = XftCharIndex(dpy, glyphs[i].font, chars[i].ucs4);
    763 	glyphs[i].x = chars[i].x;
    764 	glyphs[i].y = chars[i].y;
    765     }
    766 
    767     XftGlyphFontSpecRender (dpy, op, src, dst, srcx, srcy, glyphs, len);
    768     if (glyphs != glyphs_local)
    769 	free (glyphs);
    770 }
    771 
    772 _X_EXPORT void
    773 XftTextRender8 (Display		*dpy,
    774 		int		op,
    775 		Picture		src,
    776 		XftFont		*pub,
    777 		Picture		dst,
    778 		int		srcx,
    779 		int		srcy,
    780 		int		x,
    781 		int		y,
    782 		_Xconst FcChar8	*string,
    783 		int		len)
    784 {
    785     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
    786     int		    i;
    787 
    788     if (len <= 0)
    789 	return;
    790 
    791     if (len <= NUM_LOCAL)
    792 	glyphs = glyphs_local;
    793     else
    794     {
    795 	glyphs = AllocUIntArray (len);
    796 	if (!glyphs)
    797 	    return;
    798     }
    799     for (i = 0; i < len; i++)
    800 	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
    801     XftGlyphRender (dpy, op, src, pub, dst,
    802 		     srcx, srcy, x, y, glyphs, len);
    803     if (glyphs != glyphs_local)
    804 	free (glyphs);
    805 }
    806 
    807 _X_EXPORT void
    808 XftTextRender16 (Display	    *dpy,
    809 		 int		    op,
    810 		 Picture	    src,
    811 		 XftFont	    *pub,
    812 		 Picture	    dst,
    813 		 int		    srcx,
    814 		 int		    srcy,
    815 		 int		    x,
    816 		 int		    y,
    817 		 _Xconst FcChar16   *string,
    818 		 int		    len)
    819 {
    820     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
    821     int		    i;
    822 
    823     if (len <= 0)
    824 	return;
    825 
    826     if (len <= NUM_LOCAL)
    827 	glyphs = glyphs_local;
    828     else
    829     {
    830 	glyphs = AllocUIntArray (len);
    831 	if (!glyphs)
    832 	    return;
    833     }
    834     for (i = 0; i < len; i++)
    835 	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
    836     XftGlyphRender (dpy, op, src, pub, dst,
    837 		     srcx, srcy, x, y, glyphs, len);
    838     if (glyphs != glyphs_local)
    839 	free (glyphs);
    840 }
    841 
    842 _X_EXPORT void
    843 XftTextRender16BE (Display	    *dpy,
    844 		   int		    op,
    845 		   Picture	    src,
    846 		   XftFont	    *pub,
    847 		   Picture	    dst,
    848 		   int		    srcx,
    849 		   int		    srcy,
    850 		   int		    x,
    851 		   int		    y,
    852 		   _Xconst FcChar8  *string,
    853 		   int		    len)
    854 {
    855     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
    856     int		    i;
    857 
    858     if (len <= 0)
    859 	return;
    860 
    861     if (len <= NUM_LOCAL)
    862 	glyphs = glyphs_local;
    863     else
    864     {
    865 	glyphs = AllocUIntArray (len);
    866 	if (!glyphs)
    867 	    return;
    868     }
    869     for (i = 0; i < len; i++)
    870 	glyphs[i] = XftCharIndex (dpy, pub,
    871 				  (FcChar32)((string[i*2]<<8) | string[i*2+1]));
    872     XftGlyphRender (dpy, op, src, pub, dst,
    873 		     srcx, srcy, x, y, glyphs, len);
    874     if (glyphs != glyphs_local)
    875 	free (glyphs);
    876 }
    877 
    878 _X_EXPORT void
    879 XftTextRender16LE (Display	    *dpy,
    880 		   int		    op,
    881 		   Picture	    src,
    882 		   XftFont	    *pub,
    883 		   Picture	    dst,
    884 		   int		    srcx,
    885 		   int		    srcy,
    886 		   int		    x,
    887 		   int		    y,
    888 		   _Xconst FcChar8  *string,
    889 		   int		    len)
    890 {
    891     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
    892     int		    i;
    893 
    894     if (len <= 0)
    895 	return;
    896 
    897     if (len <= NUM_LOCAL)
    898 	glyphs = glyphs_local;
    899     else
    900     {
    901 	glyphs = AllocUIntArray (len);
    902 	if (!glyphs)
    903 	    return;
    904     }
    905     for (i = 0; i < len; i++)
    906 	glyphs[i] = XftCharIndex (dpy, pub,
    907 				  (FcChar32)(string[i*2] | (string[i*2+1]<<8)));
    908     XftGlyphRender (dpy, op, src, pub, dst,
    909 		     srcx, srcy, x, y, glyphs, len);
    910     if (glyphs != glyphs_local)
    911 	free (glyphs);
    912 }
    913 
    914 _X_EXPORT void
    915 XftTextRender32 (Display	    *dpy,
    916 		 int		    op,
    917 		 Picture	    src,
    918 		 XftFont	    *pub,
    919 		 Picture	    dst,
    920 		 int		    srcx,
    921 		 int		    srcy,
    922 		 int		    x,
    923 		 int		    y,
    924 		 _Xconst FcChar32   *string,
    925 		 int		    len)
    926 {
    927     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
    928     int		    i;
    929 
    930     if (len <= 0)
    931 	return;
    932 
    933     if (len <= NUM_LOCAL)
    934 	glyphs = glyphs_local;
    935     else
    936     {
    937 	glyphs = AllocUIntArray (len);
    938 	if (!glyphs)
    939 	    return;
    940     }
    941     for (i = 0; i < len; i++)
    942 	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
    943     XftGlyphRender (dpy, op, src, pub, dst,
    944 		     srcx, srcy, x, y, glyphs, len);
    945     if (glyphs != glyphs_local)
    946 	free (glyphs);
    947 }
    948 
    949 _X_EXPORT void
    950 XftTextRender32BE (Display	    *dpy,
    951 		   int		    op,
    952 		   Picture	    src,
    953 		   XftFont	    *pub,
    954 		   Picture	    dst,
    955 		   int		    srcx,
    956 		   int		    srcy,
    957 		   int		    x,
    958 		   int		    y,
    959 		   _Xconst FcChar8  *string,
    960 		   int		    len)
    961 {
    962     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
    963     int		    i;
    964 
    965     if (len <= 0)
    966 	return;
    967 
    968     if (len <= NUM_LOCAL)
    969 	glyphs = glyphs_local;
    970     else
    971     {
    972 	glyphs = AllocUIntArray (len);
    973 	if (!glyphs)
    974 	    return;
    975     }
    976     for (i = 0; i < len; i++)
    977 	glyphs[i] = XftCharIndex (dpy, pub,
    978 				  (FcChar32)((string[i*4] << 24) |
    979 					     (string[i*4+1] << 16) |
    980 					     (string[i*4+2] << 8) |
    981 					     (string[i*4+3])));
    982     XftGlyphRender (dpy, op, src, pub, dst,
    983 		     srcx, srcy, x, y, glyphs, len);
    984     if (glyphs != glyphs_local)
    985 	free (glyphs);
    986 }
    987 
    988 _X_EXPORT void
    989 XftTextRender32LE (Display	    *dpy,
    990 		   int		    op,
    991 		   Picture	    src,
    992 		   XftFont	    *pub,
    993 		   Picture	    dst,
    994 		   int		    srcx,
    995 		   int		    srcy,
    996 		   int		    x,
    997 		   int		    y,
    998 		   _Xconst FcChar8  *string,
    999 		   int		    len)
   1000 {
   1001     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
   1002     int		    i;
   1003 
   1004     if (len <= 0)
   1005 	return;
   1006 
   1007     if (len <= NUM_LOCAL)
   1008 	glyphs = glyphs_local;
   1009     else
   1010     {
   1011 	glyphs = AllocUIntArray (len);
   1012 	if (!glyphs)
   1013 	    return;
   1014     }
   1015     for (i = 0; i < len; i++)
   1016 	glyphs[i] = XftCharIndex (dpy, pub,
   1017 				  (FcChar32)((string[i*4]) |
   1018 					     (string[i*4+1] << 8) |
   1019 					     (string[i*4+2] << 16) |
   1020 					     (string[i*4+3] << 24)));
   1021     XftGlyphRender (dpy, op, src, pub, dst,
   1022 		     srcx, srcy, x, y, glyphs, len);
   1023     if (glyphs != glyphs_local)
   1024 	free (glyphs);
   1025 }
   1026 
   1027 _X_EXPORT void
   1028 XftTextRenderUtf8 (Display	    *dpy,
   1029 		   int		    op,
   1030 		   Picture	    src,
   1031 		   XftFont	    *pub,
   1032 		   Picture	    dst,
   1033 		   int		    srcx,
   1034 		   int		    srcy,
   1035 		   int		    x,
   1036 		   int		    y,
   1037 		   _Xconst FcChar8  *string,
   1038 		   int		    len)
   1039 {
   1040     FT_UInt	    *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
   1041     FcChar32	    ucs4;
   1042     int		    i;
   1043     int		    l;
   1044     int		    size;
   1045 
   1046     if (len <= 0)
   1047 	return;
   1048 
   1049     i = 0;
   1050     glyphs = glyphs_local;
   1051     size = NUM_LOCAL;
   1052     while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
   1053     {
   1054 	if (i == size)
   1055 	{
   1056 	    glyphs_new = AllocUIntArray (size * 2);
   1057 	    if (!glyphs_new)
   1058 	    {
   1059 		if (glyphs != glyphs_local)
   1060 		    free (glyphs);
   1061 		return;
   1062 	    }
   1063 	    memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt));
   1064 	    size *= 2;
   1065 	    if (glyphs != glyphs_local)
   1066 		free (glyphs);
   1067 	    glyphs = glyphs_new;
   1068 	}
   1069 	glyphs[i++] = XftCharIndex (dpy, pub, ucs4);
   1070 	string += l;
   1071 	len -= l;
   1072     }
   1073     XftGlyphRender (dpy, op, src, pub, dst,
   1074 		     srcx, srcy, x, y, glyphs, i);
   1075     if (glyphs != glyphs_local)
   1076 	free (glyphs);
   1077 }
   1078 
   1079 _X_EXPORT void
   1080 XftTextRenderUtf16 (Display	    *dpy,
   1081 		    int		    op _X_UNUSED,
   1082 		    Picture	    src,
   1083 		    XftFont	    *pub,
   1084 		    Picture	    dst,
   1085 		    int		    srcx,
   1086 		    int		    srcy,
   1087 		    int		    x,
   1088 		    int		    y,
   1089 		    _Xconst FcChar8 *string,
   1090 		    FcEndian	    endian,
   1091 		    int		    len)
   1092 {
   1093     FT_UInt	    *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
   1094     FcChar32	    ucs4;
   1095     int		    i;
   1096     int		    l;
   1097     int		    size;
   1098 
   1099     if (len <= 0)
   1100 	return;
   1101 
   1102     i = 0;
   1103     glyphs = glyphs_local;
   1104     size = NUM_LOCAL;
   1105     while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
   1106     {
   1107 	if (i == size)
   1108 	{
   1109 	    glyphs_new = AllocUIntArray (size * 2);
   1110 	    if (!glyphs_new)
   1111 	    {
   1112 		if (glyphs != glyphs_local)
   1113 		    free (glyphs);
   1114 		return;
   1115 	    }
   1116 	    memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt));
   1117 	    size *= 2;
   1118 	    if (glyphs != glyphs_local)
   1119 		free (glyphs);
   1120 	    glyphs = glyphs_new;
   1121 	}
   1122 	glyphs[i++] = XftCharIndex (dpy, pub, ucs4);
   1123 	string += l;
   1124 	len -= l;
   1125     }
   1126     XftGlyphRender (dpy, PictOpOver, src, pub, dst,
   1127 		     srcx, srcy, x, y, glyphs, i);
   1128     if (glyphs != glyphs_local)
   1129 	free (glyphs);
   1130 }
   1131