xftglyphs.c revision c76ae52d
1c76ae52dSmrg/*
2c76ae52dSmrg * $Id: xftglyphs.c,v 1.1.1.1 2008/07/30 02:49:10 mrg Exp $
3c76ae52dSmrg *
4c76ae52dSmrg * Copyright © 2000 Keith Packard
5c76ae52dSmrg *
6c76ae52dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
7c76ae52dSmrg * documentation for any purpose is hereby granted without fee, provided that
8c76ae52dSmrg * the above copyright notice appear in all copies and that both that
9c76ae52dSmrg * copyright notice and this permission notice appear in supporting
10c76ae52dSmrg * documentation, and that the name of Keith Packard not be used in
11c76ae52dSmrg * advertising or publicity pertaining to distribution of the software without
12c76ae52dSmrg * specific, written prior permission.  Keith Packard makes no
13c76ae52dSmrg * representations about the suitability of this software for any purpose.  It
14c76ae52dSmrg * is provided "as is" without express or implied warranty.
15c76ae52dSmrg *
16c76ae52dSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17c76ae52dSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18c76ae52dSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19c76ae52dSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20c76ae52dSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21c76ae52dSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22c76ae52dSmrg * PERFORMANCE OF THIS SOFTWARE.
23c76ae52dSmrg */
24c76ae52dSmrg
25c76ae52dSmrg#include "xftint.h"
26c76ae52dSmrg#include <freetype/ftoutln.h>
27c76ae52dSmrg
28c76ae52dSmrgstatic const int    filters[3][3] = {
29c76ae52dSmrg    /* red */
30c76ae52dSmrg#if 0
31c76ae52dSmrg{    65538*4/7,65538*2/7,65538*1/7 },
32c76ae52dSmrg    /* green */
33c76ae52dSmrg{    65536*1/4, 65536*2/4, 65537*1/4 },
34c76ae52dSmrg    /* blue */
35c76ae52dSmrg{    65538*1/7,65538*2/7,65538*4/7 },
36c76ae52dSmrg#endif
37c76ae52dSmrg{    65538*9/13,65538*3/13,65538*1/13 },
38c76ae52dSmrg    /* green */
39c76ae52dSmrg{    65538*1/6, 65538*4/6, 65538*1/6 },
40c76ae52dSmrg    /* blue */
41c76ae52dSmrg{    65538*1/13,65538*3/13,65538*9/13 },
42c76ae52dSmrg};
43c76ae52dSmrg
44c76ae52dSmrg/*
45c76ae52dSmrg * Validate the memory info for a font
46c76ae52dSmrg */
47c76ae52dSmrg
48c76ae52dSmrgstatic void
49c76ae52dSmrg_XftFontValidateMemory (Display *dpy, XftFont *public)
50c76ae52dSmrg{
51c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) public;
52c76ae52dSmrg    unsigned long   glyph_memory;
53c76ae52dSmrg    FT_UInt	    glyphindex;
54c76ae52dSmrg    XftGlyph	    *xftg;
55c76ae52dSmrg
56c76ae52dSmrg    glyph_memory = 0;
57c76ae52dSmrg    for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
58c76ae52dSmrg    {
59c76ae52dSmrg	xftg = font->glyphs[glyphindex];
60c76ae52dSmrg	if (xftg)
61c76ae52dSmrg	{
62c76ae52dSmrg	    glyph_memory += xftg->glyph_memory;
63c76ae52dSmrg	}
64c76ae52dSmrg    }
65c76ae52dSmrg    if (glyph_memory != font->glyph_memory)
66c76ae52dSmrg	printf ("Font glyph cache incorrect has %ld bytes, should have %ld\n",
67c76ae52dSmrg		font->glyph_memory, glyph_memory);
68c76ae52dSmrg}
69c76ae52dSmrg
70c76ae52dSmrg_X_EXPORT void
71c76ae52dSmrgXftFontLoadGlyphs (Display	    *dpy,
72c76ae52dSmrg		   XftFont	    *pub,
73c76ae52dSmrg		   FcBool	    need_bitmaps,
74c76ae52dSmrg		   _Xconst FT_UInt  *glyphs,
75c76ae52dSmrg		   int		    nglyph)
76c76ae52dSmrg{
77c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
78c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
79c76ae52dSmrg    FT_Error	    error;
80c76ae52dSmrg    FT_UInt	    glyphindex;
81c76ae52dSmrg    FT_GlyphSlot    glyphslot;
82c76ae52dSmrg    XftGlyph	    *xftg;
83c76ae52dSmrg    Glyph	    glyph;
84c76ae52dSmrg    unsigned char   bufLocal[4096];
85c76ae52dSmrg    unsigned char   *bufBitmap = bufLocal;
86c76ae52dSmrg    int		    bufSize = sizeof (bufLocal);
87c76ae52dSmrg    int		    size, pitch;
88c76ae52dSmrg    unsigned char   bufLocalRgba[4096];
89c76ae52dSmrg    unsigned char   *bufBitmapRgba = bufLocalRgba;
90c76ae52dSmrg    int		    bufSizeRgba = sizeof (bufLocalRgba);
91c76ae52dSmrg    int		    sizergba, pitchrgba, widthrgba;
92c76ae52dSmrg    int		    width;
93c76ae52dSmrg    int		    height;
94c76ae52dSmrg    int		    left, right, top, bottom;
95c76ae52dSmrg    int		    hmul = 1;
96c76ae52dSmrg    int		    vmul = 1;
97c76ae52dSmrg    FT_Bitmap	    ftbit;
98c76ae52dSmrg    FT_Matrix	    matrix;
99c76ae52dSmrg    FT_Vector	    vector;
100c76ae52dSmrg    Bool	    subpixel = False;
101c76ae52dSmrg    FT_Face	    face;
102c76ae52dSmrg
103c76ae52dSmrg    if (!info)
104c76ae52dSmrg	return;
105c76ae52dSmrg
106c76ae52dSmrg    face = XftLockFace (&font->public);
107c76ae52dSmrg
108c76ae52dSmrg    if (!face)
109c76ae52dSmrg	return;
110c76ae52dSmrg
111c76ae52dSmrg    matrix.xx = matrix.yy = 0x10000L;
112c76ae52dSmrg    matrix.xy = matrix.yx = 0;
113c76ae52dSmrg
114c76ae52dSmrg    if (font->info.antialias)
115c76ae52dSmrg    {
116c76ae52dSmrg	switch (font->info.rgba) {
117c76ae52dSmrg	case FC_RGBA_RGB:
118c76ae52dSmrg	case FC_RGBA_BGR:
119c76ae52dSmrg	    matrix.xx *= 3;
120c76ae52dSmrg	    subpixel = True;
121c76ae52dSmrg	    hmul = 3;
122c76ae52dSmrg	    break;
123c76ae52dSmrg	case FC_RGBA_VRGB:
124c76ae52dSmrg	case FC_RGBA_VBGR:
125c76ae52dSmrg	    matrix.yy *= 3;
126c76ae52dSmrg	    vmul = 3;
127c76ae52dSmrg	    subpixel = True;
128c76ae52dSmrg	    break;
129c76ae52dSmrg	}
130c76ae52dSmrg    }
131c76ae52dSmrg
132c76ae52dSmrg    while (nglyph--)
133c76ae52dSmrg    {
134c76ae52dSmrg	glyphindex = *glyphs++;
135c76ae52dSmrg	xftg = font->glyphs[glyphindex];
136c76ae52dSmrg	if (!xftg)
137c76ae52dSmrg	    continue;
138c76ae52dSmrg
139c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHE)
140c76ae52dSmrg	    _XftFontValidateMemory (dpy, pub);
141c76ae52dSmrg	/*
142c76ae52dSmrg	 * Check to see if this glyph has just been loaded,
143c76ae52dSmrg	 * this happens when drawing the same glyph twice
144c76ae52dSmrg	 * in a single string
145c76ae52dSmrg	 */
146c76ae52dSmrg	if (xftg->glyph_memory)
147c76ae52dSmrg	    continue;
148c76ae52dSmrg
149c76ae52dSmrg	error = FT_Load_Glyph (face, glyphindex, font->info.load_flags);
150c76ae52dSmrg	if (error)
151c76ae52dSmrg	{
152c76ae52dSmrg	    /*
153c76ae52dSmrg	     * If anti-aliasing or transforming glyphs and
154c76ae52dSmrg	     * no outline version exists, fallback to the
155c76ae52dSmrg	     * bitmap and let things look bad instead of
156c76ae52dSmrg	     * missing the glyph
157c76ae52dSmrg	     */
158c76ae52dSmrg	    if (font->info.load_flags & FT_LOAD_NO_BITMAP)
159c76ae52dSmrg		error = FT_Load_Glyph (face, glyphindex,
160c76ae52dSmrg				       font->info.load_flags & ~FT_LOAD_NO_BITMAP);
161c76ae52dSmrg	    if (error)
162c76ae52dSmrg		continue;
163c76ae52dSmrg	}
164c76ae52dSmrg
165c76ae52dSmrg#define FLOOR(x)    ((x) & -64)
166c76ae52dSmrg#define CEIL(x)	    (((x)+63) & -64)
167c76ae52dSmrg#define TRUNC(x)    ((x) >> 6)
168c76ae52dSmrg#define ROUND(x)    (((x)+32) & -64)
169c76ae52dSmrg
170c76ae52dSmrg	glyphslot = face->glyph;
171c76ae52dSmrg
172c76ae52dSmrg#if HAVE_FT_GLYPHSLOT_EMBOLDEN
173c76ae52dSmrg	/*
174c76ae52dSmrg	 * Embolden if required
175c76ae52dSmrg	 */
176c76ae52dSmrg	if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot);
177c76ae52dSmrg#endif
178c76ae52dSmrg
179c76ae52dSmrg	/*
180c76ae52dSmrg	 * Compute glyph metrics from FreeType information
181c76ae52dSmrg	 */
182c76ae52dSmrg	if(font->info.transform && glyphslot->format != ft_glyph_format_bitmap)
183c76ae52dSmrg	{
184c76ae52dSmrg	    /*
185c76ae52dSmrg	     * calculate the true width by transforming all four corners.
186c76ae52dSmrg	     */
187c76ae52dSmrg	    int xc, yc;
188c76ae52dSmrg	    left = right = top = bottom = 0;
189c76ae52dSmrg	    for(xc = 0; xc <= 1; xc ++) {
190c76ae52dSmrg		for(yc = 0; yc <= 1; yc++) {
191c76ae52dSmrg		    vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width;
192c76ae52dSmrg		    vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height;
193c76ae52dSmrg		    FT_Vector_Transform(&vector, &font->info.matrix);
194c76ae52dSmrg		    if (XftDebug() & XFT_DBG_GLYPH)
195c76ae52dSmrg			printf("Trans %d %d: %d %d\n", (int) xc, (int) yc,
196c76ae52dSmrg			       (int) vector.x, (int) vector.y);
197c76ae52dSmrg		    if(xc == 0 && yc == 0) {
198c76ae52dSmrg			left = right = vector.x;
199c76ae52dSmrg			top = bottom = vector.y;
200c76ae52dSmrg		    } else {
201c76ae52dSmrg			if(left > vector.x) left = vector.x;
202c76ae52dSmrg			if(right < vector.x) right = vector.x;
203c76ae52dSmrg			if(bottom > vector.y) bottom = vector.y;
204c76ae52dSmrg			if(top < vector.y) top = vector.y;
205c76ae52dSmrg		    }
206c76ae52dSmrg
207c76ae52dSmrg		}
208c76ae52dSmrg	    }
209c76ae52dSmrg	    left = FLOOR(left);
210c76ae52dSmrg	    right = CEIL(right);
211c76ae52dSmrg	    bottom = FLOOR(bottom);
212c76ae52dSmrg	    top = CEIL(top);
213c76ae52dSmrg
214c76ae52dSmrg	} else {
215c76ae52dSmrg	    left  = FLOOR( glyphslot->metrics.horiBearingX );
216c76ae52dSmrg	    right = CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width );
217c76ae52dSmrg
218c76ae52dSmrg	    top    = CEIL( glyphslot->metrics.horiBearingY );
219c76ae52dSmrg	    bottom = FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height );
220c76ae52dSmrg	}
221c76ae52dSmrg
222c76ae52dSmrg	width = TRUNC(right - left);
223c76ae52dSmrg	height = TRUNC( top - bottom );
224c76ae52dSmrg
225c76ae52dSmrg	/*
226c76ae52dSmrg	 * Clip charcell glyphs to the bounding box
227c76ae52dSmrg	 * XXX transformed?
228c76ae52dSmrg	 */
229c76ae52dSmrg	if (font->info.spacing >= FC_CHARCELL && !font->info.transform)
230c76ae52dSmrg	{
231c76ae52dSmrg	    if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
232c76ae52dSmrg	    {
233c76ae52dSmrg		if (TRUNC(bottom) > font->public.max_advance_width)
234c76ae52dSmrg		{
235c76ae52dSmrg		    int adjust;
236c76ae52dSmrg
237c76ae52dSmrg		    adjust = bottom - (font->public.max_advance_width << 6);
238c76ae52dSmrg		    if (adjust > top)
239c76ae52dSmrg			adjust = top;
240c76ae52dSmrg		    top -= adjust;
241c76ae52dSmrg		    bottom -= adjust;
242c76ae52dSmrg		    height = font->public.max_advance_width;
243c76ae52dSmrg		}
244c76ae52dSmrg	    }
245c76ae52dSmrg	    else
246c76ae52dSmrg	    {
247c76ae52dSmrg		if (TRUNC(right) > font->public.max_advance_width)
248c76ae52dSmrg		{
249c76ae52dSmrg		    int adjust;
250c76ae52dSmrg
251c76ae52dSmrg		    adjust = right - (font->public.max_advance_width << 6);
252c76ae52dSmrg		    if (adjust > left)
253c76ae52dSmrg			adjust = left;
254c76ae52dSmrg		    left -= adjust;
255c76ae52dSmrg		    right -= adjust;
256c76ae52dSmrg		    width = font->public.max_advance_width;
257c76ae52dSmrg		}
258c76ae52dSmrg	    }
259c76ae52dSmrg	}
260c76ae52dSmrg
261c76ae52dSmrg	if (font->info.antialias)
262c76ae52dSmrg	    pitch = (width * hmul + 3) & ~3;
263c76ae52dSmrg	else
264c76ae52dSmrg	    pitch = ((width + 31) & ~31) >> 3;
265c76ae52dSmrg
266c76ae52dSmrg	size = pitch * height * vmul;
267c76ae52dSmrg
268c76ae52dSmrg	xftg->metrics.width = width;
269c76ae52dSmrg	xftg->metrics.height = height;
270c76ae52dSmrg	xftg->metrics.x = -TRUNC(left);
271c76ae52dSmrg	xftg->metrics.y = TRUNC(top);
272c76ae52dSmrg
273c76ae52dSmrg	if (font->info.spacing >= FC_MONO)
274c76ae52dSmrg	{
275c76ae52dSmrg	    if (font->info.transform)
276c76ae52dSmrg	    {
277c76ae52dSmrg		if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
278c76ae52dSmrg		{
279c76ae52dSmrg		    vector.x = 0;
280c76ae52dSmrg		    vector.y = -face->size->metrics.max_advance;
281c76ae52dSmrg		}
282c76ae52dSmrg		else
283c76ae52dSmrg		{
284c76ae52dSmrg		    vector.x = face->size->metrics.max_advance;
285c76ae52dSmrg		    vector.y = 0;
286c76ae52dSmrg		}
287c76ae52dSmrg		FT_Vector_Transform (&vector, &font->info.matrix);
288c76ae52dSmrg		xftg->metrics.xOff = vector.x >> 6;
289c76ae52dSmrg		xftg->metrics.yOff = -(vector.y >> 6);
290c76ae52dSmrg	    }
291c76ae52dSmrg	    else
292c76ae52dSmrg	    {
293c76ae52dSmrg		if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
294c76ae52dSmrg		{
295c76ae52dSmrg		    xftg->metrics.xOff = 0;
296c76ae52dSmrg		    xftg->metrics.yOff = -font->public.max_advance_width;
297c76ae52dSmrg		}
298c76ae52dSmrg		else
299c76ae52dSmrg		{
300c76ae52dSmrg		    xftg->metrics.xOff = font->public.max_advance_width;
301c76ae52dSmrg		    xftg->metrics.yOff = 0;
302c76ae52dSmrg		}
303c76ae52dSmrg	    }
304c76ae52dSmrg	}
305c76ae52dSmrg	else
306c76ae52dSmrg	{
307c76ae52dSmrg	    xftg->metrics.xOff = TRUNC(ROUND(glyphslot->advance.x));
308c76ae52dSmrg	    xftg->metrics.yOff = -TRUNC(ROUND(glyphslot->advance.y));
309c76ae52dSmrg	}
310c76ae52dSmrg
311c76ae52dSmrg	/*
312c76ae52dSmrg	 * If the glyph is relatively large (> 1% of server memory),
313c76ae52dSmrg	 * don't send it until necessary
314c76ae52dSmrg	 */
315c76ae52dSmrg	if (!need_bitmaps && size > info->max_glyph_memory / 100)
316c76ae52dSmrg	    continue;
317c76ae52dSmrg
318c76ae52dSmrg	/*
319c76ae52dSmrg	 * Make sure there's enough buffer space for the glyph
320c76ae52dSmrg	 */
321c76ae52dSmrg	if (size > bufSize)
322c76ae52dSmrg	{
323c76ae52dSmrg	    if (bufBitmap != bufLocal)
324c76ae52dSmrg		free (bufBitmap);
325c76ae52dSmrg	    bufBitmap = (unsigned char *) malloc (size);
326c76ae52dSmrg	    if (!bufBitmap)
327c76ae52dSmrg		continue;
328c76ae52dSmrg	    bufSize = size;
329c76ae52dSmrg	}
330c76ae52dSmrg	memset (bufBitmap, 0, size);
331c76ae52dSmrg
332c76ae52dSmrg	/*
333c76ae52dSmrg	 * Rasterize into the local buffer
334c76ae52dSmrg	 */
335c76ae52dSmrg	switch (glyphslot->format) {
336c76ae52dSmrg	case ft_glyph_format_outline:
337c76ae52dSmrg	    ftbit.width      = width * hmul;
338c76ae52dSmrg	    ftbit.rows       = height * vmul;
339c76ae52dSmrg	    ftbit.pitch      = pitch;
340c76ae52dSmrg	    if (font->info.antialias)
341c76ae52dSmrg		ftbit.pixel_mode = ft_pixel_mode_grays;
342c76ae52dSmrg	    else
343c76ae52dSmrg		ftbit.pixel_mode = ft_pixel_mode_mono;
344c76ae52dSmrg
345c76ae52dSmrg	    ftbit.buffer     = bufBitmap;
346c76ae52dSmrg
347c76ae52dSmrg	    if (subpixel)
348c76ae52dSmrg		FT_Outline_Transform (&glyphslot->outline, &matrix);
349c76ae52dSmrg
350c76ae52dSmrg	    FT_Outline_Translate ( &glyphslot->outline, -left*hmul, -bottom*vmul );
351c76ae52dSmrg
352c76ae52dSmrg	    FT_Outline_Get_Bitmap( _XftFTlibrary, &glyphslot->outline, &ftbit );
353c76ae52dSmrg	    break;
354c76ae52dSmrg	case ft_glyph_format_bitmap:
355c76ae52dSmrg	    if (font->info.antialias)
356c76ae52dSmrg	    {
357c76ae52dSmrg		unsigned char	*srcLine, *dstLine;
358c76ae52dSmrg		int		height;
359c76ae52dSmrg		int		x;
360c76ae52dSmrg		int	    h, v;
361c76ae52dSmrg
362c76ae52dSmrg		srcLine = glyphslot->bitmap.buffer;
363c76ae52dSmrg		dstLine = bufBitmap;
364c76ae52dSmrg		height = glyphslot->bitmap.rows;
365c76ae52dSmrg		while (height--)
366c76ae52dSmrg		{
367c76ae52dSmrg		    for (x = 0; x < glyphslot->bitmap.width; x++)
368c76ae52dSmrg		    {
369c76ae52dSmrg			/* always MSB bitmaps */
370c76ae52dSmrg			unsigned char	a = ((srcLine[x >> 3] & (0x80 >> (x & 7))) ?
371c76ae52dSmrg					     0xff : 0x00);
372c76ae52dSmrg			if (subpixel)
373c76ae52dSmrg			{
374c76ae52dSmrg			    for (v = 0; v < vmul; v++)
375c76ae52dSmrg				for (h = 0; h < hmul; h++)
376c76ae52dSmrg				    dstLine[v * pitch + x*hmul + h] = a;
377c76ae52dSmrg			}
378c76ae52dSmrg			else
379c76ae52dSmrg			    dstLine[x] = a;
380c76ae52dSmrg		    }
381c76ae52dSmrg		    dstLine += pitch * vmul;
382c76ae52dSmrg		    srcLine += glyphslot->bitmap.pitch;
383c76ae52dSmrg		}
384c76ae52dSmrg	    }
385c76ae52dSmrg	    else
386c76ae52dSmrg	    {
387c76ae52dSmrg		unsigned char	*srcLine, *dstLine;
388c76ae52dSmrg		int		h, bytes;
389c76ae52dSmrg
390c76ae52dSmrg		srcLine = glyphslot->bitmap.buffer;
391c76ae52dSmrg		dstLine = bufBitmap;
392c76ae52dSmrg		h = glyphslot->bitmap.rows;
393c76ae52dSmrg		bytes = (glyphslot->bitmap.width + 7) >> 3;
394c76ae52dSmrg		while (h--)
395c76ae52dSmrg		{
396c76ae52dSmrg		    memcpy (dstLine, srcLine, bytes);
397c76ae52dSmrg		    dstLine += pitch;
398c76ae52dSmrg		    srcLine += glyphslot->bitmap.pitch;
399c76ae52dSmrg		}
400c76ae52dSmrg	    }
401c76ae52dSmrg	    break;
402c76ae52dSmrg	default:
403c76ae52dSmrg	    if (XftDebug() & XFT_DBG_GLYPH)
404c76ae52dSmrg		printf ("glyph %d is not in a usable format\n",
405c76ae52dSmrg			(int) glyphindex);
406c76ae52dSmrg	    continue;
407c76ae52dSmrg	}
408c76ae52dSmrg
409c76ae52dSmrg	if (XftDebug() & XFT_DBG_GLYPH)
410c76ae52dSmrg	{
411c76ae52dSmrg	    printf ("glyph %d:\n", (int) glyphindex);
412c76ae52dSmrg	    printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n",
413c76ae52dSmrg		    (int) glyphslot->metrics.horiBearingX,
414c76ae52dSmrg		    (int) glyphslot->metrics.horiBearingY,
415c76ae52dSmrg		    (int) glyphslot->metrics.width,
416c76ae52dSmrg		    (int) glyphslot->metrics.height,
417c76ae52dSmrg		    left, right, top, bottom,
418c76ae52dSmrg		    width, height);
419c76ae52dSmrg	    if (XftDebug() & XFT_DBG_GLYPHV)
420c76ae52dSmrg	    {
421c76ae52dSmrg		int		x, y;
422c76ae52dSmrg		unsigned char	*line;
423c76ae52dSmrg
424c76ae52dSmrg		line = bufBitmap;
425c76ae52dSmrg		for (y = 0; y < height * vmul; y++)
426c76ae52dSmrg		{
427c76ae52dSmrg		    if (font->info.antialias)
428c76ae52dSmrg		    {
429c76ae52dSmrg			static char    den[] = { " .:;=+*#" };
430c76ae52dSmrg			for (x = 0; x < pitch; x++)
431c76ae52dSmrg			    printf ("%c", den[line[x] >> 5]);
432c76ae52dSmrg		    }
433c76ae52dSmrg		    else
434c76ae52dSmrg		    {
435c76ae52dSmrg			for (x = 0; x < pitch * 8; x++)
436c76ae52dSmrg			{
437c76ae52dSmrg			    printf ("%c", line[x>>3] & (1 << (x & 7)) ? '#' : ' ');
438c76ae52dSmrg			}
439c76ae52dSmrg		    }
440c76ae52dSmrg		    printf ("|\n");
441c76ae52dSmrg		    line += pitch;
442c76ae52dSmrg		}
443c76ae52dSmrg		printf ("\n");
444c76ae52dSmrg	    }
445c76ae52dSmrg	}
446c76ae52dSmrg
447c76ae52dSmrg	/*
448c76ae52dSmrg	 * Use the glyph index as the wire encoding; it
449c76ae52dSmrg	 * might be more efficient for some locales to map
450c76ae52dSmrg	 * these by first usage to smaller values, but that
451c76ae52dSmrg	 * would require persistently storing the map when
452c76ae52dSmrg	 * glyphs were freed.
453c76ae52dSmrg	 */
454c76ae52dSmrg	glyph = (Glyph) glyphindex;
455c76ae52dSmrg
456c76ae52dSmrg	if (subpixel)
457c76ae52dSmrg	{
458c76ae52dSmrg	    int		    x, y;
459c76ae52dSmrg	    unsigned char   *in_line, *out_line, *in;
460c76ae52dSmrg	    unsigned int    *out;
461c76ae52dSmrg	    unsigned int    red, green, blue;
462c76ae52dSmrg	    int		    rf, gf, bf;
463c76ae52dSmrg	    int		    s;
464c76ae52dSmrg	    int		    o, os;
465c76ae52dSmrg
466c76ae52dSmrg	    /*
467c76ae52dSmrg	     * Filter the glyph to soften the color fringes
468c76ae52dSmrg	     */
469c76ae52dSmrg	    widthrgba = width;
470c76ae52dSmrg	    pitchrgba = (widthrgba * 4 + 3) & ~3;
471c76ae52dSmrg	    sizergba = pitchrgba * height;
472c76ae52dSmrg
473c76ae52dSmrg	    os = 1;
474c76ae52dSmrg	    switch (font->info.rgba) {
475c76ae52dSmrg	    case FC_RGBA_VRGB:
476c76ae52dSmrg		os = pitch;
477c76ae52dSmrg	    case FC_RGBA_RGB:
478c76ae52dSmrg	    default:
479c76ae52dSmrg		rf = 0;
480c76ae52dSmrg		gf = 1;
481c76ae52dSmrg		bf = 2;
482c76ae52dSmrg		break;
483c76ae52dSmrg	    case FC_RGBA_VBGR:
484c76ae52dSmrg		os = pitch;
485c76ae52dSmrg	    case FC_RGBA_BGR:
486c76ae52dSmrg		bf = 0;
487c76ae52dSmrg		gf = 1;
488c76ae52dSmrg		rf = 2;
489c76ae52dSmrg		break;
490c76ae52dSmrg	    }
491c76ae52dSmrg	    if (sizergba > bufSizeRgba)
492c76ae52dSmrg	    {
493c76ae52dSmrg		if (bufBitmapRgba != bufLocalRgba)
494c76ae52dSmrg		    free (bufBitmapRgba);
495c76ae52dSmrg		bufBitmapRgba = (unsigned char *) malloc (sizergba);
496c76ae52dSmrg		if (!bufBitmapRgba)
497c76ae52dSmrg		    continue;
498c76ae52dSmrg		bufSizeRgba = sizergba;
499c76ae52dSmrg	    }
500c76ae52dSmrg	    memset (bufBitmapRgba, 0, sizergba);
501c76ae52dSmrg	    in_line = bufBitmap;
502c76ae52dSmrg	    out_line = bufBitmapRgba;
503c76ae52dSmrg	    for (y = 0; y < height; y++)
504c76ae52dSmrg	    {
505c76ae52dSmrg		in = in_line;
506c76ae52dSmrg		out = (unsigned int *) out_line;
507c76ae52dSmrg		in_line += pitch * vmul;
508c76ae52dSmrg		out_line += pitchrgba;
509c76ae52dSmrg		for (x = 0; x < width * hmul; x += hmul)
510c76ae52dSmrg		{
511c76ae52dSmrg		    red = green = blue = 0;
512c76ae52dSmrg		    o = 0;
513c76ae52dSmrg		    for (s = 0; s < 3; s++)
514c76ae52dSmrg		    {
515c76ae52dSmrg			red += filters[rf][s]*in[x+o];
516c76ae52dSmrg			green += filters[gf][s]*in[x+o];
517c76ae52dSmrg			blue += filters[bf][s]*in[x+o];
518c76ae52dSmrg			o += os;
519c76ae52dSmrg		    }
520c76ae52dSmrg		    red = red / 65536;
521c76ae52dSmrg		    green = green / 65536;
522c76ae52dSmrg		    blue = blue / 65536;
523c76ae52dSmrg		    *out++ = (green << 24) | (red << 16) | (green << 8) | blue;
524c76ae52dSmrg		}
525c76ae52dSmrg	    }
526c76ae52dSmrg
527c76ae52dSmrg	    xftg->glyph_memory = sizergba + sizeof (XftGlyph);
528c76ae52dSmrg	    if (font->format)
529c76ae52dSmrg	    {
530c76ae52dSmrg		if (!font->glyphset)
531c76ae52dSmrg		    font->glyphset = XRenderCreateGlyphSet (dpy, font->format);
532c76ae52dSmrg		if (ImageByteOrder (dpy) != XftNativeByteOrder ())
533c76ae52dSmrg		    XftSwapCARD32 ((CARD32 *) bufBitmapRgba, sizergba >> 2);
534c76ae52dSmrg		XRenderAddGlyphs (dpy, font->glyphset, &glyph,
535c76ae52dSmrg				  &xftg->metrics, 1,
536c76ae52dSmrg				  (char *) bufBitmapRgba, sizergba);
537c76ae52dSmrg	    }
538c76ae52dSmrg	    else
539c76ae52dSmrg	    {
540c76ae52dSmrg		if (sizergba)
541c76ae52dSmrg		{
542c76ae52dSmrg		    xftg->bitmap = malloc (sizergba);
543c76ae52dSmrg		    if (xftg->bitmap)
544c76ae52dSmrg			memcpy (xftg->bitmap, bufBitmapRgba, sizergba);
545c76ae52dSmrg		}
546c76ae52dSmrg		else
547c76ae52dSmrg		    xftg->bitmap = 0;
548c76ae52dSmrg	    }
549c76ae52dSmrg	}
550c76ae52dSmrg	else
551c76ae52dSmrg	{
552c76ae52dSmrg	    xftg->glyph_memory = size + sizeof (XftGlyph);
553c76ae52dSmrg	    if (font->format)
554c76ae52dSmrg	    {
555c76ae52dSmrg		/*
556c76ae52dSmrg		 * swap bit order around; FreeType is always MSBFirst
557c76ae52dSmrg		 */
558c76ae52dSmrg		if (!font->info.antialias)
559c76ae52dSmrg		{
560c76ae52dSmrg		    if (BitmapBitOrder (dpy) != MSBFirst)
561c76ae52dSmrg		    {
562c76ae52dSmrg			unsigned char   *line;
563c76ae52dSmrg			unsigned char   c;
564c76ae52dSmrg			int		    i;
565c76ae52dSmrg
566c76ae52dSmrg			line = (unsigned char *) bufBitmap;
567c76ae52dSmrg			i = size;
568c76ae52dSmrg			while (i--)
569c76ae52dSmrg			{
570c76ae52dSmrg			    c = *line;
571c76ae52dSmrg			    c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
572c76ae52dSmrg			    c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
573c76ae52dSmrg			    c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
574c76ae52dSmrg			    *line++ = c;
575c76ae52dSmrg			}
576c76ae52dSmrg		    }
577c76ae52dSmrg		}
578c76ae52dSmrg		if (!font->glyphset)
579c76ae52dSmrg		    font->glyphset = XRenderCreateGlyphSet (dpy, font->format);
580c76ae52dSmrg		XRenderAddGlyphs (dpy, font->glyphset, &glyph,
581c76ae52dSmrg				  &xftg->metrics, 1,
582c76ae52dSmrg				  (char *) bufBitmap, size);
583c76ae52dSmrg	    }
584c76ae52dSmrg	    else
585c76ae52dSmrg	    {
586c76ae52dSmrg		if (size)
587c76ae52dSmrg		{
588c76ae52dSmrg		    xftg->bitmap = malloc (size);
589c76ae52dSmrg		    if (xftg->bitmap)
590c76ae52dSmrg			memcpy (xftg->bitmap, bufBitmap, size);
591c76ae52dSmrg		}
592c76ae52dSmrg		else
593c76ae52dSmrg		    xftg->bitmap = 0;
594c76ae52dSmrg	    }
595c76ae52dSmrg	}
596c76ae52dSmrg	font->glyph_memory += xftg->glyph_memory;
597c76ae52dSmrg	info->glyph_memory += xftg->glyph_memory;
598c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHE)
599c76ae52dSmrg	    _XftFontValidateMemory (dpy, pub);
600c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHEV)
601c76ae52dSmrg	    printf ("Caching glyph 0x%x size %ld\n", glyphindex,
602c76ae52dSmrg		    xftg->glyph_memory);
603c76ae52dSmrg    }
604c76ae52dSmrg    if (bufBitmap != bufLocal)
605c76ae52dSmrg	free (bufBitmap);
606c76ae52dSmrg    if (bufBitmapRgba != bufLocalRgba)
607c76ae52dSmrg	free (bufBitmapRgba);
608c76ae52dSmrg    XftUnlockFace (&font->public);
609c76ae52dSmrg}
610c76ae52dSmrg
611c76ae52dSmrg_X_EXPORT void
612c76ae52dSmrgXftFontUnloadGlyphs (Display		*dpy,
613c76ae52dSmrg		     XftFont		*pub,
614c76ae52dSmrg		     _Xconst FT_UInt	*glyphs,
615c76ae52dSmrg		     int		nglyph)
616c76ae52dSmrg{
617c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
618c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
619c76ae52dSmrg    XftGlyph	    *xftg;
620c76ae52dSmrg    FT_UInt	    glyphindex;
621c76ae52dSmrg    Glyph	    glyphBuf[1024];
622c76ae52dSmrg    int		    nused;
623c76ae52dSmrg
624c76ae52dSmrg    nused = 0;
625c76ae52dSmrg    while (nglyph--)
626c76ae52dSmrg    {
627c76ae52dSmrg	glyphindex = *glyphs++;
628c76ae52dSmrg	xftg = font->glyphs[glyphindex];
629c76ae52dSmrg	if (!xftg)
630c76ae52dSmrg	    continue;
631c76ae52dSmrg	if (xftg->glyph_memory)
632c76ae52dSmrg	{
633c76ae52dSmrg	    if (font->format)
634c76ae52dSmrg	    {
635c76ae52dSmrg		if (font->glyphset)
636c76ae52dSmrg		{
637c76ae52dSmrg		    glyphBuf[nused++] = (Glyph) glyphindex;
638c76ae52dSmrg		    if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0]))
639c76ae52dSmrg		    {
640c76ae52dSmrg			XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
641c76ae52dSmrg			nused = 0;
642c76ae52dSmrg		    }
643c76ae52dSmrg		}
644c76ae52dSmrg	    }
645c76ae52dSmrg	    else
646c76ae52dSmrg	    {
647c76ae52dSmrg		if (xftg->bitmap)
648c76ae52dSmrg		    free (xftg->bitmap);
649c76ae52dSmrg	    }
650c76ae52dSmrg	    font->glyph_memory -= xftg->glyph_memory;
651c76ae52dSmrg	    if (info)
652c76ae52dSmrg		info->glyph_memory -= xftg->glyph_memory;
653c76ae52dSmrg	}
654c76ae52dSmrg	free (xftg);
655c76ae52dSmrg	XftMemFree (XFT_MEM_GLYPH, sizeof (XftGlyph));
656c76ae52dSmrg	font->glyphs[glyphindex] = 0;
657c76ae52dSmrg    }
658c76ae52dSmrg    if (font->glyphset && nused)
659c76ae52dSmrg	XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
660c76ae52dSmrg}
661c76ae52dSmrg
662c76ae52dSmrg_X_EXPORT FcBool
663c76ae52dSmrgXftFontCheckGlyph (Display	*dpy,
664c76ae52dSmrg		   XftFont	*pub,
665c76ae52dSmrg		   FcBool	need_bitmaps,
666c76ae52dSmrg		   FT_UInt	glyph,
667c76ae52dSmrg		   FT_UInt	*missing,
668c76ae52dSmrg		   int		*nmissing)
669c76ae52dSmrg{
670c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
671c76ae52dSmrg    XftGlyph	    *xftg;
672c76ae52dSmrg    int		    n;
673c76ae52dSmrg
674c76ae52dSmrg    if (glyph >= font->num_glyphs)
675c76ae52dSmrg	return FcFalse;
676c76ae52dSmrg    xftg = font->glyphs[glyph];
677c76ae52dSmrg    if (!xftg || (need_bitmaps && !xftg->glyph_memory))
678c76ae52dSmrg    {
679c76ae52dSmrg	if (!xftg)
680c76ae52dSmrg	{
681c76ae52dSmrg	    xftg = (XftGlyph *) malloc (sizeof (XftGlyph));
682c76ae52dSmrg	    if (!xftg)
683c76ae52dSmrg		return FcFalse;
684c76ae52dSmrg	    XftMemAlloc (XFT_MEM_GLYPH, sizeof (XftGlyph));
685c76ae52dSmrg	    xftg->bitmap = 0;
686c76ae52dSmrg	    xftg->glyph_memory = 0;
687c76ae52dSmrg	    font->glyphs[glyph] = xftg;
688c76ae52dSmrg	}
689c76ae52dSmrg	n = *nmissing;
690c76ae52dSmrg	missing[n++] = glyph;
691c76ae52dSmrg	if (n == XFT_NMISSING)
692c76ae52dSmrg	{
693c76ae52dSmrg	    XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n);
694c76ae52dSmrg	    n = 0;
695c76ae52dSmrg	}
696c76ae52dSmrg	*nmissing = n;
697c76ae52dSmrg	return FcTrue;
698c76ae52dSmrg    }
699c76ae52dSmrg    else
700c76ae52dSmrg	return FcFalse;
701c76ae52dSmrg}
702c76ae52dSmrg
703c76ae52dSmrg_X_EXPORT FcBool
704c76ae52dSmrgXftCharExists (Display	    *dpy,
705c76ae52dSmrg	       XftFont	    *pub,
706c76ae52dSmrg	       FcChar32    ucs4)
707c76ae52dSmrg{
708c76ae52dSmrg    if (pub->charset)
709c76ae52dSmrg	return FcCharSetHasChar (pub->charset, ucs4);
710c76ae52dSmrg    return FcFalse;
711c76ae52dSmrg}
712c76ae52dSmrg
713c76ae52dSmrg#define Missing	    ((FT_UInt) ~0)
714c76ae52dSmrg
715c76ae52dSmrg_X_EXPORT FT_UInt
716c76ae52dSmrgXftCharIndex (Display	    *dpy,
717c76ae52dSmrg	      XftFont	    *pub,
718c76ae52dSmrg	      FcChar32	    ucs4)
719c76ae52dSmrg{
720c76ae52dSmrg    XftFontInt	*font = (XftFontInt *) pub;
721c76ae52dSmrg    FcChar32	ent, offset;
722c76ae52dSmrg    FT_Face	face;
723c76ae52dSmrg
724c76ae52dSmrg    if (!font->hash_value)
725c76ae52dSmrg	return 0;
726c76ae52dSmrg
727c76ae52dSmrg    ent = ucs4 % font->hash_value;
728c76ae52dSmrg    offset = 0;
729c76ae52dSmrg    while (font->hash_table[ent].ucs4 != ucs4)
730c76ae52dSmrg    {
731c76ae52dSmrg	if (font->hash_table[ent].ucs4 == (FcChar32) ~0)
732c76ae52dSmrg	{
733c76ae52dSmrg	    if (!XftCharExists (dpy, pub, ucs4))
734c76ae52dSmrg		return 0;
735c76ae52dSmrg	    face  = XftLockFace (pub);
736c76ae52dSmrg	    if (!face)
737c76ae52dSmrg		return 0;
738c76ae52dSmrg	    font->hash_table[ent].ucs4 = ucs4;
739c76ae52dSmrg	    font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4);
740c76ae52dSmrg	    XftUnlockFace (pub);
741c76ae52dSmrg	    break;
742c76ae52dSmrg	}
743c76ae52dSmrg	if (!offset)
744c76ae52dSmrg	{
745c76ae52dSmrg	    offset = ucs4 % font->rehash_value;
746c76ae52dSmrg	    if (!offset)
747c76ae52dSmrg		offset = 1;
748c76ae52dSmrg	}
749c76ae52dSmrg	ent = ent + offset;
750c76ae52dSmrg	if (ent >= font->hash_value)
751c76ae52dSmrg	    ent -= font->hash_value;
752c76ae52dSmrg    }
753c76ae52dSmrg    return font->hash_table[ent].glyph;
754c76ae52dSmrg}
755c76ae52dSmrg
756c76ae52dSmrg/*
757c76ae52dSmrg * Pick a random glyph from the font and remove it from the cache
758c76ae52dSmrg */
759c76ae52dSmrg_X_HIDDEN void
760c76ae52dSmrg_XftFontUncacheGlyph (Display *dpy, XftFont *pub)
761c76ae52dSmrg{
762c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
763c76ae52dSmrg    unsigned long   glyph_memory;
764c76ae52dSmrg    FT_UInt	    glyphindex;
765c76ae52dSmrg    XftGlyph	    *xftg;
766c76ae52dSmrg
767c76ae52dSmrg    if (!font->glyph_memory)
768c76ae52dSmrg	return;
769c76ae52dSmrg    if (font->use_free_glyphs)
770c76ae52dSmrg    {
771c76ae52dSmrg	glyph_memory = rand() % font->glyph_memory;
772c76ae52dSmrg    }
773c76ae52dSmrg    else
774c76ae52dSmrg    {
775c76ae52dSmrg	if (font->glyphset)
776c76ae52dSmrg	{
777c76ae52dSmrg	    XRenderFreeGlyphSet (dpy, font->glyphset);
778c76ae52dSmrg	    font->glyphset = 0;
779c76ae52dSmrg	}
780c76ae52dSmrg	glyph_memory = 0;
781c76ae52dSmrg    }
782c76ae52dSmrg
783c76ae52dSmrg    if (XftDebug() & XFT_DBG_CACHE)
784c76ae52dSmrg	_XftFontValidateMemory (dpy, pub);
785c76ae52dSmrg    for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
786c76ae52dSmrg    {
787c76ae52dSmrg	xftg = font->glyphs[glyphindex];
788c76ae52dSmrg	if (xftg)
789c76ae52dSmrg	{
790c76ae52dSmrg	    if (xftg->glyph_memory > glyph_memory)
791c76ae52dSmrg	    {
792c76ae52dSmrg		if (XftDebug() & XFT_DBG_CACHEV)
793c76ae52dSmrg		    printf ("Uncaching glyph 0x%x size %ld\n",
794c76ae52dSmrg			    glyphindex, xftg->glyph_memory);
795c76ae52dSmrg		XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1);
796c76ae52dSmrg		if (!font->use_free_glyphs)
797c76ae52dSmrg		    continue;
798c76ae52dSmrg		break;
799c76ae52dSmrg	    }
800c76ae52dSmrg	    glyph_memory -= xftg->glyph_memory;
801c76ae52dSmrg	}
802c76ae52dSmrg    }
803c76ae52dSmrg    if (XftDebug() & XFT_DBG_CACHE)
804c76ae52dSmrg	_XftFontValidateMemory (dpy, pub);
805c76ae52dSmrg}
806c76ae52dSmrg
807c76ae52dSmrg_X_HIDDEN void
808c76ae52dSmrg_XftFontManageMemory (Display *dpy, XftFont *pub)
809c76ae52dSmrg{
810c76ae52dSmrg    XftFontInt	*font = (XftFontInt *) pub;
811c76ae52dSmrg
812c76ae52dSmrg    if (font->max_glyph_memory)
813c76ae52dSmrg    {
814c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHE)
815c76ae52dSmrg	{
816c76ae52dSmrg	    if (font->glyph_memory > font->max_glyph_memory)
817c76ae52dSmrg		printf ("Reduce memory for font 0x%lx from %ld to %ld\n",
818c76ae52dSmrg			font->glyphset ? font->glyphset : (unsigned long) font,
819c76ae52dSmrg			font->glyph_memory, font->max_glyph_memory);
820c76ae52dSmrg	}
821c76ae52dSmrg	while (font->glyph_memory > font->max_glyph_memory)
822c76ae52dSmrg	    _XftFontUncacheGlyph (dpy, pub);
823c76ae52dSmrg    }
824c76ae52dSmrg    _XftDisplayManageMemory (dpy);
825c76ae52dSmrg}
826