/* * Copyright © 2000 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include "xftint.h" #include #define NUM_LOCAL 1024 #define NUM_ELT_LOCAL 128 /* * Dispatch glyph drawing to the correct XRenderCompositeString function */ static void _XftCompositeString (Display *dpy, int op, Picture src, Picture dst, XRenderPictFormat *format, GlyphSet glyphset, int srcx, int srcy, int dstx, int dsty, int charwidth, unsigned int *chars, int nchars) { if (nchars == 0) return; switch (charwidth) { case 1: default: XRenderCompositeString8 (dpy, op, src, dst, format, glyphset, srcx, srcy, dstx, dsty, (char*)chars, nchars); break; case 2: XRenderCompositeString16(dpy, op, src, dst, format, glyphset, srcx, srcy, dstx, dsty, (unsigned short*)chars, nchars); break; case 4: XRenderCompositeString32(dpy, op, src, dst, format, glyphset, srcx, srcy, dstx, dsty, (unsigned int*)chars, nchars); break; } } /* * Use the Render extension to draw the glyphs */ _X_EXPORT void XftGlyphRender (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FT_UInt *glyphs, int nglyphs) { XftFontInt *font = (XftFontInt *) pub; int i, j; FT_UInt missing[XFT_NMISSING]; int nmissing; FT_UInt g, max; int width; int dstx, dsty; Glyph wire; XftGlyph* glyph; char *char8; unsigned short *char16; unsigned int *char32; unsigned int char_local[NUM_LOCAL]; unsigned int *chars; FcBool glyphs_loaded; size_t size; size_t needed; if (!font->format) return; /* * Load missing glyphs */ nmissing = 0; max = 0; glyphs_loaded = FcFalse; for (i = 0; i < nglyphs; i++) { g = glyphs[i]; if (g > max) max = g; if (XftFontCheckGlyph (dpy, pub, FcTrue, g, missing, &nmissing)) glyphs_loaded = FcTrue; } if (nmissing) XftFontLoadGlyphs (dpy, pub, FcTrue, missing, nmissing); if (!font->glyphset) goto bail1; if (max < 0x100) { width = 1; size = sizeof (char); } else if (max < 0x10000) { width = 2; size = sizeof (unsigned short); } else { width = 4; size = sizeof (unsigned int); } chars = char_local; if ((size_t)nglyphs > SIZE_MAX / size) goto bail1; needed = (size_t)nglyphs * size; if (needed > sizeof (char_local)) { chars = malloc (needed); if (!chars) goto bail1; } dstx = x; dsty = y; char8 = (char *) chars; char16 = (unsigned short *) chars; char32 = (unsigned int *) chars; for (i = 0, j = 0; i < nglyphs; i++) { wire = (Glyph) glyphs[i]; if (wire >= (Glyph) font->num_glyphs || !font->glyphs[wire]) wire = 0; glyph = font->glyphs[wire]; if (glyph == NULL) continue; if (glyph->picture) { _XftCompositeString(dpy, op, src, dst, font->format, font->glyphset, srcx, srcy, x, y, width, chars, j); 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); dstx += glyph->metrics.xOff; dsty += glyph->metrics.yOff; x = dstx; y = dsty; j = 0; } else { switch (width) { case 1: char8[j] = (char) wire; break; case 2: char16[j] = (unsigned short) wire; break; case 4: char32[j] = (unsigned int) wire; break; } dstx += glyph->metrics.xOff; dsty += glyph->metrics.yOff; ++j; } } _XftCompositeString(dpy, op, src, dst, font->format, font->glyphset, srcx, srcy, x, y, width, chars, j); if (chars != char_local) free (chars); bail1: if (glyphs_loaded) _XftFontManageMemory (dpy, pub); } /* * Dispatch glyph drawing to the correct XRenderCompositeText function */ static void _XftCompositeText (Display *dpy, int op, Picture src, Picture dst, XRenderPictFormat *format, int srcx, int srcy, int dstx, int dsty, int eltwidth, XGlyphElt8 *elts, int nelt) { if (nelt == 0) return; switch (eltwidth) { case 1: default: XRenderCompositeText8 (dpy, op, src, dst, format, srcx, srcy, dstx, dsty, (XGlyphElt8*)elts, nelt); break; case 2: XRenderCompositeText16(dpy, op, src, dst, format, srcx, srcy, dstx, dsty, (XGlyphElt16*)elts, nelt); break; case 4: XRenderCompositeText32(dpy, op, src, dst, format, srcx, srcy, dstx, dsty, (XGlyphElt32*)elts, nelt); break; } } _X_EXPORT void XftGlyphSpecRender (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, _Xconst XftGlyphSpec *glyphs, int nglyphs) { XftFontInt *font = (XftFontInt *) pub; int i, j; FT_UInt missing[XFT_NMISSING]; int nmissing; int n; FT_UInt g; XftGlyph *glyph; FT_UInt max; int size, width; char *char8; unsigned short *char16; unsigned int *char32; unsigned int char_local[NUM_LOCAL]; unsigned int *chars; XGlyphElt8 *elts; XGlyphElt8 elts_local[NUM_ELT_LOCAL]; FcBool glyphs_loaded; int nelt; int x, y; if (!font->format) return; if (!nglyphs) return; /* * Load missing glyphs */ max = 0; nmissing = 0; glyphs_loaded = FcFalse; g = glyphs[0].glyph; for (i = 0; i < nglyphs; i++) { g = glyphs[i].glyph; if (g > max) max = g; if (XftFontCheckGlyph (dpy, pub, FcTrue, g, missing, &nmissing)) glyphs_loaded = FcTrue; } if (nmissing) XftFontLoadGlyphs (dpy, pub, FcTrue, missing, nmissing); if (!font->glyphset) goto bail1; /* * See what encoding size is needed */ if (max < 0x100) { size = sizeof (char); width = 1; } else if (max < 0x10000) { size = sizeof (unsigned short); width = 2; } else { size = sizeof (unsigned int); width = 4; } chars = char_local; if (nglyphs * size > NUM_LOCAL) { chars = malloc ((size_t)(nglyphs * size)); if (!chars) goto bail1; } char8 = (char *) chars; char16 = (unsigned short *) chars; char32 = (unsigned int *) chars; /* * Compute the number of glyph elts needed */ nelt = 1; for (i = 0; i < nglyphs; i++) { g = glyphs[i].glyph; /* Substitute default for non-existent glyphs */ if (g >= font->num_glyphs || !font->glyphs[g]) g = 0; if (font->glyphs[g]) break; } if (i == nglyphs) goto bail2; glyph = font->glyphs[g]; x = glyphs[i].x + glyph->metrics.xOff; y = glyphs[i].y + glyph->metrics.yOff; while (++i < nglyphs) { g = glyphs[i].glyph; /* Substitute default for non-existent glyphs */ if (g >= font->num_glyphs || !font->glyphs[g]) g = 0; /* * check to see if the glyph is placed where it would * fall using the normal spacing and if it would render * as a XRender glyph */ if ((glyph = font->glyphs[g]) && !glyph->picture) { if (x != glyphs[i].x || y != glyphs[i].y) { x = glyphs[i].x; y = glyphs[i].y; ++nelt; } x += glyph->metrics.xOff; y += glyph->metrics.yOff; } } elts = elts_local; if (!font->info.color && nelt > NUM_ELT_LOCAL) { elts = AllocGlyphElt8Array (nelt); if (!elts) goto bail2; } /* * Generate the list of glyph elts or render color glyphs */ nelt = 0; x = y = 0; n = 0; j = 0; for (i = 0; i < nglyphs; i++) { g = glyphs[i].glyph; /* Substitute default for non-existent glyphs */ if (g >= font->num_glyphs || !font->glyphs[g]) g = 0; if ((glyph = font->glyphs[g])) { if (glyph->picture) { XRenderComposite(dpy, PictOpOver, glyph->picture, None, dst, 0, 0, 0, 0, glyphs[i].x - glyph->metrics.x, glyphs[i].y - glyph->metrics.y, glyph->metrics.width, glyph->metrics.height); continue; } if (!i || x != glyphs[i].x || y != glyphs[i].y) { if (n) { elts[nelt].nchars = n; nelt++; } elts[nelt].glyphset = font->glyphset; elts[nelt].chars = char8 + size * j; elts[nelt].xOff = glyphs[i].x - x; elts[nelt].yOff = glyphs[i].y - y; x = glyphs[i].x; y = glyphs[i].y; n = 0; } switch (width) { case 1: char8[j] = (char) g; break; case 2: char16[j] = (unsigned short) g; break; case 4: char32[j] = (unsigned int) g; break; } x += glyph->metrics.xOff; y += glyph->metrics.yOff; j++; n++; } } if (n) { elts[nelt].nchars = n; nelt++; } _XftCompositeText(dpy, op, src, dst, font->format, srcx, srcy, glyphs[0].x, glyphs[0].y, width, elts, nelt); if (elts != elts_local) free (elts); bail2: if (chars != char_local) free (chars); bail1: if (glyphs_loaded) _XftFontManageMemory (dpy, pub); } _X_EXPORT void XftCharSpecRender (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, _Xconst XftCharSpec *chars, int len) { XftGlyphSpec *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocGlyphSpecArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) { glyphs[i].glyph = XftCharIndex(dpy, pub, chars[i].ucs4); glyphs[i].x = chars[i].x; glyphs[i].y = chars[i].y; } XftGlyphSpecRender (dpy, op, src, pub, dst, srcx, srcy, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } /* * Choose which format to draw text in when drawing with fonts * of different formats. The trick is that ARGB formats aren't * compatible with A formats as PictOpAdd does the wrong thing, so * fall back to an A format when presented with an ARGB and A format */ #define XftIsARGBFormat(a) ((a)->depth == 32) static XRenderPictFormat * XftPreferFormat (Display *dpy, XRenderPictFormat *a, XRenderPictFormat *b) { XRenderPictFormat *prefer = NULL; if (a == b) prefer = a; else if (XftIsARGBFormat(a) != XftIsARGBFormat(b)) prefer = XRenderFindStandardFormat (dpy, PictStandardA8); else if (a->depth > b->depth) prefer = a; else prefer = b; return prefer; } _X_EXPORT void XftGlyphFontSpecRender (Display *dpy, int op, Picture src, Picture dst, int srcx, int srcy, _Xconst XftGlyphFontSpec *glyphs, int nglyphs) { int i, j; XftFont *prevPublic; XftFontInt *firstFont; XRenderPictFormat *format; FT_UInt missing[XFT_NMISSING]; int nmissing; int n; FT_UInt g; XftGlyph *glyph; FT_UInt max; int size, width; char *char8; unsigned short *char16; unsigned int *char32; unsigned int char_local[NUM_LOCAL]; unsigned int *chars; XGlyphElt8 *elts; XGlyphElt8 elts_local[NUM_ELT_LOCAL]; FcBool glyphs_loaded; int nelt; int x, y; if (!nglyphs) return; /* * Load missing glyphs. Have to load them * one at a time in case the font changes */ max = 0; glyphs_loaded = FcFalse; g = glyphs[0].glyph; for (i = 0; i < nglyphs; i++) { XftFont *pub = glyphs[i].font; XftFontInt *font = (XftFontInt *) pub; g = glyphs[i].glyph; if (g > max) max = g; nmissing = 0; if (XftFontCheckGlyph (dpy, pub, FcTrue, g, missing, &nmissing)) glyphs_loaded = FcTrue; if (nmissing) XftFontLoadGlyphs (dpy, pub, FcTrue, missing, nmissing); if (!font->format) goto bail1; if (!font->glyphset) goto bail1; } /* * See what encoding size is needed */ if (max < 0x100) { size = sizeof (char); width = 1; } else if (max < 0x10000) { size = sizeof (unsigned short); width = 2; } else { size = sizeof (unsigned int); width = 4; } chars = char_local; if (nglyphs * size > NUM_LOCAL) { chars = malloc ((size_t)(nglyphs * size)); if (!chars) goto bail1; } char8 = (char *) chars; char16 = (unsigned short *) chars; char32 = (unsigned int *) chars; /* * Compute the number of glyph elts needed */ nelt = 1; firstFont = NULL; for (i = 0; i < nglyphs; i++) { XftFont *pub = glyphs[i].font; XftFontInt *font = (XftFontInt *) pub; g = glyphs[i].glyph; /* Substitute default for non-existent glyphs */ if (g >= font->num_glyphs || !font->glyphs[g]) g = 0; if (font->glyphs[g]) { firstFont = font; break; } } if (i == nglyphs || !firstFont) goto bail2; glyph = firstFont->glyphs[g]; format = firstFont->format; x = glyphs[i].x + glyph->metrics.xOff; y = glyphs[i].y + glyph->metrics.yOff; prevPublic = NULL; while (++i < nglyphs) { XftFont *pub = glyphs[i].font; XftFontInt *font = (XftFontInt *) pub; g = glyphs[i].glyph; /* Substitute default for non-existent glyphs */ if (g >= font->num_glyphs || !font->glyphs[g]) g = 0; /* * check to see if the glyph is placed where it would * fall using the normal spacing */ if ((glyph = font->glyphs[g]) && !glyph->picture) { if (pub != prevPublic || x != glyphs[i].x || y != glyphs[i].y) { prevPublic = pub; if (font->format != format) format = XftPreferFormat (dpy, font->format, format); x = glyphs[i].x; y = glyphs[i].y; ++nelt; } x += glyph->metrics.xOff; y += glyph->metrics.yOff; } } elts = elts_local; if (nelt > NUM_ELT_LOCAL) { elts = AllocGlyphElt8Array (nelt); if (!elts) goto bail2; } /* * Generate the list of glyph elts and render color glyphs */ nelt = 0; x = y = 0; n = 0; j = 0; prevPublic = NULL; for (i = 0; i < nglyphs; i++) { XftFont *pub = glyphs[i].font; XftFontInt *font = (XftFontInt *) pub; g = glyphs[i].glyph; /* Substitute default for non-existent glyphs */ if (g >= font->num_glyphs || !font->glyphs[g]) g = 0; if ((glyph = font->glyphs[g])) { if (glyph->picture) { XRenderComposite(dpy, PictOpOver, glyph->picture, None, dst, 0, 0, 0, 0, glyphs[i].x - glyph->metrics.x, glyphs[i].y - glyph->metrics.y, glyph->metrics.width, glyph->metrics.height); continue; } if (!i || pub != prevPublic || x != glyphs[i].x || y != glyphs[i].y) { if (n) { elts[nelt].nchars = n; nelt++; } elts[nelt].glyphset = font->glyphset; elts[nelt].chars = char8 + size * j; elts[nelt].xOff = glyphs[i].x - x; elts[nelt].yOff = glyphs[i].y - y; prevPublic = pub; x = glyphs[i].x; y = glyphs[i].y; n = 0; } switch (width) { case 1: char8[j] = (char) g; break; case 2: char16[j] = (unsigned short) g; break; case 4: char32[j] = (unsigned int) g; break; } x += glyph->metrics.xOff; y += glyph->metrics.yOff; j++; n++; } } if (n) { elts[nelt].nchars = n; nelt++; } _XftCompositeText(dpy, op, src, dst, format, srcx, srcy, glyphs[0].x, glyphs[0].y, width, elts, nelt); if (elts != elts_local) free (elts); bail2: if (chars != char_local) free (chars); bail1: if (glyphs_loaded) for (i = 0; i < nglyphs; i++) _XftFontManageMemory (dpy, glyphs[i].font); } _X_EXPORT void XftCharFontSpecRender (Display *dpy, int op, Picture src, Picture dst, int srcx, int srcy, _Xconst XftCharFontSpec *chars, int len) { XftGlyphFontSpec *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocGlyphFontSpecArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) { glyphs[i].font = chars[i].font; glyphs[i].glyph = XftCharIndex(dpy, glyphs[i].font, chars[i].ucs4); glyphs[i].x = chars[i].x; glyphs[i].y = chars[i].y; } XftGlyphFontSpecRender (dpy, op, src, dst, srcx, srcy, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRender8 (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar8 *string, int len) { FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocUIntArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) glyphs[i] = XftCharIndex (dpy, pub, string[i]); XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRender16 (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar16 *string, int len) { FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocUIntArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) glyphs[i] = XftCharIndex (dpy, pub, string[i]); XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRender16BE (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar8 *string, int len) { FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocUIntArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) glyphs[i] = XftCharIndex (dpy, pub, (FcChar32)((string[i*2]<<8) | string[i*2+1])); XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRender16LE (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar8 *string, int len) { FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocUIntArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) glyphs[i] = XftCharIndex (dpy, pub, (FcChar32)(string[i*2] | (string[i*2+1]<<8))); XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRender32 (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar32 *string, int len) { FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocUIntArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) glyphs[i] = XftCharIndex (dpy, pub, string[i]); XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRender32BE (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar8 *string, int len) { FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocUIntArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) glyphs[i] = XftCharIndex (dpy, pub, (FcChar32)((string[i*4] << 24) | (string[i*4+1] << 16) | (string[i*4+2] << 8) | (string[i*4+3]))); XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRender32LE (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar8 *string, int len) { FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; int i; if (len <= 0) return; if (len <= NUM_LOCAL) glyphs = glyphs_local; else { glyphs = AllocUIntArray (len); if (!glyphs) return; } for (i = 0; i < len; i++) glyphs[i] = XftCharIndex (dpy, pub, (FcChar32)((string[i*4]) | (string[i*4+1] << 8) | (string[i*4+2] << 16) | (string[i*4+3] << 24))); XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, len); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRenderUtf8 (Display *dpy, int op, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar8 *string, int len) { FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL]; FcChar32 ucs4; int i; int l; int size; if (len <= 0) return; i = 0; glyphs = glyphs_local; size = NUM_LOCAL; while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0) { if (i == size) { glyphs_new = AllocUIntArray (size * 2); if (!glyphs_new) { if (glyphs != glyphs_local) free (glyphs); return; } memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt)); size *= 2; if (glyphs != glyphs_local) free (glyphs); glyphs = glyphs_new; } glyphs[i++] = XftCharIndex (dpy, pub, ucs4); string += l; len -= l; } XftGlyphRender (dpy, op, src, pub, dst, srcx, srcy, x, y, glyphs, i); if (glyphs != glyphs_local) free (glyphs); } _X_EXPORT void XftTextRenderUtf16 (Display *dpy, int op _X_UNUSED, Picture src, XftFont *pub, Picture dst, int srcx, int srcy, int x, int y, _Xconst FcChar8 *string, FcEndian endian, int len) { FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL]; FcChar32 ucs4; int i; int l; int size; if (len <= 0) return; i = 0; glyphs = glyphs_local; size = NUM_LOCAL; while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0) { if (i == size) { glyphs_new = AllocUIntArray (size * 2); if (!glyphs_new) { if (glyphs != glyphs_local) free (glyphs); return; } memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt)); size *= 2; if (glyphs != glyphs_local) free (glyphs); glyphs = glyphs_new; } glyphs[i++] = XftCharIndex (dpy, pub, ucs4); string += l; len -= l; } XftGlyphRender (dpy, PictOpOver, src, pub, dst, srcx, srcy, x, y, glyphs, i); if (glyphs != glyphs_local) free (glyphs); }