1c76ae52dSmrg/*
2120fad34Smrg * Copyright © 2022 Thomas E. Dickey
3c76ae52dSmrg * Copyright © 2000 Keith Packard
4c76ae52dSmrg *
5c76ae52dSmrg * Permission to use, copy, modify, distribute, and sell this software and its
6c76ae52dSmrg * documentation for any purpose is hereby granted without fee, provided that
7120fad34Smrg * the above copyright notice appear in all copies and that both that copyright
8120fad34Smrg * notice and this permission notice appear in supporting documentation, and
9120fad34Smrg * that the name of the above copyright holders not be used in advertising or
10120fad34Smrg * publicity pertaining to distribution of the software without specific,
11120fad34Smrg * written prior permission.  The above copyright holders make no
12c76ae52dSmrg * representations about the suitability of this software for any purpose.  It
13c76ae52dSmrg * is provided "as is" without express or implied warranty.
14c76ae52dSmrg *
15120fad34Smrg * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO
16120fad34Smrg * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17120fad34Smrg * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE
18120fad34Smrg * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19120fad34Smrg * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20120fad34Smrg * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21120fad34Smrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22c76ae52dSmrg */
23c76ae52dSmrg
24c76ae52dSmrg#include "xftint.h"
257bbb83baSmrg#include FT_OUTLINE_H
2612d4a5f4Smrg#include FT_LCD_FILTER_H
277bbb83baSmrg
2812d4a5f4Smrg#include FT_SYNTHESIS_H
29c76ae52dSmrg
30120fad34Smrg#include FT_GLYPH_H
31120fad34Smrg
32120fad34Smrgtypedef double m3x3[3][3];
33120fad34Smrg
34120fad34Smrgstatic void
35120fad34Smrgm3x3_uniform(m3x3 m)
36120fad34Smrg{
37120fad34Smrg    m[0][0] = m[1][1] = m[2][2] = 1.0;
38120fad34Smrg    m[0][1] = m[1][0] = m[0][2] = m[1][2] = m[2][0] = m[2][1] = 0;
39120fad34Smrg}
40120fad34Smrg
41120fad34Smrgstatic void
42120fad34Smrgm3x3_transform(FT_Vector *v, m3x3 m)
43120fad34Smrg{
44120fad34Smrg    double x, y;
45120fad34Smrg
46120fad34Smrg    x = (double)v->x;
47120fad34Smrg    y = (double)v->y;
48120fad34Smrg    v->x = (FT_Pos)(x * m[0][0] + y * m[0][1] + m[0][2] + 0.5);
49120fad34Smrg    v->y = (FT_Pos)(x * m[1][0] + y * m[1][1] + m[1][2] + 0.5);
50120fad34Smrg}
51120fad34Smrg
52120fad34Smrgstatic void
53120fad34Smrgm3x3_invert(m3x3 m, m3x3 mi)
54120fad34Smrg{
55120fad34Smrg    double det;
56120fad34Smrg
57120fad34Smrg    det  = m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]);
58120fad34Smrg    det -= m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]);
59120fad34Smrg    det += m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
60120fad34Smrg    det  = 1.0 / det;
61120fad34Smrg    mi[0][0] = det * (m[1][1] * m[2][2] - m[1][2] * m[2][1]);
62120fad34Smrg    mi[1][0] = det * (m[1][2] * m[2][0] - m[1][0] * m[2][2]);
63120fad34Smrg    mi[2][0] = det * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
64120fad34Smrg    mi[0][1] = det * (m[0][2] * m[2][1] - m[0][1] * m[2][2]);
65120fad34Smrg    mi[1][1] = det * (m[0][0] * m[2][2] - m[0][2] * m[2][0]);
66120fad34Smrg    mi[2][1] = det * (m[0][1] * m[2][0] - m[0][0] * m[2][1]);
67120fad34Smrg    mi[0][2] = det * (m[0][1] * m[1][2] - m[0][2] * m[1][1]);
68120fad34Smrg    mi[1][2] = det * (m[0][2] * m[1][0] - m[0][0] * m[1][2]);
69120fad34Smrg    mi[2][2] = det * (m[0][0] * m[1][1] - m[0][1] * m[1][0]);
70120fad34Smrg}
71120fad34Smrg
72c76ae52dSmrg/*
73c76ae52dSmrg * Validate the memory info for a font
74c76ae52dSmrg */
75c76ae52dSmrg
76c76ae52dSmrgstatic void
77120fad34Smrg_XftFontValidateMemory (Display *dpy _X_UNUSED, XftFont *public)
78c76ae52dSmrg{
79c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) public;
80c76ae52dSmrg    unsigned long   glyph_memory;
81c76ae52dSmrg    FT_UInt	    glyphindex;
82c76ae52dSmrg    XftGlyph	    *xftg;
83c76ae52dSmrg
84c76ae52dSmrg    glyph_memory = 0;
85c76ae52dSmrg    for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
86c76ae52dSmrg    {
87c76ae52dSmrg	xftg = font->glyphs[glyphindex];
88c76ae52dSmrg	if (xftg)
89c76ae52dSmrg	{
90c76ae52dSmrg	    glyph_memory += xftg->glyph_memory;
91c76ae52dSmrg	}
92c76ae52dSmrg    }
93c76ae52dSmrg    if (glyph_memory != font->glyph_memory)
94120fad34Smrg	printf ("Font glyph cache incorrect has %lu bytes, should have %lu\n",
95c76ae52dSmrg		font->glyph_memory, glyph_memory);
96c76ae52dSmrg}
97c76ae52dSmrg
98120fad34Smrg/*
99120fad34Smrg * Validate the glyph usage-links for a font.
100120fad34Smrg */
101120fad34Smrgstatic void
102120fad34Smrg_XftValidateGlyphUsage(XftFontInt *font)
103120fad34Smrg{
104120fad34Smrg    if (font->newest != FT_UINT_MAX) {
105120fad34Smrg	FT_UInt forward;
106120fad34Smrg	FT_UInt reverse;
107120fad34Smrg	FT_UInt next;
108120fad34Smrg	XftGlyphUsage *x1st = (XftGlyphUsage *) font->glyphs[font->newest];
109120fad34Smrg	XftGlyphUsage *xuse = x1st;
110120fad34Smrg	for (forward = 1,
111120fad34Smrg	     next = x1st->newer;
112120fad34Smrg	     xuse != NULL &&
113120fad34Smrg	     next != font->newest;
114120fad34Smrg	     next = xuse->newer) {
115120fad34Smrg	    if (next >= font->num_glyphs) {
116120fad34Smrg		printf("Xft: out of range; %d\n", next);
117120fad34Smrg		break;
118120fad34Smrg	    }
119120fad34Smrg	    if (++forward > font->total_inuse) {
120120fad34Smrg		printf("Xft: too many in-use glyphs (%d vs %d)\n",
121120fad34Smrg		       forward, font->total_inuse);
122120fad34Smrg		if (forward > font->total_inuse + 10)
123120fad34Smrg		    break;
124120fad34Smrg	    }
125120fad34Smrg	    xuse = (XftGlyphUsage *) font->glyphs[next];
126120fad34Smrg	}
127120fad34Smrg	if (forward < font->total_inuse) {
128120fad34Smrg	    printf("Xft: too few in-use glyphs (%u vs %d)\n",
129120fad34Smrg		   forward, font->total_inuse);
130120fad34Smrg	}
131120fad34Smrg	for (reverse = 1,
132120fad34Smrg	     next = x1st->older;
133120fad34Smrg	     xuse != NULL &&
134120fad34Smrg	     next != font->newest;
135120fad34Smrg	     next = xuse->older) {
136120fad34Smrg	    if (next >= font->num_glyphs) {
137120fad34Smrg		printf("Xft out of range; %d\n", next);
138120fad34Smrg		break;
139120fad34Smrg	    }
140120fad34Smrg	    if (++reverse > font->total_inuse) {
141120fad34Smrg		printf("Xft: too many in-use glyphs (%d vs %d)\n",
142120fad34Smrg		       reverse, font->total_inuse);
143120fad34Smrg		if (reverse > font->total_inuse + 10)
144120fad34Smrg		    break;
145120fad34Smrg	    }
146120fad34Smrg	    xuse = (XftGlyphUsage *) font->glyphs[next];
147120fad34Smrg	}
148120fad34Smrg	if (reverse < font->total_inuse) {
149120fad34Smrg	    printf("Xft: too few in-use glyphs (%u vs %d)\n",
150120fad34Smrg		   reverse, font->total_inuse);
151120fad34Smrg	}
152120fad34Smrg	if (forward != reverse) {
153120fad34Smrg	    printf("Xft: forward %d vs reverse %d\n",
154120fad34Smrg		   forward, reverse);
155120fad34Smrg	    exit(1);
156120fad34Smrg	}
157120fad34Smrg    }
158120fad34Smrg}
159120fad34Smrg
1602836776bSmrg/* we sometimes need to convert the glyph bitmap in a FT_GlyphSlot
1612836776bSmrg * into a different format. For example, we want to convert a
1622836776bSmrg * FT_PIXEL_MODE_LCD or FT_PIXEL_MODE_LCD_V bitmap into a 32-bit
1632836776bSmrg * ARGB or ABGR bitmap.
1642836776bSmrg *
1652836776bSmrg * this function prepares a target descriptor for this operation.
1662836776bSmrg *
1672836776bSmrg * input :: target bitmap descriptor. The function will set its
1682836776bSmrg *          'width', 'rows' and 'pitch' fields, and only these
1692836776bSmrg *
1702836776bSmrg * slot  :: the glyph slot containing the source bitmap. this
1712836776bSmrg *          function assumes that slot->format == FT_GLYPH_FORMAT_BITMAP
1722836776bSmrg *
1732836776bSmrg * mode  :: the requested final rendering mode. supported values are
1742836776bSmrg *          MONO, NORMAL (i.e. gray), LCD and LCD_V
1752836776bSmrg *
1762836776bSmrg * the function returns the size in bytes of the corresponding buffer,
1772836776bSmrg * it's up to the caller to allocate the corresponding memory block
1782836776bSmrg * before calling _fill_xrender_bitmap
1792836776bSmrg *
1802836776bSmrg * it also returns -1 in case of error (e.g. incompatible arguments,
1812836776bSmrg * like trying to convert a gray bitmap into a monochrome one)
1822836776bSmrg */
1832836776bSmrgstatic int
1842836776bSmrg_compute_xrender_bitmap_size( FT_Bitmap*	target,
1852836776bSmrg			      FT_GlyphSlot	slot,
186120fad34Smrg			      FT_Render_Mode	mode,
187120fad34Smrg			      FT_Matrix*	matrix,
188120fad34Smrg			      m3x3		m )
1892836776bSmrg{
1902836776bSmrg    FT_Bitmap*	ftbit;
1912836776bSmrg    int		width, height, pitch;
1922836776bSmrg
1932836776bSmrg    if ( slot->format != FT_GLYPH_FORMAT_BITMAP )
1942836776bSmrg	return -1;
1952836776bSmrg
1960e0b1094Smrg    /* compute the size of the final bitmap */
1972836776bSmrg    ftbit = &slot->bitmap;
1982836776bSmrg
1990e0b1094Smrg    width = (int)ftbit->width;
2000e0b1094Smrg    height = (int)ftbit->rows;
201120fad34Smrg
202120fad34Smrg    if ( matrix && mode == FT_RENDER_MODE_NORMAL )
203120fad34Smrg    {
204120fad34Smrg	FT_Matrix mirror, inverse;
205120fad34Smrg	FT_Vector vector;
206120fad34Smrg	int xc, yc;
207120fad34Smrg	int left, right, top, bottom;
208120fad34Smrg
209120fad34Smrg	left = right = top = bottom = 0;
210120fad34Smrg	for (xc = 0; xc <= 1; xc++) {
211120fad34Smrg	    for (yc = 0; yc <= 1; yc++) {
212120fad34Smrg		vector.x = xc * width;
213120fad34Smrg		vector.y = yc * height;
214120fad34Smrg		FT_Vector_Transform(&vector, matrix);
215120fad34Smrg		if (xc == 0 && yc == 0) {
216120fad34Smrg		    left = right = (int)vector.x;
217120fad34Smrg		    top = bottom = (int)vector.y;
218120fad34Smrg		} else {
219120fad34Smrg		    if (left   > vector.x) left   = (int)vector.x;
220120fad34Smrg		    if (right  < vector.x) right  = (int)vector.x;
221120fad34Smrg		    if (bottom > vector.y) bottom = (int)vector.y;
222120fad34Smrg		    if (top    < vector.y) top    = (int)vector.y;
223120fad34Smrg		}
224120fad34Smrg	    }
225120fad34Smrg	}
226120fad34Smrg	width = (int)(right - left);
227120fad34Smrg	height = (int)(top - bottom);
228120fad34Smrg
229120fad34Smrg	mirror.xx = + 0x10000;
230120fad34Smrg	mirror.yy = - 0x10000;
231120fad34Smrg	mirror.xy = mirror.yx = 0;
232120fad34Smrg	inverse = *matrix;
233120fad34Smrg	FT_Matrix_Multiply(&mirror, &inverse);
234120fad34Smrg	FT_Matrix_Invert(&inverse);
235120fad34Smrg	FT_Matrix_Multiply(&mirror, &inverse);
236120fad34Smrg
237120fad34Smrg	vector.x = vector.y = 0;
238120fad34Smrg	FT_Vector_Transform(&vector, &inverse);
239120fad34Smrg	left = (int)vector.x;
240120fad34Smrg	bottom = (int)vector.y;
241120fad34Smrg	vector.x = width;
242120fad34Smrg	vector.y = height;
243120fad34Smrg	FT_Vector_Transform(&vector, &inverse);
244120fad34Smrg	right = (int)vector.x;
245120fad34Smrg	top = (int)vector.y;
246120fad34Smrg	left = (right - left) - (int)ftbit->width;
247120fad34Smrg	bottom = (top - bottom) - (int)ftbit->rows;
248120fad34Smrg
249120fad34Smrg	m[0][0] = (double)inverse.xx / 0x10000;
250120fad34Smrg	m[0][1] = (double)inverse.xy / 0x10000;
251120fad34Smrg	m[1][0] = (double)inverse.yx / 0x10000;
252120fad34Smrg	m[1][1] = (double)inverse.yy / 0x10000;
253120fad34Smrg	m[0][2] = (double)-left / 2;
254120fad34Smrg	m[1][2] = (double)-bottom / 2;
255120fad34Smrg	m[2][0] = m[2][1] = 0.0;
256120fad34Smrg	m[2][2] = 1.0;
257120fad34Smrg    }
2582836776bSmrg    pitch = (width+3) & ~3;
2592836776bSmrg
2602836776bSmrg    switch ( ftbit->pixel_mode )
2612836776bSmrg    {
2622836776bSmrg    case FT_PIXEL_MODE_MONO:
2632836776bSmrg	if ( mode == FT_RENDER_MODE_MONO )
2642836776bSmrg	{
2652836776bSmrg	    pitch = (((width+31) & ~31) >> 3);
2662836776bSmrg	    break;
2672836776bSmrg	}
2682836776bSmrg	/* fall-through */
2692836776bSmrg
2702836776bSmrg    case FT_PIXEL_MODE_GRAY:
2712836776bSmrg	if ( mode == FT_RENDER_MODE_LCD ||
2722836776bSmrg	     mode == FT_RENDER_MODE_LCD_V )
2732836776bSmrg	{
2742836776bSmrg	    /* each pixel is replicated into a 32-bit ARGB value */
2752836776bSmrg	    pitch = width*4;
2762836776bSmrg	}
2772836776bSmrg	break;
2782836776bSmrg
279120fad34Smrg    case FT_PIXEL_MODE_BGRA:
280120fad34Smrg	pitch = width * 4;
281120fad34Smrg	break;
282120fad34Smrg
2832836776bSmrg    case FT_PIXEL_MODE_LCD:
2842836776bSmrg	if ( mode != FT_RENDER_MODE_LCD )
2852836776bSmrg	    return -1;
2862836776bSmrg
2872836776bSmrg	/* horz pixel triplets are packed into 32-bit ARGB values */
2882836776bSmrg	width /= 3;
2892836776bSmrg	pitch = width*4;
2902836776bSmrg	break;
2912836776bSmrg
2922836776bSmrg    case FT_PIXEL_MODE_LCD_V:
2932836776bSmrg	if ( mode != FT_RENDER_MODE_LCD_V )
2942836776bSmrg	    return -1;
2952836776bSmrg
2962836776bSmrg	/* vert pixel triplets are packed into 32-bit ARGB values */
2972836776bSmrg	height /= 3;
2982836776bSmrg	pitch = width*4;
2992836776bSmrg	break;
3002836776bSmrg
3012836776bSmrg    default:  /* unsupported source format */
3022836776bSmrg	return -1;
3032836776bSmrg    }
3042836776bSmrg
3050e0b1094Smrg    target->width = (unsigned)width;
3060e0b1094Smrg    target->rows = (unsigned)height;
3072836776bSmrg    target->pitch = pitch;
3082836776bSmrg    target->buffer = NULL;
3092836776bSmrg
3102836776bSmrg    return pitch * height;
3112836776bSmrg}
3122836776bSmrg
313120fad34Smrg/* this functions converts the glyph bitmap found in a FT_GlyphSlot
314120fad34Smrg * into a different format while scaling by applying the given matrix
315120fad34Smrg * (see _compute_xrender_bitmap_size)
316120fad34Smrg *
317120fad34Smrg * you should call this function after _compute_xrender_bitmap_size
318120fad34Smrg *
319120fad34Smrg * target :: target bitmap descriptor. Note that its 'buffer' pointer
320120fad34Smrg *           must point to memory allocated by the caller
321120fad34Smrg *
322120fad34Smrg * source :: the source bitmap descriptor
323120fad34Smrg *
324120fad34Smrg * matrix :: the scaling matrix to apply
325120fad34Smrg */
326120fad34Smrgstatic void
327120fad34Smrg_scaled_fill_xrender_bitmap( FT_Bitmap*	target,
328120fad34Smrg			     FT_Bitmap* source,
329120fad34Smrg			     m3x3 m )
330120fad34Smrg{
331120fad34Smrg    unsigned char*	src_buf	  = source->buffer;
332120fad34Smrg    unsigned char*	dst_line  = target->buffer;
333120fad34Smrg    int			src_pitch = source->pitch;
334120fad34Smrg    int			width     = (int) target->width;
335120fad34Smrg    int			height    = (int) target->rows;
336120fad34Smrg    int			pitch     = target->pitch;
337120fad34Smrg    int			i, x, y;
338120fad34Smrg    FT_Vector		vector, vector0;
339120fad34Smrg    int			sampling_width;
340120fad34Smrg    int			sampling_height;
341120fad34Smrg    int			sample_count;
342120fad34Smrg
343120fad34Smrg    if ( src_pitch < 0 )
344120fad34Smrg	src_buf -= ((unsigned) src_pitch * (source->rows - 1));
345120fad34Smrg
346120fad34Smrg    /* compute how many source pixels a target pixel spans */
347120fad34Smrg    vector.x = 1;
348120fad34Smrg    vector.y = 1;
349120fad34Smrg    m3x3_transform(&vector, m);
350120fad34Smrg    vector0.x = 0;
351120fad34Smrg    vector0.y = 0;
352120fad34Smrg    m3x3_transform(&vector0, m);
353120fad34Smrg    sampling_width = (int) ((vector.x - vector0.x) / 2);
354120fad34Smrg    sampling_height = (int) ((vector.y - vector0.y) / 2);
355120fad34Smrg    if (sampling_width < 0) sampling_width = -sampling_width;
356120fad34Smrg    if (sampling_height < 0) sampling_height = -sampling_height;
357120fad34Smrg    sample_count = (2 * sampling_width + 1) * (2 * sampling_height + 1);
358120fad34Smrg
359120fad34Smrg    for	( y = height; y > 0; y--, dst_line += pitch )
360120fad34Smrg    {
361120fad34Smrg	for ( x	= 0; x < width; x++ )
362120fad34Smrg	{
363120fad34Smrg	    unsigned char* src;
364120fad34Smrg
365120fad34Smrg	    /* compute target pixel location in source space */
366120fad34Smrg	    vector.x = x;
367120fad34Smrg	    vector.y = height - y;
368120fad34Smrg	    m3x3_transform(&vector, m);
369120fad34Smrg
370120fad34Smrg	    if (source->pixel_mode == FT_PIXEL_MODE_BGRA)
371120fad34Smrg	    {
372120fad34Smrg		if (vector.x < -sampling_width
373120fad34Smrg		 || vector.x > (source->width + (unsigned) sampling_width))
374120fad34Smrg		    continue;
375120fad34Smrg		if (vector.y < -sampling_height
376120fad34Smrg		 || vector.y > (source->rows + (unsigned) sampling_height))
377120fad34Smrg		    continue;
378120fad34Smrg	    }
379120fad34Smrg	    else
380120fad34Smrg	    {
381120fad34Smrg		if (vector.x < 0 || vector.x >= source->width)
382120fad34Smrg		    continue;
383120fad34Smrg		if (vector.y < 0 || vector.y >= source->rows)
384120fad34Smrg		    continue;
385120fad34Smrg	    }
386120fad34Smrg
387120fad34Smrg	    switch ( source->pixel_mode )
388120fad34Smrg	    {
389120fad34Smrg	    case FT_PIXEL_MODE_MONO: /* convert mono to 8-bit gray, scale using nearest pixel */
390120fad34Smrg		src = src_buf + (vector.y * src_pitch);
391120fad34Smrg		if ( src[(vector.x >> 3)] & (0x80 >> (vector.x & 7)) )
392120fad34Smrg		    dst_line[x] = 0xff;
393120fad34Smrg		break;
394120fad34Smrg
395120fad34Smrg	    case FT_PIXEL_MODE_GRAY: /* scale using nearest pixel */
396120fad34Smrg		src = src_buf + (vector.y * src_pitch);
397120fad34Smrg		dst_line[x] = src[vector.x];
398120fad34Smrg		break;
399120fad34Smrg
400120fad34Smrg	    case FT_PIXEL_MODE_BGRA: /* scale by averaging all relevant source pixels, keep BGRA format */
401120fad34Smrg	    {
402120fad34Smrg		int sample_x, sample_y;
403120fad34Smrg		int bgra[4] = { 0, 0, 0, 0 };
404120fad34Smrg
405120fad34Smrg		for (sample_y = - sampling_height; sample_y < sampling_height + 1; ++sample_y)
406120fad34Smrg		{
407120fad34Smrg		    int src_y = (int) (vector.y + sample_y);
408120fad34Smrg
409120fad34Smrg		    if (src_y < 0 || (FT_Pos) src_y >= source->rows)
410120fad34Smrg			continue;
411120fad34Smrg		    src = src_buf + (src_y * src_pitch);
412120fad34Smrg		    for (sample_x = - sampling_width; sample_x < sampling_width + 1; ++sample_x)
413120fad34Smrg		    {
414120fad34Smrg			int src_x = (int) (vector.x + sample_x);
415120fad34Smrg
416120fad34Smrg			if (src_x < 0 || (FT_Pos) src_x >= source->width)
417120fad34Smrg			    continue;
418120fad34Smrg			for (i = 0; i < 4; ++i)
419120fad34Smrg			    bgra[i] += src[src_x * 4 + i];
420120fad34Smrg		    }
421120fad34Smrg		}
422120fad34Smrg
423120fad34Smrg		for (i = 0; i < 4; ++i)
424120fad34Smrg		    dst_line[4 * x + i] = (unsigned char) (bgra[i] / sample_count);
425120fad34Smrg		break;
426120fad34Smrg	    }
427120fad34Smrg	    }
428120fad34Smrg	}
429120fad34Smrg    }
430120fad34Smrg}
431120fad34Smrg
4322836776bSmrg/* this functions converts the glyph bitmap found in a FT_GlyphSlot
4332836776bSmrg * into a different format (see _compute_xrender_bitmap_size)
4342836776bSmrg *
4352836776bSmrg * you should call this function after _compute_xrender_bitmap_size
4362836776bSmrg *
4372836776bSmrg * target :: target bitmap descriptor. Note that its 'buffer' pointer
4382836776bSmrg *           must point to memory allocated by the caller
4392836776bSmrg *
4402836776bSmrg * slot   :: the glyph slot containing the source bitmap
4412836776bSmrg *
4422836776bSmrg * mode   :: the requested final rendering mode
4432836776bSmrg *
4442836776bSmrg * bgr    :: boolean, set if BGR or VBGR pixel ordering is needed
4452836776bSmrg */
4462836776bSmrgstatic void
4472836776bSmrg_fill_xrender_bitmap( FT_Bitmap*	target,
4482836776bSmrg		      FT_GlyphSlot	slot,
4492836776bSmrg		      FT_Render_Mode	mode,
4502836776bSmrg		      int		bgr )
4512836776bSmrg{
4522836776bSmrg    FT_Bitmap*   ftbit = &slot->bitmap;
4532836776bSmrg
4542836776bSmrg    {
4552836776bSmrg	unsigned char*	srcLine	= ftbit->buffer;
456120fad34Smrg	unsigned char*	dstLine	= target->buffer;
457120fad34Smrg	int		src_pitch = ftbit->pitch;
458120fad34Smrg	int		width = (int)target->width;
459120fad34Smrg	int		height = (int)target->rows;
460120fad34Smrg	int		pitch = target->pitch;
461120fad34Smrg	int		subpixel;
462120fad34Smrg	int		h;
463120fad34Smrg
464120fad34Smrg	subpixel = ( mode == FT_RENDER_MODE_LCD ||
4652836776bSmrg		     mode == FT_RENDER_MODE_LCD_V );
4662836776bSmrg
4672836776bSmrg	if ( src_pitch < 0 )
4680e0b1094Smrg	    srcLine -= ((unsigned)src_pitch * (ftbit->rows-1));
4692836776bSmrg
4702836776bSmrg	switch ( ftbit->pixel_mode )
4712836776bSmrg	{
4722836776bSmrg	case FT_PIXEL_MODE_MONO:
4732836776bSmrg	    if ( subpixel )  /* convert mono to ARGB32 values */
4742836776bSmrg	    {
4752836776bSmrg		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
4762836776bSmrg		{
4772836776bSmrg		    int x;
4782836776bSmrg
4792836776bSmrg		    for ( x = 0; x < width; x++ )
4802836776bSmrg		    {
4812836776bSmrg			if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) )
4822836776bSmrg			    ((unsigned int*)dstLine)[x] = 0xffffffffU;
4832836776bSmrg		    }
4842836776bSmrg		}
4852836776bSmrg	    }
4862836776bSmrg	    else if ( mode == FT_RENDER_MODE_NORMAL )  /* convert mono to 8-bit gray */
4872836776bSmrg	    {
4882836776bSmrg		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
4892836776bSmrg		{
4902836776bSmrg		    int x;
4912836776bSmrg
4922836776bSmrg		    for ( x = 0; x < width; x++ )
4932836776bSmrg		    {
4942836776bSmrg			if ( srcLine[(x >> 3)] & (0x80 >> (x & 7)) )
4952836776bSmrg			    dstLine[x] = 0xff;
4962836776bSmrg		    }
4972836776bSmrg		}
4982836776bSmrg	    }
4992836776bSmrg	    else  /* copy mono to mono */
5002836776bSmrg	    {
5012836776bSmrg		int bytes = (width+7) >> 3;
5022836776bSmrg
5032836776bSmrg		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
5040e0b1094Smrg		    memcpy( dstLine, srcLine, (size_t)bytes );
5052836776bSmrg	    }
5062836776bSmrg	    break;
5072836776bSmrg
5082836776bSmrg	case FT_PIXEL_MODE_GRAY:
5092836776bSmrg	    if ( subpixel )  /* convert gray to ARGB32 values */
5102836776bSmrg	    {
5112836776bSmrg		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
5122836776bSmrg		{
5132836776bSmrg		    int		   x;
5142836776bSmrg		    unsigned int*  dst = (unsigned int*)dstLine;
5152836776bSmrg
5162836776bSmrg		    for ( x = 0; x < width; x++ )
5172836776bSmrg		    {
5182836776bSmrg			unsigned int pix = srcLine[x];
5192836776bSmrg
5202836776bSmrg			pix |= (pix << 8);
5212836776bSmrg			pix |= (pix << 16);
5222836776bSmrg
5232836776bSmrg			dst[x] = pix;
5242836776bSmrg		    }
5252836776bSmrg		}
5262836776bSmrg	    }
5272836776bSmrg	    else  /* copy gray into gray */
5282836776bSmrg	    {
5292836776bSmrg		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
5300e0b1094Smrg		    memcpy( dstLine, srcLine, (size_t)width );
5312836776bSmrg	    }
5322836776bSmrg	    break;
5332836776bSmrg
534120fad34Smrg	case FT_PIXEL_MODE_BGRA: /* Preserve BGRA format */
535120fad34Smrg	    for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
536120fad34Smrg		memcpy( dstLine, srcLine, (size_t) width * 4 );
537120fad34Smrg	    break;
538120fad34Smrg
5392836776bSmrg	case FT_PIXEL_MODE_LCD:
5402836776bSmrg	    if ( !bgr )
5412836776bSmrg	    {
5422836776bSmrg		/* convert horizontal RGB into ARGB32 */
5432836776bSmrg		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
5442836776bSmrg		{
5452836776bSmrg		    int		   x;
5462836776bSmrg		    unsigned char* src = srcLine;
5472836776bSmrg		    unsigned int*  dst = (unsigned int*)dstLine;
5482836776bSmrg
5492836776bSmrg		    for ( x = 0; x < width; x++, src += 3 )
5502836776bSmrg		    {
5512836776bSmrg			unsigned int pix;
5522836776bSmrg
5532836776bSmrg			pix = ((unsigned int)src[0] << 16) |
5542836776bSmrg			      ((unsigned int)src[1] <<  8) |
5552836776bSmrg			      ((unsigned int)src[2]      ) |
5562836776bSmrg			      ((unsigned int)src[1] << 24) ;
5572836776bSmrg
5582836776bSmrg			dst[x] = pix;
5592836776bSmrg		    }
5602836776bSmrg		}
5612836776bSmrg	    }
5622836776bSmrg	    else
5632836776bSmrg	    {
5642836776bSmrg		/* convert horizontal BGR into ARGB32 */
5652836776bSmrg		for ( h = height; h > 0; h--, srcLine += src_pitch, dstLine += pitch )
5662836776bSmrg		{
5672836776bSmrg		    int		   x;
5682836776bSmrg		    unsigned char* src = srcLine;
5692836776bSmrg		    unsigned int*  dst = (unsigned int*)dstLine;
5702836776bSmrg
5712836776bSmrg		    for ( x = 0; x < width; x++, src += 3 )
5722836776bSmrg		    {
5732836776bSmrg			unsigned int pix;
5742836776bSmrg
5752836776bSmrg			pix = ((unsigned int)src[2] << 16) |
5762836776bSmrg			      ((unsigned int)src[1] <<  8) |
5772836776bSmrg			      ((unsigned int)src[0]      ) |
5782836776bSmrg			      ((unsigned int)src[1] << 24) ;
5792836776bSmrg
5802836776bSmrg			dst[x] = pix;
5812836776bSmrg		    }
5822836776bSmrg		}
5832836776bSmrg	    }
5842836776bSmrg	    break;
5852836776bSmrg
5862836776bSmrg	default:  /* FT_PIXEL_MODE_LCD_V */
5872836776bSmrg	    /* convert vertical RGB into ARGB32 */
5882836776bSmrg	    if ( !bgr )
5892836776bSmrg	    {
5902836776bSmrg		for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch )
5912836776bSmrg		{
5922836776bSmrg		    int		   x;
5932836776bSmrg		    unsigned char* src = srcLine;
5942836776bSmrg		    unsigned int*  dst = (unsigned int*)dstLine;
5952836776bSmrg
5962836776bSmrg		    for ( x = 0; x < width; x++, src += 1 )
5972836776bSmrg		    {
5982836776bSmrg			unsigned int  pix;
5992836776bSmrg
6002836776bSmrg			pix = ((unsigned int)src[0]           << 16) |
6012836776bSmrg			      ((unsigned int)src[src_pitch]   <<  8) |
6022836776bSmrg			      ((unsigned int)src[src_pitch*2]      ) |
6032836776bSmrg			      ((unsigned int)src[src_pitch]   << 24) ;
6042836776bSmrg
6052836776bSmrg			dst[x] = pix;
6062836776bSmrg		    }
6072836776bSmrg		}
6082836776bSmrg	    }
6092836776bSmrg	    else
6102836776bSmrg	    {
6112836776bSmrg	    for ( h = height; h > 0; h--, srcLine += 3*src_pitch, dstLine += pitch )
6122836776bSmrg		{
6132836776bSmrg		    int		   x;
6142836776bSmrg		    unsigned char* src = srcLine;
6152836776bSmrg		    unsigned int*  dst = (unsigned int*)dstLine;
6162836776bSmrg
6172836776bSmrg		    for ( x = 0; x < width; x++, src += 1 )
6182836776bSmrg		    {
6192836776bSmrg			unsigned int  pix;
6202836776bSmrg
6212836776bSmrg			pix = ((unsigned int)src[src_pitch*2] << 16) |
6222836776bSmrg			      ((unsigned int)src[src_pitch]   <<  8) |
6232836776bSmrg			      ((unsigned int)src[0]                ) |
6242836776bSmrg			      ((unsigned int)src[src_pitch]   << 24) ;
6252836776bSmrg
6262836776bSmrg			dst[x] = pix;
6272836776bSmrg		    }
6282836776bSmrg		}
6292836776bSmrg	    }
6302836776bSmrg	}
6312836776bSmrg    }
6322836776bSmrg}
6332836776bSmrg
634c76ae52dSmrg_X_EXPORT void
635c76ae52dSmrgXftFontLoadGlyphs (Display	    *dpy,
636c76ae52dSmrg		   XftFont	    *pub,
637c76ae52dSmrg		   FcBool	    need_bitmaps,
638c76ae52dSmrg		   _Xconst FT_UInt  *glyphs,
639c76ae52dSmrg		   int		    nglyph)
640c76ae52dSmrg{
641c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, True);
642c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
643c76ae52dSmrg    FT_Error	    error;
644c76ae52dSmrg    FT_UInt	    glyphindex;
645c76ae52dSmrg    FT_GlyphSlot    glyphslot;
646c76ae52dSmrg    XftGlyph	    *xftg;
647c76ae52dSmrg    Glyph	    glyph;
648c76ae52dSmrg    unsigned char   bufLocal[4096];
649c76ae52dSmrg    unsigned char   *bufBitmap = bufLocal;
650c76ae52dSmrg    int		    bufSize = sizeof (bufLocal);
6512836776bSmrg    int		    size;
652c76ae52dSmrg    int		    width;
653c76ae52dSmrg    int		    height;
654c76ae52dSmrg    int		    left, right, top, bottom;
6552836776bSmrg    FT_Bitmap*	    ftbit;
6562836776bSmrg    FT_Bitmap	    local;
657c76ae52dSmrg    FT_Vector	    vector;
658120fad34Smrg    m3x3	    m;
659c76ae52dSmrg    FT_Face	    face;
6602836776bSmrg    FT_Render_Mode  mode = FT_RENDER_MODE_MONO;
661120fad34Smrg    FcBool	    transform;
662120fad34Smrg    FcBool	    glyph_transform;
663c76ae52dSmrg
664c76ae52dSmrg    if (!info)
665c76ae52dSmrg	return;
666c76ae52dSmrg
667c76ae52dSmrg    face = XftLockFace (&font->public);
6682836776bSmrg
669c76ae52dSmrg    if (!face)
670c76ae52dSmrg	return;
671c76ae52dSmrg
672120fad34Smrg    if (font->info.color)
673120fad34Smrg	mode = FT_RENDER_MODE_NORMAL;
674c76ae52dSmrg    if (font->info.antialias)
675c76ae52dSmrg    {
676c76ae52dSmrg	switch (font->info.rgba) {
677c76ae52dSmrg	case FC_RGBA_RGB:
678c76ae52dSmrg	case FC_RGBA_BGR:
6792836776bSmrg	    mode = FT_RENDER_MODE_LCD;
680c76ae52dSmrg	    break;
681c76ae52dSmrg	case FC_RGBA_VRGB:
682c76ae52dSmrg	case FC_RGBA_VBGR:
6832836776bSmrg	    mode = FT_RENDER_MODE_LCD_V;
684c76ae52dSmrg	    break;
6852836776bSmrg	default:
6862836776bSmrg	    mode = FT_RENDER_MODE_NORMAL;
687c76ae52dSmrg	}
688c76ae52dSmrg    }
689c76ae52dSmrg
690120fad34Smrg    transform = font->info.transform && mode != FT_RENDER_MODE_MONO;
691120fad34Smrg
692c76ae52dSmrg    while (nglyph--)
693c76ae52dSmrg    {
694c76ae52dSmrg	glyphindex = *glyphs++;
695c76ae52dSmrg	xftg = font->glyphs[glyphindex];
696c76ae52dSmrg	if (!xftg)
697c76ae52dSmrg	    continue;
6982836776bSmrg
699c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHE)
700c76ae52dSmrg	    _XftFontValidateMemory (dpy, pub);
701c76ae52dSmrg	/*
702c76ae52dSmrg	 * Check to see if this glyph has just been loaded,
703c76ae52dSmrg	 * this happens when drawing the same glyph twice
704c76ae52dSmrg	 * in a single string
705c76ae52dSmrg	 */
706c76ae52dSmrg	if (xftg->glyph_memory)
707c76ae52dSmrg	    continue;
7082836776bSmrg
7092836776bSmrg	FT_Library_SetLcdFilter( _XftFTlibrary, font->info.lcd_filter);
7102836776bSmrg
711c76ae52dSmrg	error = FT_Load_Glyph (face, glyphindex, font->info.load_flags);
712c76ae52dSmrg	if (error)
713c76ae52dSmrg	{
714c76ae52dSmrg	    /*
715c76ae52dSmrg	     * If anti-aliasing or transforming glyphs and
716c76ae52dSmrg	     * no outline version exists, fallback to the
717c76ae52dSmrg	     * bitmap and let things look bad instead of
718c76ae52dSmrg	     * missing the glyph
719c76ae52dSmrg	     */
720c76ae52dSmrg	    if (font->info.load_flags & FT_LOAD_NO_BITMAP)
721c76ae52dSmrg		error = FT_Load_Glyph (face, glyphindex,
722c76ae52dSmrg				       font->info.load_flags & ~FT_LOAD_NO_BITMAP);
723c76ae52dSmrg	    if (error)
724c76ae52dSmrg		continue;
725c76ae52dSmrg	}
726c76ae52dSmrg
727c76ae52dSmrg#define FLOOR(x)    ((x) & -64)
728c76ae52dSmrg#define CEIL(x)	    (((x)+63) & -64)
729c76ae52dSmrg#define TRUNC(x)    ((x) >> 6)
730c76ae52dSmrg#define ROUND(x)    (((x)+32) & -64)
7312836776bSmrg
732c76ae52dSmrg	glyphslot = face->glyph;
733c76ae52dSmrg
734c76ae52dSmrg	/*
735c76ae52dSmrg	 * Embolden if required
736c76ae52dSmrg	 */
737c76ae52dSmrg	if (font->info.embolden) FT_GlyphSlot_Embolden(glyphslot);
738c76ae52dSmrg
739c76ae52dSmrg	/*
740c76ae52dSmrg	 * Compute glyph metrics from FreeType information
741c76ae52dSmrg	 */
742120fad34Smrg	if (transform)
743c76ae52dSmrg	{
744c76ae52dSmrg	    /*
745c76ae52dSmrg	     * calculate the true width by transforming all four corners.
746c76ae52dSmrg	     */
747c76ae52dSmrg	    int xc, yc;
748c76ae52dSmrg	    left = right = top = bottom = 0;
749120fad34Smrg	    for (xc = 0; xc <= 1; xc++) {
750120fad34Smrg		for (yc = 0; yc <= 1; yc++) {
751c76ae52dSmrg		    vector.x = glyphslot->metrics.horiBearingX + xc * glyphslot->metrics.width;
752c76ae52dSmrg		    vector.y = glyphslot->metrics.horiBearingY - yc * glyphslot->metrics.height;
7532836776bSmrg		    FT_Vector_Transform(&vector, &font->info.matrix);
754c76ae52dSmrg		    if (XftDebug() & XFT_DBG_GLYPH)
7552836776bSmrg			printf("Trans %d %d: %d %d\n", (int) xc, (int) yc,
756c76ae52dSmrg			       (int) vector.x, (int) vector.y);
757120fad34Smrg		    if (xc == 0 && yc == 0) {
7580e0b1094Smrg			left = right = (int)vector.x;
7590e0b1094Smrg			top = bottom = (int)vector.y;
760c76ae52dSmrg		    } else {
761120fad34Smrg			if (left   > vector.x) left   = (int)vector.x;
762120fad34Smrg			if (right  < vector.x) right  = (int)vector.x;
763120fad34Smrg			if (bottom > vector.y) bottom = (int)vector.y;
764120fad34Smrg			if (top	   < vector.y) top    = (int)vector.y;
765c76ae52dSmrg		    }
766c76ae52dSmrg
767c76ae52dSmrg		}
768c76ae52dSmrg	    }
7690e0b1094Smrg	    left   = (int)FLOOR(left);
7700e0b1094Smrg	    right  = (int)CEIL(right);
7710e0b1094Smrg	    bottom = (int)FLOOR(bottom);
772120fad34Smrg	    top	   = (int)CEIL(top);
773c76ae52dSmrg
774c76ae52dSmrg	} else {
7750e0b1094Smrg	    left   = (int)FLOOR( glyphslot->metrics.horiBearingX );
7760e0b1094Smrg	    right  = (int)CEIL( glyphslot->metrics.horiBearingX + glyphslot->metrics.width );
777c76ae52dSmrg
7780e0b1094Smrg	    top    = (int)CEIL( glyphslot->metrics.horiBearingY );
7790e0b1094Smrg	    bottom = (int)FLOOR( glyphslot->metrics.horiBearingY - glyphslot->metrics.height );
780c76ae52dSmrg	}
781c76ae52dSmrg
782c76ae52dSmrg	/*
783c76ae52dSmrg	 * Clip charcell glyphs to the bounding box
784c76ae52dSmrg	 * XXX transformed?
785c76ae52dSmrg	 */
786120fad34Smrg	if (font->info.spacing >= FC_CHARCELL && !transform)
787c76ae52dSmrg	{
788c76ae52dSmrg	    if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
789c76ae52dSmrg	    {
790c76ae52dSmrg		if (TRUNC(bottom) > font->public.max_advance_width)
791c76ae52dSmrg		{
792c76ae52dSmrg		    int adjust;
7932836776bSmrg
794c76ae52dSmrg		    adjust = bottom - (font->public.max_advance_width << 6);
795c76ae52dSmrg		    if (adjust > top)
796c76ae52dSmrg			adjust = top;
797c76ae52dSmrg		    top -= adjust;
798c76ae52dSmrg		    bottom -= adjust;
799c76ae52dSmrg		}
800c76ae52dSmrg	    }
801c76ae52dSmrg	    else
802c76ae52dSmrg	    {
803c76ae52dSmrg		if (TRUNC(right) > font->public.max_advance_width)
804c76ae52dSmrg		{
805c76ae52dSmrg		    int adjust;
8062836776bSmrg
807c76ae52dSmrg		    adjust = right - (font->public.max_advance_width << 6);
808c76ae52dSmrg		    if (adjust > left)
809c76ae52dSmrg			adjust = left;
810c76ae52dSmrg		    left -= adjust;
811c76ae52dSmrg		    right -= adjust;
812c76ae52dSmrg		}
813c76ae52dSmrg	    }
814c76ae52dSmrg	}
815c76ae52dSmrg
816120fad34Smrg	glyph_transform = transform;
8172836776bSmrg	if ( glyphslot->format != FT_GLYPH_FORMAT_BITMAP )
8182836776bSmrg	{
8192836776bSmrg	    error = FT_Render_Glyph( face->glyph, mode );
8202836776bSmrg	    if (error)
8212836776bSmrg		continue;
822120fad34Smrg	    glyph_transform = False;
8232836776bSmrg	}
824c76ae52dSmrg
8252836776bSmrg	FT_Library_SetLcdFilter( _XftFTlibrary, FT_LCD_FILTER_NONE );
826c76ae52dSmrg
827c76ae52dSmrg	if (font->info.spacing >= FC_MONO)
828c76ae52dSmrg	{
829120fad34Smrg	    if (transform)
830c76ae52dSmrg	    {
831c76ae52dSmrg		if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
832c76ae52dSmrg		{
833c76ae52dSmrg		    vector.x = 0;
834c76ae52dSmrg		    vector.y = -face->size->metrics.max_advance;
835c76ae52dSmrg		}
836c76ae52dSmrg		else
837c76ae52dSmrg		{
838c76ae52dSmrg		    vector.x = face->size->metrics.max_advance;
839c76ae52dSmrg		    vector.y = 0;
840c76ae52dSmrg		}
841120fad34Smrg		FT_Vector_Transform(&vector, &font->info.matrix);
842120fad34Smrg		xftg->metrics.xOff = (short)(TRUNC(ROUND(vector.x)));
843a773ec55Smrg		xftg->metrics.yOff = (short)(-TRUNC(ROUND(vector.y)));
844c76ae52dSmrg	    }
845c76ae52dSmrg	    else
846c76ae52dSmrg	    {
847a773ec55Smrg		short maximum_x = (short)(font->public.max_advance_width);
848a773ec55Smrg		short maximum_y = (short)(-font->public.max_advance_width);
849a773ec55Smrg		short trimmed_x = (short)(TRUNC(ROUND(glyphslot->advance.x)));
850a773ec55Smrg		short trimmed_y = (short)(-TRUNC(ROUND(glyphslot->advance.y)));
851c76ae52dSmrg		if (font->info.load_flags & FT_LOAD_VERTICAL_LAYOUT)
852c76ae52dSmrg		{
853c76ae52dSmrg		    xftg->metrics.xOff = 0;
854a773ec55Smrg		    xftg->metrics.yOff = min(maximum_y,trimmed_y);
855c76ae52dSmrg		}
856c76ae52dSmrg		else
857c76ae52dSmrg		{
858a773ec55Smrg		    xftg->metrics.xOff = min(maximum_x,trimmed_x);
859c76ae52dSmrg		    xftg->metrics.yOff = 0;
860c76ae52dSmrg		}
861c76ae52dSmrg	    }
862c76ae52dSmrg	}
863c76ae52dSmrg	else
864c76ae52dSmrg	{
8650e0b1094Smrg	    xftg->metrics.xOff = (short)(TRUNC(ROUND(glyphslot->advance.x)));
8660e0b1094Smrg	    xftg->metrics.yOff = (short)(-TRUNC(ROUND(glyphslot->advance.y)));
867c76ae52dSmrg	}
868c76ae52dSmrg
8690e0b1094Smrg	/* compute the size of the final bitmap */
8702836776bSmrg	ftbit = &glyphslot->bitmap;
871c76ae52dSmrg
8720e0b1094Smrg	width = (int)ftbit->width;
8730e0b1094Smrg	height = (int)ftbit->rows;
874c76ae52dSmrg
875c76ae52dSmrg	if (XftDebug() & XFT_DBG_GLYPH)
876c76ae52dSmrg	{
877c76ae52dSmrg	    printf ("glyph %d:\n", (int) glyphindex);
878c76ae52dSmrg	    printf (" xywh (%d %d %d %d), trans (%d %d %d %d) wh (%d %d)\n",
879c76ae52dSmrg		    (int) glyphslot->metrics.horiBearingX,
880c76ae52dSmrg		    (int) glyphslot->metrics.horiBearingY,
881c76ae52dSmrg		    (int) glyphslot->metrics.width,
882c76ae52dSmrg		    (int) glyphslot->metrics.height,
883c76ae52dSmrg		    left, right, top, bottom,
884c76ae52dSmrg		    width, height);
885c76ae52dSmrg	    if (XftDebug() & XFT_DBG_GLYPHV)
886c76ae52dSmrg	    {
887c76ae52dSmrg		int		x, y;
888c76ae52dSmrg		unsigned char	*line;
889c76ae52dSmrg
8902836776bSmrg		line = ftbit->buffer;
8912836776bSmrg		if (ftbit->pitch < 0)
8922836776bSmrg		    line -= ftbit->pitch*(height-1);
8932836776bSmrg
8942836776bSmrg		for (y = 0; y < height; y++)
895c76ae52dSmrg		{
8962836776bSmrg		    if (font->info.antialias)
897c76ae52dSmrg		    {
8982836776bSmrg			static const char    den[] = { " .:;=+*#" };
8992836776bSmrg			for (x = 0; x < width; x++)
900c76ae52dSmrg			    printf ("%c", den[line[x] >> 5]);
901c76ae52dSmrg		    }
902c76ae52dSmrg		    else
903c76ae52dSmrg		    {
9042836776bSmrg			for (x = 0; x < width * 8; x++)
905c76ae52dSmrg			{
906120fad34Smrg			    printf ("%c", (line[x>>3] & (1 << (x & 7))) ? '#' : ' ');
907c76ae52dSmrg			}
908c76ae52dSmrg		    }
909c76ae52dSmrg		    printf ("|\n");
9102836776bSmrg		    line += ftbit->pitch;
911c76ae52dSmrg		}
912c76ae52dSmrg		printf ("\n");
913c76ae52dSmrg	    }
914c76ae52dSmrg	}
915c76ae52dSmrg
916120fad34Smrg	m3x3_uniform(m);
917120fad34Smrg	size = _compute_xrender_bitmap_size( &local, glyphslot, mode, glyph_transform ? &font->info.matrix : NULL, m );
9182836776bSmrg	if ( size < 0 )
9192836776bSmrg	    continue;
9202836776bSmrg
9210e0b1094Smrg	xftg->metrics.width  = (unsigned short)local.width;
9220e0b1094Smrg	xftg->metrics.height = (unsigned short)local.rows;
923120fad34Smrg	if (glyph_transform)
924120fad34Smrg	{
925120fad34Smrg	    m3x3 mi;
926120fad34Smrg
927120fad34Smrg	    m3x3_invert(m, mi);
928120fad34Smrg	    vector.x = - glyphslot->bitmap_left;
929120fad34Smrg	    vector.y =   glyphslot->bitmap_top;
930120fad34Smrg	    m3x3_transform(&vector, mi);
931120fad34Smrg	    xftg->metrics.x = (short)vector.x;
932120fad34Smrg	    xftg->metrics.y = (short)vector.y;
933120fad34Smrg	}
934120fad34Smrg	else
935120fad34Smrg	{
936120fad34Smrg	    xftg->metrics.x = (short)(- glyphslot->bitmap_left);
937120fad34Smrg	    xftg->metrics.y = (short)(  glyphslot->bitmap_top);
938120fad34Smrg	}
9392836776bSmrg
9402836776bSmrg	/*
9412836776bSmrg	 * If the glyph is relatively large (> 1% of server memory),
9422836776bSmrg	 * don't send it until necessary.
9432836776bSmrg	 */
944120fad34Smrg	if (!need_bitmaps && ((unsigned long) size > (info->max_glyph_memory / 100)))
9452836776bSmrg	    continue;
9462836776bSmrg
9472836776bSmrg	/*
9482836776bSmrg	 * Make sure there is enough buffer space for the glyph.
9492836776bSmrg	 */
9502836776bSmrg	if (size > bufSize)
9512836776bSmrg	{
9522836776bSmrg	    if (bufBitmap != bufLocal)
9532836776bSmrg		free (bufBitmap);
9540e0b1094Smrg	    bufBitmap = (unsigned char *) malloc ((size_t)size);
9552836776bSmrg	    if (!bufBitmap)
9562836776bSmrg		continue;
9572836776bSmrg	    bufSize = size;
9582836776bSmrg	}
9590e0b1094Smrg	memset (bufBitmap, 0, (size_t)size);
9602836776bSmrg
9612836776bSmrg	local.buffer = bufBitmap;
9622836776bSmrg
963120fad34Smrg	if (mode == FT_RENDER_MODE_NORMAL && glyph_transform)
964120fad34Smrg	    _scaled_fill_xrender_bitmap(&local, &glyphslot->bitmap, m);
965120fad34Smrg	else
966120fad34Smrg	    _fill_xrender_bitmap( &local, glyphslot, mode,
967120fad34Smrg				 (font->info.rgba == FC_RGBA_BGR ||
968120fad34Smrg				  font->info.rgba == FC_RGBA_VBGR) );
9692836776bSmrg
9702836776bSmrg	/*
9712836776bSmrg	 * Copy or convert into local buffer.
9722836776bSmrg	 */
9732836776bSmrg
974c76ae52dSmrg	/*
975c76ae52dSmrg	 * Use the glyph index as the wire encoding; it
976c76ae52dSmrg	 * might be more efficient for some locales to map
977c76ae52dSmrg	 * these by first usage to smaller values, but that
978c76ae52dSmrg	 * would require persistently storing the map when
979c76ae52dSmrg	 * glyphs were freed.
980c76ae52dSmrg	 */
981c76ae52dSmrg	glyph = (Glyph) glyphindex;
982c76ae52dSmrg
983120fad34Smrg	if (xftg->picture)
984120fad34Smrg	{
985120fad34Smrg	    XRenderFreePicture(dpy, xftg->picture);
986120fad34Smrg	    xftg->picture = 0;
987120fad34Smrg	}
988120fad34Smrg	xftg->glyph_memory = (size_t)size + font->sizeof_glyph;
9892836776bSmrg	if (font->format)
990c76ae52dSmrg	{
9912836776bSmrg	    if (!font->glyphset)
9922836776bSmrg		font->glyphset = XRenderCreateGlyphSet (dpy, font->format);
9932836776bSmrg	    if ( mode == FT_RENDER_MODE_MONO )
994c76ae52dSmrg	    {
9952836776bSmrg		/* swap bits in each byte */
9962836776bSmrg		if (BitmapBitOrder (dpy) != MSBFirst)
997c76ae52dSmrg		{
9982836776bSmrg		    unsigned char   *line = (unsigned char*)bufBitmap;
9992836776bSmrg		    int		    i = size;
10002836776bSmrg
10012836776bSmrg		    while (i--)
1002c76ae52dSmrg		    {
10032836776bSmrg			int c = *line;
10042836776bSmrg			c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
10052836776bSmrg			c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
10062836776bSmrg			c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
10070e0b1094Smrg			*line++ = (unsigned char)c;
1008c76ae52dSmrg		    }
1009c76ae52dSmrg		}
1010c76ae52dSmrg	    }
1011120fad34Smrg	    else if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA || mode != FT_RENDER_MODE_NORMAL)
1012c76ae52dSmrg	    {
10132836776bSmrg		/* invert ARGB <=> BGRA */
1014c76ae52dSmrg		if (ImageByteOrder (dpy) != XftNativeByteOrder ())
10152836776bSmrg		    XftSwapCARD32 ((CARD32 *) bufBitmap, size >> 2);
1016c76ae52dSmrg	    }
1017120fad34Smrg
1018120fad34Smrg	    if (glyphslot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA)
1019120fad34Smrg	    {
1020120fad34Smrg		Pixmap pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), local.width, local.rows, 32);
1021120fad34Smrg		GC gc = XCreateGC(dpy, pixmap, 0, NULL);
1022120fad34Smrg		XImage image = {
1023120fad34Smrg		    (int) local.width, (int) local.rows, 0, ZPixmap, (char *)bufBitmap,
1024120fad34Smrg		    dpy->byte_order, dpy->bitmap_unit, dpy->bitmap_bit_order, 32,
1025120fad34Smrg		    32, (int) (local.width * 4 - (unsigned) local.pitch), 32,
1026120fad34Smrg		    0, 0, 0, NULL, { NULL }
1027120fad34Smrg		};
1028120fad34Smrg
1029120fad34Smrg		XInitImage(&image);
1030120fad34Smrg		XPutImage(dpy, pixmap, gc, &image, 0, 0, 0, 0, local.width, local.rows);
1031120fad34Smrg		xftg->picture = XRenderCreatePicture(dpy, pixmap, font->format, 0, NULL);
1032120fad34Smrg
1033120fad34Smrg		XFreeGC(dpy, gc);
1034120fad34Smrg		XFreePixmap(dpy, pixmap);
1035120fad34Smrg		/*
1036120fad34Smrg		 * Record 256 times higher memory pressure for unrotated
1037120fad34Smrg		 * pictures, and maximum for rotated pictures.
1038120fad34Smrg		 */
1039120fad34Smrg		if (font->info.matrix.xy || font->info.matrix.yx)
1040120fad34Smrg		    xftg->glyph_memory += font->max_glyph_memory - (unsigned long) size;
1041120fad34Smrg		else
1042120fad34Smrg		    xftg->glyph_memory += (size_t)size * 255;
1043120fad34Smrg	    }
1044120fad34Smrg	    else
1045120fad34Smrg		XRenderAddGlyphs (dpy, font->glyphset, &glyph,
1046120fad34Smrg				  &xftg->metrics, 1,
1047120fad34Smrg				  (char *) bufBitmap, size);
1048c76ae52dSmrg	}
1049c76ae52dSmrg	else
1050c76ae52dSmrg	{
10512836776bSmrg	    if (size)
1052c76ae52dSmrg	    {
10530e0b1094Smrg		xftg->bitmap = malloc ((size_t)size);
10542836776bSmrg		if (xftg->bitmap)
10550e0b1094Smrg		    memcpy (xftg->bitmap, bufBitmap, (size_t)size);
1056c76ae52dSmrg	    }
1057c76ae52dSmrg	    else
10582836776bSmrg		xftg->bitmap = NULL;
1059c76ae52dSmrg	}
10602836776bSmrg
1061c76ae52dSmrg	font->glyph_memory += xftg->glyph_memory;
1062c76ae52dSmrg	info->glyph_memory += xftg->glyph_memory;
1063c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHE)
1064c76ae52dSmrg	    _XftFontValidateMemory (dpy, pub);
1065c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHEV)
1066120fad34Smrg	    printf ("Caching glyph 0x%x size %lu\n", glyphindex,
1067c76ae52dSmrg		    xftg->glyph_memory);
1068120fad34Smrg
1069120fad34Smrg	if (font->track_mem_usage) {
1070120fad34Smrg	    XftGlyphUsage *xuse = (XftGlyphUsage *) xftg;
1071120fad34Smrg
1072120fad34Smrg	    if (font->newest == FT_UINT_MAX) {
1073120fad34Smrg		xuse->older = glyphindex;
1074120fad34Smrg	        xuse->newer = glyphindex;
1075120fad34Smrg		if (XftDebug() & XFT_DBG_USAGE)
1076120fad34Smrg		    printf("alloc %p -> %d: %p USE %d.%d\n",
1077120fad34Smrg			    (void *) font, glyphindex,
1078120fad34Smrg			    (void *) xuse, xuse->older, xuse->newer);
1079120fad34Smrg	    } else {
1080120fad34Smrg		XftGlyphUsage *xnew;
1081120fad34Smrg		XftGlyphUsage *xold;
1082120fad34Smrg
1083120fad34Smrg		assert(font->glyphs[font->newest] != NULL);
1084120fad34Smrg		xnew = (XftGlyphUsage *) font->glyphs[font->newest];
1085120fad34Smrg
1086120fad34Smrg		assert(font->glyphs[xnew->newer] != NULL);
1087120fad34Smrg		xold = (XftGlyphUsage *) font->glyphs[xnew->newer];
1088120fad34Smrg
1089120fad34Smrg		xuse->older = font->newest;
1090120fad34Smrg		xuse->newer = xnew->newer;
1091120fad34Smrg		xnew->newer = glyphindex;
1092120fad34Smrg		xold->older = glyphindex;
1093120fad34Smrg		if (XftDebug() & XFT_DBG_USAGE)
1094120fad34Smrg		    printf("alloc %p -> %d: %p USE %d.%d, %p NEW %d.%d %p OLD %d.%d\n",
1095120fad34Smrg			    (void *) font, glyphindex,
1096120fad34Smrg			    (void *) xuse, xuse->older, xuse->newer,
1097120fad34Smrg			    (void *) xnew, xnew->older, xnew->newer,
1098120fad34Smrg			    (void *) xold, xold->older, xold->newer);
1099120fad34Smrg	    }
1100120fad34Smrg
1101120fad34Smrg	    font->newest = glyphindex;
1102120fad34Smrg	    font->total_inuse++;
1103120fad34Smrg	    if (XftDebug() & XFT_DBG_USAGE)
1104120fad34Smrg		_XftValidateGlyphUsage(font);
1105120fad34Smrg	}
1106c76ae52dSmrg    }
1107c76ae52dSmrg    if (bufBitmap != bufLocal)
1108c76ae52dSmrg	free (bufBitmap);
1109c76ae52dSmrg    XftUnlockFace (&font->public);
1110c76ae52dSmrg}
1111c76ae52dSmrg
1112c76ae52dSmrg_X_EXPORT void
1113c76ae52dSmrgXftFontUnloadGlyphs (Display		*dpy,
1114c76ae52dSmrg		     XftFont		*pub,
1115c76ae52dSmrg		     _Xconst FT_UInt	*glyphs,
1116c76ae52dSmrg		     int		nglyph)
1117c76ae52dSmrg{
1118c76ae52dSmrg    XftDisplayInfo  *info = _XftDisplayInfoGet (dpy, False);
1119c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
1120c76ae52dSmrg    XftGlyph	    *xftg;
1121c76ae52dSmrg    FT_UInt	    glyphindex;
1122c76ae52dSmrg    Glyph	    glyphBuf[1024];
1123c76ae52dSmrg    int		    nused;
11242836776bSmrg
1125c76ae52dSmrg    nused = 0;
1126c76ae52dSmrg    while (nglyph--)
1127c76ae52dSmrg    {
1128c76ae52dSmrg	glyphindex = *glyphs++;
1129c76ae52dSmrg	xftg = font->glyphs[glyphindex];
1130c76ae52dSmrg	if (!xftg)
1131c76ae52dSmrg	    continue;
1132c76ae52dSmrg	if (xftg->glyph_memory)
1133c76ae52dSmrg	{
1134120fad34Smrg	    if (XftDebug() & XFT_DBG_CACHEV)
1135120fad34Smrg		printf ("Uncaching glyph 0x%x size %lu\n",
1136120fad34Smrg			glyphindex, xftg->glyph_memory);
1137c76ae52dSmrg	    if (font->format)
1138c76ae52dSmrg	    {
1139120fad34Smrg		if (xftg->picture)
1140120fad34Smrg		    XRenderFreePicture(dpy, xftg->picture);
1141120fad34Smrg		else if (font->glyphset)
1142c76ae52dSmrg		{
1143c76ae52dSmrg		    glyphBuf[nused++] = (Glyph) glyphindex;
1144c76ae52dSmrg		    if (nused == sizeof (glyphBuf) / sizeof (glyphBuf[0]))
1145c76ae52dSmrg		    {
1146c76ae52dSmrg			XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
1147c76ae52dSmrg			nused = 0;
1148c76ae52dSmrg		    }
1149c76ae52dSmrg		}
1150c76ae52dSmrg	    }
1151120fad34Smrg	    else if (xftg->bitmap)
1152120fad34Smrg		free (xftg->bitmap);
1153c76ae52dSmrg	    font->glyph_memory -= xftg->glyph_memory;
1154c76ae52dSmrg	    if (info)
1155c76ae52dSmrg		info->glyph_memory -= xftg->glyph_memory;
1156c76ae52dSmrg	}
1157120fad34Smrg
1158120fad34Smrg	if (font->track_mem_usage) {
1159120fad34Smrg	    XftGlyphUsage *xuse = (XftGlyphUsage *) xftg;
1160120fad34Smrg	    XftGlyphUsage *xtmp;
1161120fad34Smrg
1162120fad34Smrg	    if (XftDebug() & XFT_DBG_USAGE)
1163120fad34Smrg		printf("free %p -> %p USE %d.%d\n",
1164120fad34Smrg		       (void *) font, (void *) xuse, xuse->older, xuse->newer);
1165120fad34Smrg
1166120fad34Smrg	    if (xuse->older != FT_UINT_MAX) {
1167120fad34Smrg		xtmp = (XftGlyphUsage *) font->glyphs[xuse->older];
1168120fad34Smrg		if (xtmp != NULL) {
1169120fad34Smrg		    /* update link around to oldest glyph */
1170120fad34Smrg		    xtmp->newer = xuse->newer;
1171120fad34Smrg		}
1172120fad34Smrg		if (font->newest == glyphindex) {
1173120fad34Smrg		    if (font->newest == xuse->older)
1174120fad34Smrg			font->newest = FT_UINT_MAX;
1175120fad34Smrg		    else
1176120fad34Smrg			font->newest = xuse->older;
1177120fad34Smrg		}
1178120fad34Smrg	    }
1179120fad34Smrg	    if (xuse->newer != FT_UINT_MAX) {
1180120fad34Smrg		xtmp = (XftGlyphUsage *) font->glyphs[xuse->newer];
1181120fad34Smrg		if (xtmp != NULL) {
1182120fad34Smrg		    /* update link around to newest glyph */
1183120fad34Smrg		    xtmp->older = xuse->older;
1184120fad34Smrg		}
1185120fad34Smrg	    }
1186120fad34Smrg	    if (font->total_inuse) {
1187120fad34Smrg		font->total_inuse--;
1188120fad34Smrg	    } else {
1189120fad34Smrg		fprintf (stderr, "Xft: glyph count error\n");
1190120fad34Smrg	    }
1191120fad34Smrg	    if (XftDebug() & XFT_DBG_USAGE)
1192120fad34Smrg		_XftValidateGlyphUsage(font);
1193120fad34Smrg	}
1194120fad34Smrg
1195c76ae52dSmrg	free (xftg);
1196120fad34Smrg	XftMemFree (XFT_MEM_GLYPH, font->sizeof_glyph);
11970d590c07Smrg	font->glyphs[glyphindex] = NULL;
11982836776bSmrg    }
1199c76ae52dSmrg    if (font->glyphset && nused)
1200c76ae52dSmrg	XRenderFreeGlyphs (dpy, font->glyphset, glyphBuf, nused);
1201c76ae52dSmrg}
1202c76ae52dSmrg
1203c76ae52dSmrg_X_EXPORT FcBool
1204c76ae52dSmrgXftFontCheckGlyph (Display	*dpy,
1205c76ae52dSmrg		   XftFont	*pub,
1206c76ae52dSmrg		   FcBool	need_bitmaps,
1207c76ae52dSmrg		   FT_UInt	glyph,
1208c76ae52dSmrg		   FT_UInt	*missing,
1209c76ae52dSmrg		   int		*nmissing)
1210c76ae52dSmrg{
1211c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
1212c76ae52dSmrg    XftGlyph	    *xftg;
1213c76ae52dSmrg    int		    n;
12142836776bSmrg
1215c76ae52dSmrg    if (glyph >= font->num_glyphs)
1216c76ae52dSmrg	return FcFalse;
1217c76ae52dSmrg    xftg = font->glyphs[glyph];
1218c76ae52dSmrg    if (!xftg || (need_bitmaps && !xftg->glyph_memory))
1219c76ae52dSmrg    {
1220c76ae52dSmrg	if (!xftg)
1221c76ae52dSmrg	{
1222120fad34Smrg	    xftg = malloc (font->sizeof_glyph);
1223c76ae52dSmrg	    if (!xftg)
1224c76ae52dSmrg		return FcFalse;
1225120fad34Smrg	    XftMemAlloc (XFT_MEM_GLYPH, font->sizeof_glyph);
1226120fad34Smrg
12270d590c07Smrg	    xftg->bitmap = NULL;
1228c76ae52dSmrg	    xftg->glyph_memory = 0;
1229120fad34Smrg	    xftg->picture = 0;
1230c76ae52dSmrg	    font->glyphs[glyph] = xftg;
1231120fad34Smrg
1232120fad34Smrg	    if (font->track_mem_usage) {
1233120fad34Smrg		XftGlyphUsage *xuse = (XftGlyphUsage *) xftg;
1234120fad34Smrg		xuse->older = FT_UINT_MAX;
1235120fad34Smrg		xuse->newer = FT_UINT_MAX;
1236120fad34Smrg	    }
1237c76ae52dSmrg	}
1238c76ae52dSmrg	n = *nmissing;
1239c76ae52dSmrg	missing[n++] = glyph;
1240c76ae52dSmrg	if (n == XFT_NMISSING)
1241c76ae52dSmrg	{
1242c76ae52dSmrg	    XftFontLoadGlyphs (dpy, pub, need_bitmaps, missing, n);
1243c76ae52dSmrg	    n = 0;
1244c76ae52dSmrg	}
1245c76ae52dSmrg	*nmissing = n;
1246c76ae52dSmrg	return FcTrue;
1247c76ae52dSmrg    }
1248120fad34Smrg
1249120fad34Smrg    /*
1250120fad34Smrg     * Make unloading faster by moving newly-referenced glyphs to the front
1251120fad34Smrg     * of the list, leaving the less-used glyphs on the end.
1252a773ec55Smrg     *
1253a773ec55Smrg     * If the glyph is zero, the older/newer data may not have been set.
1254120fad34Smrg     */
1255a773ec55Smrg    if (glyph != 0
1256a773ec55Smrg     && font->track_mem_usage
1257120fad34Smrg     && font->total_inuse > 10
1258120fad34Smrg     && font->newest != FT_UINT_MAX
1259120fad34Smrg     && font->newest != glyph)
1260120fad34Smrg    {
1261120fad34Smrg	XftGlyphUsage *xuse = (XftGlyphUsage *) xftg;
1262120fad34Smrg	XftGlyphUsage *xtmp = (XftGlyphUsage *) font->glyphs[font->newest];
1263120fad34Smrg	XftGlyphUsage *xold;
1264120fad34Smrg	XftGlyphUsage *xnew;
1265120fad34Smrg
1266120fad34Smrg	/* delink */
1267120fad34Smrg	xold = (XftGlyphUsage *) font->glyphs[xuse->older];
1268120fad34Smrg	xnew = (XftGlyphUsage *) font->glyphs[xuse->newer];
1269120fad34Smrg	assert(xold != NULL);
1270120fad34Smrg	assert(xnew != NULL);
1271120fad34Smrg	xold->newer = xuse->newer;
1272120fad34Smrg	xnew->older = xuse->older;
1273120fad34Smrg
1274120fad34Smrg	/* relink */
1275120fad34Smrg	xnew = (XftGlyphUsage *) font->glyphs[xtmp->newer];
1276120fad34Smrg	assert(xnew != NULL);
1277120fad34Smrg	xnew->older = glyph;
1278120fad34Smrg	xuse->older = font->newest;
1279120fad34Smrg	xuse->newer = xtmp->newer;
1280120fad34Smrg	xtmp->newer = glyph;
1281120fad34Smrg
1282120fad34Smrg	font->newest = glyph;
1283120fad34Smrg    }
1284120fad34Smrg    return FcFalse;
1285c76ae52dSmrg}
1286c76ae52dSmrg
1287c76ae52dSmrg_X_EXPORT FcBool
1288120fad34SmrgXftCharExists (Display	    *dpy _X_UNUSED,
1289c76ae52dSmrg	       XftFont	    *pub,
1290120fad34Smrg	       FcChar32	     ucs4)
1291c76ae52dSmrg{
1292c76ae52dSmrg    if (pub->charset)
1293c76ae52dSmrg	return FcCharSetHasChar (pub->charset, ucs4);
1294c76ae52dSmrg    return FcFalse;
1295c76ae52dSmrg}
1296c76ae52dSmrg
1297c76ae52dSmrg#define Missing	    ((FT_UInt) ~0)
1298c76ae52dSmrg
1299c76ae52dSmrg_X_EXPORT FT_UInt
13002836776bSmrgXftCharIndex (Display	    *dpy,
1301c76ae52dSmrg	      XftFont	    *pub,
1302c76ae52dSmrg	      FcChar32	    ucs4)
1303c76ae52dSmrg{
1304c76ae52dSmrg    XftFontInt	*font = (XftFontInt *) pub;
1305c76ae52dSmrg    FcChar32	ent, offset;
1306c76ae52dSmrg    FT_Face	face;
13072836776bSmrg
1308c76ae52dSmrg    if (!font->hash_value)
1309c76ae52dSmrg	return 0;
1310c76ae52dSmrg
13110e0b1094Smrg    ent = ucs4 % (FcChar32)font->hash_value;
1312c76ae52dSmrg    offset = 0;
1313c76ae52dSmrg    while (font->hash_table[ent].ucs4 != ucs4)
1314c76ae52dSmrg    {
1315c76ae52dSmrg	if (font->hash_table[ent].ucs4 == (FcChar32) ~0)
1316c76ae52dSmrg	{
1317c76ae52dSmrg	    if (!XftCharExists (dpy, pub, ucs4))
1318c76ae52dSmrg		return 0;
1319c76ae52dSmrg	    face  = XftLockFace (pub);
1320c76ae52dSmrg	    if (!face)
1321c76ae52dSmrg		return 0;
1322c76ae52dSmrg	    font->hash_table[ent].ucs4 = ucs4;
1323c76ae52dSmrg	    font->hash_table[ent].glyph = FcFreeTypeCharIndex (face, ucs4);
1324c76ae52dSmrg	    XftUnlockFace (pub);
1325c76ae52dSmrg	    break;
1326c76ae52dSmrg	}
1327c76ae52dSmrg	if (!offset)
1328c76ae52dSmrg	{
13290e0b1094Smrg	    offset = ucs4 % (FcChar32)font->rehash_value;
1330c76ae52dSmrg	    if (!offset)
1331c76ae52dSmrg		offset = 1;
1332c76ae52dSmrg	}
1333c76ae52dSmrg	ent = ent + offset;
1334120fad34Smrg	if (ent >= (FcChar32)font->hash_value)
13350e0b1094Smrg	    ent -= (FcChar32)font->hash_value;
1336c76ae52dSmrg    }
1337c76ae52dSmrg    return font->hash_table[ent].glyph;
1338c76ae52dSmrg}
1339c76ae52dSmrg
1340c76ae52dSmrg/*
1341120fad34Smrg * Remove glyph(s) from the font to reduce memory-usage.
1342c76ae52dSmrg */
1343c76ae52dSmrg_X_HIDDEN void
1344c76ae52dSmrg_XftFontUncacheGlyph (Display *dpy, XftFont *pub)
1345c76ae52dSmrg{
1346c76ae52dSmrg    XftFontInt	    *font = (XftFontInt *) pub;
1347c76ae52dSmrg    unsigned long   glyph_memory;
1348c76ae52dSmrg    FT_UInt	    glyphindex;
1349c76ae52dSmrg    XftGlyph	    *xftg;
13502836776bSmrg
1351c76ae52dSmrg    if (!font->glyph_memory)
1352c76ae52dSmrg	return;
1353120fad34Smrg
1354120fad34Smrg    if (XftDebug() & XFT_DBG_CACHE)
1355120fad34Smrg	_XftFontValidateMemory (dpy, pub);
1356120fad34Smrg
1357120fad34Smrg    if (font->track_mem_usage)
1358c76ae52dSmrg    {
1359120fad34Smrg	/*
1360120fad34Smrg	 * Remove the oldest glyph from the font.
1361120fad34Smrg	 */
1362120fad34Smrg	if (font->newest != FT_UINT_MAX) {
1363120fad34Smrg	    XftGlyphUsage *xuse = (XftGlyphUsage *) font->glyphs[font->newest];
1364120fad34Smrg	    if ((glyphindex = xuse->newer) != FT_UINT_MAX)
1365120fad34Smrg		XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1);
1366120fad34Smrg	}
1367120fad34Smrg    }
1368120fad34Smrg    else if (font->use_free_glyphs)
1369120fad34Smrg    {
1370120fad34Smrg	/*
1371120fad34Smrg	 * Pick a random glyph from the font and remove it from the cache
1372120fad34Smrg	 */
13730e0b1094Smrg	glyph_memory = ((unsigned long)rand() % font->glyph_memory);
1374120fad34Smrg	for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
1375120fad34Smrg	{
1376120fad34Smrg	    xftg = font->glyphs[glyphindex];
1377120fad34Smrg	    if (xftg)
1378120fad34Smrg	    {
1379120fad34Smrg		if (xftg->glyph_memory > glyph_memory)
1380120fad34Smrg		{
1381120fad34Smrg		    XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1);
1382120fad34Smrg		    break;
1383120fad34Smrg		}
1384120fad34Smrg		glyph_memory -= xftg->glyph_memory;
1385120fad34Smrg	    }
1386120fad34Smrg	}
1387c76ae52dSmrg    }
1388c76ae52dSmrg    else
1389c76ae52dSmrg    {
1390120fad34Smrg	/*
1391120fad34Smrg	 * Free all glyphs, since they are part of a set.
1392120fad34Smrg	 */
1393c76ae52dSmrg	if (font->glyphset)
1394c76ae52dSmrg	{
1395c76ae52dSmrg	    XRenderFreeGlyphSet (dpy, font->glyphset);
1396c76ae52dSmrg	    font->glyphset = 0;
1397c76ae52dSmrg	}
1398120fad34Smrg	for (glyphindex = 0; glyphindex < font->num_glyphs; glyphindex++)
1399c76ae52dSmrg	{
1400120fad34Smrg	    xftg = font->glyphs[glyphindex];
1401120fad34Smrg	    if (xftg)
1402c76ae52dSmrg	    {
1403120fad34Smrg		if (xftg->glyph_memory > 0)
1404120fad34Smrg		{
1405120fad34Smrg		    XftFontUnloadGlyphs (dpy, pub, &glyphindex, 1);
1406120fad34Smrg		}
1407c76ae52dSmrg	    }
1408c76ae52dSmrg	}
1409c76ae52dSmrg    }
1410120fad34Smrg
1411c76ae52dSmrg    if (XftDebug() & XFT_DBG_CACHE)
1412c76ae52dSmrg	_XftFontValidateMemory (dpy, pub);
1413c76ae52dSmrg}
1414c76ae52dSmrg
1415c76ae52dSmrg_X_HIDDEN void
1416c76ae52dSmrg_XftFontManageMemory (Display *dpy, XftFont *pub)
1417c76ae52dSmrg{
1418c76ae52dSmrg    XftFontInt	*font = (XftFontInt *) pub;
1419c76ae52dSmrg
1420c76ae52dSmrg    if (font->max_glyph_memory)
1421c76ae52dSmrg    {
1422c76ae52dSmrg	if (XftDebug() & XFT_DBG_CACHE)
1423c76ae52dSmrg	{
1424c76ae52dSmrg	    if (font->glyph_memory > font->max_glyph_memory)
1425120fad34Smrg		printf ("Reduce memory for font 0x%lx from %lu to %lu\n",
1426c76ae52dSmrg			font->glyphset ? font->glyphset : (unsigned long) font,
1427c76ae52dSmrg			font->glyph_memory, font->max_glyph_memory);
1428c76ae52dSmrg	}
1429c76ae52dSmrg	while (font->glyph_memory > font->max_glyph_memory)
1430c76ae52dSmrg	    _XftFontUncacheGlyph (dpy, pub);
1431c76ae52dSmrg    }
1432c76ae52dSmrg    _XftDisplayManageMemory (dpy);
1433c76ae52dSmrg}
1434