xenocara/lib/libXft/src/xftrender.c
2006-11-25 16:46:32 +00:00

1010 lines
22 KiB
C

/*
* $Id: xftrender.c,v 1.1.1.1 2006/11/25 17:21:39 matthieu Exp $
*
* 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"
#define NUM_LOCAL 1024
#define NUM_ELT_LOCAL 128
/*
* 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;
FT_UInt missing[XFT_NMISSING];
int nmissing;
FT_UInt g, max;
int size, width;
Glyph wire;
char *char8;
unsigned short *char16;
unsigned int *char32;
unsigned int char_local[NUM_LOCAL];
unsigned int *chars;
FcBool glyphs_loaded;
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 (nglyphs * size > sizeof (char_local))
{
chars = malloc (nglyphs * size);
if (!chars)
goto bail1;
}
char8 = (char *) chars;
char16 = (unsigned short *) chars;
char32 = (unsigned int *) chars;
for (i = 0; i < nglyphs; i++)
{
wire = (Glyph) glyphs[i];
if (wire >= font->num_glyphs || !font->glyphs[wire])
wire = 0;
switch (width) {
case 1: char8[i] = (char) wire; break;
case 2: char16[i] = (unsigned short) wire; break;
case 4: char32[i] = (unsigned long) wire; break;
}
}
switch (width) {
case 1:
default:
XRenderCompositeString8 (dpy, op,
src, dst, font->format, font->glyphset,
srcx, srcy, x, y, char8, nglyphs);
break;
case 2:
XRenderCompositeString16(dpy, op,
src, dst, font->format, font->glyphset,
srcx, srcy, x, y, char16, nglyphs);
break;
case 4:
XRenderCompositeString32(dpy, op,
src, dst, font->format, font->glyphset,
srcx, srcy, x, y, char32, nglyphs);
break;
}
if (chars != char_local)
free (chars);
bail1:
if (glyphs_loaded)
_XftFontManageMemory (dpy, pub);
}
_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 (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-existant 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-existant 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]))
{
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 (nelt > NUM_ELT_LOCAL)
{
elts = malloc (nelt * sizeof (XGlyphElt8));
if (!elts)
goto bail2;
}
/*
* Generate the list of glyph elts
*/
nelt = 0;
x = y = 0;
n = 0;
j = 0;
for (i = 0; i < nglyphs; i++)
{
g = glyphs[i].glyph;
/* Substitute default for non-existant glyphs */
if (g >= font->num_glyphs || !font->glyphs[g])
g = 0;
if ((glyph = font->glyphs[g]))
{
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++;
}
switch (width) {
case 1:
XRenderCompositeText8 (dpy, op, src, dst, font->format,
srcx, srcy, glyphs[0].x, glyphs[0].y,
elts, nelt);
break;
case 2:
XRenderCompositeText16 (dpy, op, src, dst, font->format,
srcx, srcy, glyphs[0].x, glyphs[0].y,
(XGlyphElt16 *) elts, nelt);
break;
case 4:
XRenderCompositeText32 (dpy, op, src, dst, font->format,
srcx, srcy, glyphs[0].x, glyphs[0].y,
(XGlyphElt32 *) elts, nelt);
break;
}
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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (XftGlyphSpec));
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 = 0;
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 (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 = 0;
for (i = 0; i < nglyphs; i++)
{
XftFont *pub = glyphs[i].font;
XftFontInt *font = (XftFontInt *) pub;
g = glyphs[i].glyph;
/* Substitute default for non-existant 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 = 0;
while (++i < nglyphs)
{
XftFont *pub = glyphs[i].font;
XftFontInt *font = (XftFontInt *) pub;
g = glyphs[i].glyph;
/* Substitute default for non-existant 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]))
{
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 = malloc (nelt * sizeof (XGlyphElt8));
if (!elts)
goto bail2;
}
/*
* Generate the list of glyph elts
*/
nelt = 0;
x = y = 0;
n = 0;
j = 0;
prevPublic = 0;
for (i = 0; i < nglyphs; i++)
{
XftFont *pub = glyphs[i].font;
XftFontInt *font = (XftFontInt *) pub;
g = glyphs[i].glyph;
/* Substitute default for non-existant glyphs */
if (g >= font->num_glyphs || !font->glyphs[g])
g = 0;
if ((glyph = font->glyphs[g]))
{
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++;
}
switch (width) {
case 1:
XRenderCompositeText8 (dpy, op, src, dst, format,
srcx, srcy, glyphs[0].x, glyphs[0].y,
elts, nelt);
break;
case 2:
XRenderCompositeText16 (dpy, op, src, dst, format,
srcx, srcy, glyphs[0].x, glyphs[0].y,
(XGlyphElt16 *) elts, nelt);
break;
case 4:
XRenderCompositeText32 (dpy, op, src, dst, format,
srcx, srcy, glyphs[0].x, glyphs[0].y,
(XGlyphElt32 *) elts, nelt);
break;
}
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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (XftGlyphFontSpec));
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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (FT_UInt));
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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (FT_UInt));
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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (FT_UInt));
if (!glyphs)
return;
}
for (i = 0; i < len; i++)
glyphs[i] = XftCharIndex (dpy, pub,
(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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (FT_UInt));
if (!glyphs)
return;
}
for (i = 0; i < len; i++)
glyphs[i] = XftCharIndex (dpy, pub,
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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (FT_UInt));
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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (FT_UInt));
if (!glyphs)
return;
}
for (i = 0; i < len; i++)
glyphs[i] = XftCharIndex (dpy, pub,
(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 <= NUM_LOCAL)
glyphs = glyphs_local;
else
{
glyphs = malloc (len * sizeof (FT_UInt));
if (!glyphs)
return;
}
for (i = 0; i < len; i++)
glyphs[i] = XftCharIndex (dpy, pub,
(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;
i = 0;
glyphs = glyphs_local;
size = NUM_LOCAL;
while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
{
if (i == size)
{
glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
if (!glyphs_new)
{
if (glyphs != glyphs_local)
free (glyphs);
return;
}
memcpy (glyphs_new, glyphs, 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,
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;
i = 0;
glyphs = glyphs_local;
size = NUM_LOCAL;
while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
{
if (i == size)
{
glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
if (!glyphs_new)
{
if (glyphs != glyphs_local)
free (glyphs);
return;
}
memcpy (glyphs_new, glyphs, 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);
}