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