1 /*
2  * Copyright © 2000 Keith Packard
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation, and that the name of Keith Packard not be used in
9  * advertising or publicity pertaining to distribution of the software without
10  * specific, written prior permission.  Keith Packard makes no
11  * representations about the suitability of this software for any purpose.  It
12  * is provided "as is" without express or implied warranty.
13  *
14  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20  * PERFORMANCE OF THIS SOFTWARE.
21  */
22 
23 #include "xftint.h"
24 
25 _X_EXPORT void
XftGlyphExtents(Display * dpy,XftFont * pub,_Xconst FT_UInt * glyphs,int nglyphs,XGlyphInfo * extents)26 XftGlyphExtents (Display	    *dpy,
27 		 XftFont	    *pub,
28 		 _Xconst FT_UInt    *glyphs,
29 		 int		    nglyphs,
30 		 XGlyphInfo	    *extents)
31 {
32     XftFontInt		*font = (XftFontInt *) pub;
33     FT_UInt		missing[XFT_NMISSING];
34     int			nmissing;
35     int			n;
36     _Xconst FT_UInt	*g;
37     FT_UInt		glyph;
38     XftGlyph		*xftg;
39     FcBool		glyphs_loaded;
40     int			x, y;
41     int			left, right, top, bottom;
42     int			overall_left, overall_right;
43     int			overall_top, overall_bottom;
44 
45     g = glyphs;
46     n = nglyphs;
47     nmissing = 0;
48     glyphs_loaded = FcFalse;
49     while (n--)
50 	if (XftFontCheckGlyph (dpy, pub, FcFalse, *g++, missing, &nmissing))
51 	    glyphs_loaded = FcTrue;
52     if (nmissing)
53 	XftFontLoadGlyphs (dpy, pub, FcFalse, missing, nmissing);
54     g = glyphs;
55     n = nglyphs;
56     xftg = NULL;
57     while (n)
58     {
59 	glyph = *g++;
60 	n--;
61 	if (glyph < font->num_glyphs &&
62 	    (xftg = font->glyphs[glyph]))
63 	    break;
64     }
65     if (n == 0)
66     {
67 	if (xftg)
68 	    *extents = xftg->metrics;
69 	else
70 	    memset (extents, '\0', sizeof (*extents));
71     }
72     else
73     {
74 	x = 0;
75 	y = 0;
76 	overall_left = x - xftg->metrics.x;
77 	overall_top = y - xftg->metrics.y;
78 	overall_right = overall_left + (int) xftg->metrics.width;
79 	overall_bottom = overall_top + (int) xftg->metrics.height;
80 	x += xftg->metrics.xOff;
81 	y += xftg->metrics.yOff;
82 	while (n--)
83 	{
84 	    glyph = *g++;
85 	    if (glyph < font->num_glyphs && (xftg = font->glyphs[glyph]))
86 	    {
87 		left = x - xftg->metrics.x;
88 		top = y - xftg->metrics.y;
89 		right = left + (int) xftg->metrics.width;
90 		bottom = top + (int) xftg->metrics.height;
91 		if (left < overall_left)
92 		    overall_left = left;
93 		if (top < overall_top)
94 		    overall_top = top;
95 		if (right > overall_right)
96 		    overall_right = right;
97 		if (bottom > overall_bottom)
98 		    overall_bottom = bottom;
99 		x += xftg->metrics.xOff;
100 		y += xftg->metrics.yOff;
101 	    }
102 	}
103 	extents->x = (short)(-overall_left);
104 	extents->y = (short)(-overall_top);
105 	extents->width = (unsigned short)(overall_right - overall_left);
106 	extents->height = (unsigned short)(overall_bottom - overall_top);
107 	extents->xOff = (short)x;
108 	extents->yOff = (short)y;
109     }
110     if (glyphs_loaded)
111 	_XftFontManageMemory (dpy, pub);
112 }
113 
114 #define NUM_LOCAL   1024
115 
116 _X_EXPORT void
XftTextExtents8(Display * dpy,XftFont * pub,_Xconst FcChar8 * string,int len,XGlyphInfo * extents)117 XftTextExtents8 (Display	    *dpy,
118 		 XftFont	    *pub,
119 		 _Xconst FcChar8    *string,
120 		 int		    len,
121 		 XGlyphInfo	    *extents)
122 {
123     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
124     int		    i;
125 
126     if (len <= NUM_LOCAL)
127 	glyphs = glyphs_local;
128     else
129     {
130 	glyphs = malloc ((size_t)len * sizeof (FT_UInt));
131 	if (!glyphs)
132 	{
133 	    memset (extents, '\0', sizeof (XGlyphInfo));
134 	    return;
135 	}
136     }
137     for (i = 0; i < len; i++)
138 	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
139     XftGlyphExtents (dpy, pub, glyphs, len, extents);
140     if (glyphs != glyphs_local)
141 	free (glyphs);
142 }
143 
144 _X_EXPORT void
XftTextExtents16(Display * dpy,XftFont * pub,_Xconst FcChar16 * string,int len,XGlyphInfo * extents)145 XftTextExtents16 (Display	    *dpy,
146 		  XftFont	    *pub,
147 		  _Xconst FcChar16  *string,
148 		  int		    len,
149 		  XGlyphInfo	    *extents)
150 {
151     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
152     int		    i;
153 
154     if (len <= NUM_LOCAL)
155 	glyphs = glyphs_local;
156     else
157     {
158 	glyphs = malloc ((size_t)len * sizeof (FT_UInt));
159 	if (!glyphs)
160 	{
161 	    memset (extents, '\0', sizeof (XGlyphInfo));
162 	    return;
163 	}
164     }
165     for (i = 0; i < len; i++)
166 	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
167     XftGlyphExtents (dpy, pub, glyphs, len, extents);
168     if (glyphs != glyphs_local)
169 	free (glyphs);
170 }
171 
172 _X_EXPORT void
XftTextExtents32(Display * dpy,XftFont * pub,_Xconst FcChar32 * string,int len,XGlyphInfo * extents)173 XftTextExtents32 (Display	    *dpy,
174 		  XftFont	    *pub,
175 		  _Xconst FcChar32  *string,
176 		  int		    len,
177 		  XGlyphInfo	    *extents)
178 {
179     FT_UInt	    *glyphs, glyphs_local[NUM_LOCAL];
180     int		    i;
181 
182     if (len <= NUM_LOCAL)
183 	glyphs = glyphs_local;
184     else
185     {
186 	glyphs = malloc ((size_t)len * sizeof (FT_UInt));
187 	if (!glyphs)
188 	{
189 	    memset (extents, '\0', sizeof (XGlyphInfo));
190 	    return;
191 	}
192     }
193     for (i = 0; i < len; i++)
194 	glyphs[i] = XftCharIndex (dpy, pub, string[i]);
195     XftGlyphExtents (dpy, pub, glyphs, len, extents);
196     if (glyphs != glyphs_local)
197 	free (glyphs);
198 }
199 
200 _X_EXPORT void
XftTextExtentsUtf8(Display * dpy,XftFont * pub,_Xconst FcChar8 * string,int len,XGlyphInfo * extents)201 XftTextExtentsUtf8 (Display	    *dpy,
202 		    XftFont	    *pub,
203 		    _Xconst FcChar8 *string,
204 		    int		    len,
205 		    XGlyphInfo	    *extents)
206 {
207     FT_UInt	    *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
208     FcChar32	    ucs4;
209     int		    i;
210     int		    l;
211     int		    size;
212 
213     i = 0;
214     glyphs = glyphs_local;
215     size = NUM_LOCAL;
216     while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
217     {
218 	if (i == size)
219 	{
220 	    glyphs_new = malloc ((size_t)size * 2 * sizeof (FT_UInt));
221 	    if (!glyphs_new)
222 	    {
223 		if (glyphs != glyphs_local)
224 		    free (glyphs);
225 		memset (extents, '\0', sizeof (XGlyphInfo));
226 		return;
227 	    }
228 	    memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt));
229 	    size *= 2;
230 	    if (glyphs != glyphs_local)
231 		free (glyphs);
232 	    glyphs = glyphs_new;
233 	}
234 	glyphs[i++] = XftCharIndex (dpy, pub, ucs4);
235 	string += l;
236 	len -= l;
237     }
238     XftGlyphExtents (dpy, pub, glyphs, i, extents);
239     if (glyphs != glyphs_local)
240 	free (glyphs);
241 }
242 
243 _X_EXPORT void
XftTextExtentsUtf16(Display * dpy,XftFont * pub,_Xconst FcChar8 * string,FcEndian endian,int len,XGlyphInfo * extents)244 XftTextExtentsUtf16 (Display		*dpy,
245 		     XftFont		*pub,
246 		     _Xconst FcChar8	*string,
247 		     FcEndian		endian,
248 		     int		len,
249 		     XGlyphInfo		*extents)
250 {
251     FT_UInt	    *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
252     FcChar32	    ucs4;
253     int		    i;
254     int		    l;
255     int		    size;
256 
257     i = 0;
258     glyphs = glyphs_local;
259     size = NUM_LOCAL;
260     while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
261     {
262 	if (i == size)
263 	{
264 	    glyphs_new = malloc ((size_t)size * 2 * sizeof (FT_UInt));
265 	    if (!glyphs_new)
266 	    {
267 		if (glyphs != glyphs_local)
268 		    free (glyphs);
269 		memset (extents, '\0', sizeof (XGlyphInfo));
270 		return;
271 	    }
272 	    memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt));
273 	    size *= 2;
274 	    if (glyphs != glyphs_local)
275 		free (glyphs);
276 	    glyphs = glyphs_new;
277 	}
278 	glyphs[i++] = XftCharIndex (dpy, pub, ucs4);
279 	string += l;
280 	len -= l;
281     }
282     XftGlyphExtents (dpy, pub, glyphs, i, extents);
283     if (glyphs != glyphs_local)
284 	free (glyphs);
285 }
286