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"
242836776bSmrg
25c76ae52dSmrg_X_EXPORT void
26c76ae52dSmrgXftGlyphExtents (Display	    *dpy,
27c76ae52dSmrg		 XftFont	    *pub,
28c76ae52dSmrg		 _Xconst FT_UInt    *glyphs,
29c76ae52dSmrg		 int		    nglyphs,
30c76ae52dSmrg		 XGlyphInfo	    *extents)
31c76ae52dSmrg{
32c76ae52dSmrg    XftFontInt		*font = (XftFontInt *) pub;
33c76ae52dSmrg    FT_UInt		missing[XFT_NMISSING];
34c76ae52dSmrg    int			nmissing;
35c76ae52dSmrg    int			n;
36c76ae52dSmrg    _Xconst FT_UInt	*g;
37c76ae52dSmrg    FT_UInt		glyph;
38c76ae52dSmrg    XftGlyph		*xftg;
39c76ae52dSmrg    FcBool		glyphs_loaded;
40c76ae52dSmrg    int			x, y;
41c76ae52dSmrg    int			left, right, top, bottom;
42c76ae52dSmrg    int			overall_left, overall_right;
43c76ae52dSmrg    int			overall_top, overall_bottom;
442836776bSmrg
45c76ae52dSmrg    g = glyphs;
46c76ae52dSmrg    n = nglyphs;
47c76ae52dSmrg    nmissing = 0;
48c76ae52dSmrg    glyphs_loaded = FcFalse;
49c76ae52dSmrg    while (n--)
50c76ae52dSmrg	if (XftFontCheckGlyph (dpy, pub, FcFalse, *g++, missing, &nmissing))
51c76ae52dSmrg	    glyphs_loaded = FcTrue;
52c76ae52dSmrg    if (nmissing)
53c76ae52dSmrg	XftFontLoadGlyphs (dpy, pub, FcFalse, missing, nmissing);
54c76ae52dSmrg    g = glyphs;
55c76ae52dSmrg    n = nglyphs;
560d590c07Smrg    xftg = NULL;
57c76ae52dSmrg    while (n)
58c76ae52dSmrg    {
59c76ae52dSmrg	glyph = *g++;
60c76ae52dSmrg	n--;
61c76ae52dSmrg	if (glyph < font->num_glyphs &&
62c76ae52dSmrg	    (xftg = font->glyphs[glyph]))
63c76ae52dSmrg	    break;
64c76ae52dSmrg    }
65c76ae52dSmrg    if (n == 0)
66c76ae52dSmrg    {
67c76ae52dSmrg	if (xftg)
68c76ae52dSmrg	    *extents = xftg->metrics;
69c76ae52dSmrg	else
70c76ae52dSmrg	    memset (extents, '\0', sizeof (*extents));
71c76ae52dSmrg    }
72c76ae52dSmrg    else
73c76ae52dSmrg    {
74c76ae52dSmrg	x = 0;
75c76ae52dSmrg	y = 0;
76c76ae52dSmrg	overall_left = x - xftg->metrics.x;
77c76ae52dSmrg	overall_top = y - xftg->metrics.y;
78c76ae52dSmrg	overall_right = overall_left + (int) xftg->metrics.width;
79c76ae52dSmrg	overall_bottom = overall_top + (int) xftg->metrics.height;
80c76ae52dSmrg	x += xftg->metrics.xOff;
81c76ae52dSmrg	y += xftg->metrics.yOff;
82c76ae52dSmrg	while (n--)
83c76ae52dSmrg	{
84c76ae52dSmrg	    glyph = *g++;
85c76ae52dSmrg	    if (glyph < font->num_glyphs && (xftg = font->glyphs[glyph]))
86c76ae52dSmrg	    {
87c76ae52dSmrg		left = x - xftg->metrics.x;
88c76ae52dSmrg		top = y - xftg->metrics.y;
89c76ae52dSmrg		right = left + (int) xftg->metrics.width;
90c76ae52dSmrg		bottom = top + (int) xftg->metrics.height;
91c76ae52dSmrg		if (left < overall_left)
92c76ae52dSmrg		    overall_left = left;
93c76ae52dSmrg		if (top < overall_top)
94c76ae52dSmrg		    overall_top = top;
95c76ae52dSmrg		if (right > overall_right)
96c76ae52dSmrg		    overall_right = right;
97c76ae52dSmrg		if (bottom > overall_bottom)
98c76ae52dSmrg		    overall_bottom = bottom;
99c76ae52dSmrg		x += xftg->metrics.xOff;
100c76ae52dSmrg		y += xftg->metrics.yOff;
101c76ae52dSmrg	    }
102c76ae52dSmrg	}
10384febdacSmrg	extents->x = (short)(-overall_left);
10484febdacSmrg	extents->y = (short)(-overall_top);
10584febdacSmrg	extents->width = (unsigned short)(overall_right - overall_left);
10684febdacSmrg	extents->height = (unsigned short)(overall_bottom - overall_top);
10784febdacSmrg	extents->xOff = (short)x;
10884febdacSmrg	extents->yOff = (short)y;
109c76ae52dSmrg    }
110c76ae52dSmrg    if (glyphs_loaded)
111c76ae52dSmrg	_XftFontManageMemory (dpy, pub);
112c76ae52dSmrg}
113c76ae52dSmrg
114c76ae52dSmrg#define NUM_LOCAL   1024
115c76ae52dSmrg
116c76ae52dSmrg_X_EXPORT void
117c76ae52dSmrgXftTextExtents8 (Display	    *dpy,
118c76ae52dSmrg		 XftFont	    *pub,
1192836776bSmrg		 _Xconst FcChar8    *string,
120c76ae52dSmrg		 int		    len,
121c76ae52dSmrg		 XGlyphInfo	    *extents)
122c76ae52dSmrg{
123c76ae52dSmrg    FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
124c76ae52dSmrg    int		    i;
125c76ae52dSmrg
1268a91a6ebSmrg    if (len < 0)
127de3c0529Smrg	return;
128de3c0529Smrg
129c76ae52dSmrg    if (len <= NUM_LOCAL)
1308a91a6ebSmrg	*(glyphs = glyphs_local) = 0;
131c76ae52dSmrg    else
132c76ae52dSmrg    {
133de3c0529Smrg	glyphs = AllocUIntArray (len);
134c76ae52dSmrg	if (!glyphs)
135c76ae52dSmrg	{
136c76ae52dSmrg	    memset (extents, '\0', sizeof (XGlyphInfo));
137c76ae52dSmrg	    return;
138c76ae52dSmrg	}
139c76ae52dSmrg    }
140c76ae52dSmrg    for (i = 0; i < len; i++)
141c76ae52dSmrg	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
142c76ae52dSmrg    XftGlyphExtents (dpy, pub, glyphs, len, extents);
143c76ae52dSmrg    if (glyphs != glyphs_local)
144c76ae52dSmrg	free (glyphs);
145c76ae52dSmrg}
146c76ae52dSmrg
147c76ae52dSmrg_X_EXPORT void
148c76ae52dSmrgXftTextExtents16 (Display	    *dpy,
149c76ae52dSmrg		  XftFont	    *pub,
1502836776bSmrg		  _Xconst FcChar16  *string,
151c76ae52dSmrg		  int		    len,
152c76ae52dSmrg		  XGlyphInfo	    *extents)
153c76ae52dSmrg{
154c76ae52dSmrg    FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
155c76ae52dSmrg    int		    i;
156c76ae52dSmrg
1578a91a6ebSmrg    if (len < 0)
158de3c0529Smrg	return;
159de3c0529Smrg
160c76ae52dSmrg    if (len <= NUM_LOCAL)
1618a91a6ebSmrg	*(glyphs = glyphs_local) = 0;
162c76ae52dSmrg    else
163c76ae52dSmrg    {
164de3c0529Smrg	glyphs = AllocUIntArray (len);
165c76ae52dSmrg	if (!glyphs)
166c76ae52dSmrg	{
167c76ae52dSmrg	    memset (extents, '\0', sizeof (XGlyphInfo));
168c76ae52dSmrg	    return;
169c76ae52dSmrg	}
170c76ae52dSmrg    }
171c76ae52dSmrg    for (i = 0; i < len; i++)
172c76ae52dSmrg	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
173c76ae52dSmrg    XftGlyphExtents (dpy, pub, glyphs, len, extents);
174c76ae52dSmrg    if (glyphs != glyphs_local)
175c76ae52dSmrg	free (glyphs);
176c76ae52dSmrg}
177c76ae52dSmrg
178c76ae52dSmrg_X_EXPORT void
179c76ae52dSmrgXftTextExtents32 (Display	    *dpy,
180c76ae52dSmrg		  XftFont	    *pub,
1812836776bSmrg		  _Xconst FcChar32  *string,
182c76ae52dSmrg		  int		    len,
183c76ae52dSmrg		  XGlyphInfo	    *extents)
184c76ae52dSmrg{
185c76ae52dSmrg    FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
186c76ae52dSmrg    int		    i;
187c76ae52dSmrg
1888a91a6ebSmrg    if (len < 0)
189de3c0529Smrg	return;
190de3c0529Smrg
191c76ae52dSmrg    if (len <= NUM_LOCAL)
1928a91a6ebSmrg	*(glyphs = glyphs_local) = 0;
193c76ae52dSmrg    else
194c76ae52dSmrg    {
195de3c0529Smrg	glyphs = AllocUIntArray (len);
196c76ae52dSmrg	if (!glyphs)
197c76ae52dSmrg	{
198c76ae52dSmrg	    memset (extents, '\0', sizeof (XGlyphInfo));
199c76ae52dSmrg	    return;
200c76ae52dSmrg	}
201c76ae52dSmrg    }
202c76ae52dSmrg    for (i = 0; i < len; i++)
203c76ae52dSmrg	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
204c76ae52dSmrg    XftGlyphExtents (dpy, pub, glyphs, len, extents);
205c76ae52dSmrg    if (glyphs != glyphs_local)
206c76ae52dSmrg	free (glyphs);
207c76ae52dSmrg}
208c76ae52dSmrg
209c76ae52dSmrg_X_EXPORT void
210c76ae52dSmrgXftTextExtentsUtf8 (Display	    *dpy,
211c76ae52dSmrg		    XftFont	    *pub,
2122836776bSmrg		    _Xconst FcChar8 *string,
213c76ae52dSmrg		    int		    len,
214c76ae52dSmrg		    XGlyphInfo	    *extents)
215c76ae52dSmrg{
216c76ae52dSmrg    FT_UInt	    *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
217c76ae52dSmrg    FcChar32	    ucs4;
218c76ae52dSmrg    int		    i;
219c76ae52dSmrg    int		    l;
220c76ae52dSmrg    int		    size;
221c76ae52dSmrg
2228a91a6ebSmrg    if (len < 0)
223de3c0529Smrg	return;
224de3c0529Smrg
225c76ae52dSmrg    i = 0;
2268a91a6ebSmrg    *(glyphs = glyphs_local) = 0;
227c76ae52dSmrg    size = NUM_LOCAL;
228c76ae52dSmrg    while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
229c76ae52dSmrg    {
230c76ae52dSmrg	if (i == size)
231c76ae52dSmrg	{
232de3c0529Smrg	    glyphs_new = AllocUIntArray (size * 2);
233c76ae52dSmrg	    if (!glyphs_new)
234c76ae52dSmrg	    {
235c76ae52dSmrg		if (glyphs != glyphs_local)
236c76ae52dSmrg		    free (glyphs);
237c76ae52dSmrg		memset (extents, '\0', sizeof (XGlyphInfo));
238c76ae52dSmrg		return;
239c76ae52dSmrg	    }
24084febdacSmrg	    memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt));
241c76ae52dSmrg	    size *= 2;
242c76ae52dSmrg	    if (glyphs != glyphs_local)
243c76ae52dSmrg		free (glyphs);
244c76ae52dSmrg	    glyphs = glyphs_new;
245c76ae52dSmrg	}
246c76ae52dSmrg	glyphs[i++] = XftCharIndex (dpy, pub, ucs4);
247c76ae52dSmrg	string += l;
248c76ae52dSmrg	len -= l;
249c76ae52dSmrg    }
250c76ae52dSmrg    XftGlyphExtents (dpy, pub, glyphs, i, extents);
251c76ae52dSmrg    if (glyphs != glyphs_local)
252c76ae52dSmrg	free (glyphs);
253c76ae52dSmrg}
254c76ae52dSmrg
255c76ae52dSmrg_X_EXPORT void
256c76ae52dSmrgXftTextExtentsUtf16 (Display		*dpy,
257c76ae52dSmrg		     XftFont		*pub,
2582836776bSmrg		     _Xconst FcChar8	*string,
259c76ae52dSmrg		     FcEndian		endian,
260c76ae52dSmrg		     int		len,
261c76ae52dSmrg		     XGlyphInfo		*extents)
262c76ae52dSmrg{
263c76ae52dSmrg    FT_UInt	    *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
264c76ae52dSmrg    FcChar32	    ucs4;
265c76ae52dSmrg    int		    i;
266c76ae52dSmrg    int		    l;
267c76ae52dSmrg    int		    size;
268c76ae52dSmrg
2698a91a6ebSmrg    if (len < 0)
270de3c0529Smrg	return;
271de3c0529Smrg
272c76ae52dSmrg    i = 0;
2738a91a6ebSmrg    *(glyphs = glyphs_local) = 0;
274c76ae52dSmrg    size = NUM_LOCAL;
275c76ae52dSmrg    while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
276c76ae52dSmrg    {
277c76ae52dSmrg	if (i == size)
278c76ae52dSmrg	{
279de3c0529Smrg	    glyphs_new = AllocUIntArray (size * 2);
280c76ae52dSmrg	    if (!glyphs_new)
281c76ae52dSmrg	    {
282c76ae52dSmrg		if (glyphs != glyphs_local)
283c76ae52dSmrg		    free (glyphs);
284c76ae52dSmrg		memset (extents, '\0', sizeof (XGlyphInfo));
285c76ae52dSmrg		return;
286c76ae52dSmrg	    }
28784febdacSmrg	    memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt));
288c76ae52dSmrg	    size *= 2;
289c76ae52dSmrg	    if (glyphs != glyphs_local)
290c76ae52dSmrg		free (glyphs);
291c76ae52dSmrg	    glyphs = glyphs_new;
292c76ae52dSmrg	}
293c76ae52dSmrg	glyphs[i++] = XftCharIndex (dpy, pub, ucs4);
294c76ae52dSmrg	string += l;
295c76ae52dSmrg	len -= l;
296c76ae52dSmrg    }
297c76ae52dSmrg    XftGlyphExtents (dpy, pub, glyphs, i, extents);
298c76ae52dSmrg    if (glyphs != glyphs_local)
299c76ae52dSmrg	free (glyphs);
300c76ae52dSmrg}
301