File: | xftfreetype.c |
Location: | line 135, column 27 |
Description: | Division by zero |
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_HIDDEN__attribute__((visibility("hidden"))) FT_Library _XftFTlibrary; | |||
26 | ||||
27 | #define FT_Matrix_Equal(a,b)((a)->xx == (b)->xx && (a)->yy == (b)->yy && (a)->xy == (b)->xy && (a)->yx == (b)->yx) ((a)->xx == (b)->xx && \ | |||
28 | (a)->yy == (b)->yy && \ | |||
29 | (a)->xy == (b)->xy && \ | |||
30 | (a)->yx == (b)->yx) | |||
31 | /* | |||
32 | * List of all open files (each face in a file is managed separately) | |||
33 | */ | |||
34 | ||||
35 | static XftFtFile *_XftFtFiles; | |||
36 | static int XftMaxFreeTypeFiles = 5; | |||
37 | ||||
38 | static XftFtFile * | |||
39 | _XftGetFile (const FcChar8 *file, int id) | |||
40 | { | |||
41 | XftFtFile *f; | |||
42 | ||||
43 | if (!XftInitFtLibrary ()) | |||
44 | return NULL((void*)0); | |||
45 | ||||
46 | for (f = _XftFtFiles; f; f = f->next) | |||
47 | { | |||
48 | if (!strcmp (f->file, (char *) file) && f->id == id) | |||
49 | { | |||
50 | ++f->ref; | |||
51 | if (XftDebug () & XFT_DBG_REF16) | |||
52 | printf ("FontFile %s/%d matches existing (%d)\n", | |||
53 | file, id, f->ref); | |||
54 | return f; | |||
55 | } | |||
56 | } | |||
57 | f = malloc (sizeof (XftFtFile) + strlen ((char *) file) + 1); | |||
58 | if (!f) | |||
59 | return NULL((void*)0); | |||
60 | ||||
61 | XftMemAlloc (XFT_MEM_FILE2, sizeof (XftFtFile) + strlen ((char *) file) + 1); | |||
62 | if (XftDebug () & XFT_DBG_REF16) | |||
63 | printf ("FontFile %s/%d matches new\n", | |||
64 | file, id); | |||
65 | f->next = _XftFtFiles; | |||
66 | _XftFtFiles = f; | |||
67 | ||||
68 | f->ref = 1; | |||
69 | ||||
70 | f->file = (char *) (f+1); | |||
71 | strcpy (f->file, (char *) file)__builtin___strcpy_chk (f->file, (char *) file, __builtin_object_size (f->file, 2 > 1 ? 1 : 0)); | |||
72 | f->id = id; | |||
73 | ||||
74 | f->lock = 0; | |||
75 | f->face = NULL((void*)0); | |||
76 | f->xsize = 0; | |||
77 | f->ysize = 0; | |||
78 | f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0; | |||
79 | return f; | |||
80 | } | |||
81 | ||||
82 | static XftFtFile * | |||
83 | _XftGetFaceFile (FT_Face face) | |||
84 | { | |||
85 | XftFtFile *f; | |||
86 | ||||
87 | f = malloc (sizeof (XftFtFile)); | |||
88 | if (!f) | |||
89 | return NULL((void*)0); | |||
90 | XftMemAlloc (XFT_MEM_FILE2, sizeof(XftFtFile)); | |||
91 | f->next = NULL((void*)0); | |||
92 | ||||
93 | f->ref = 1; | |||
94 | ||||
95 | f->file = NULL((void*)0); | |||
96 | f->id = 0; | |||
97 | f->lock = 0; | |||
98 | f->face = face; | |||
99 | f->xsize = 0; | |||
100 | f->ysize = 0; | |||
101 | f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0; | |||
102 | return f; | |||
103 | } | |||
104 | ||||
105 | static int | |||
106 | _XftNumFiles (void) | |||
107 | { | |||
108 | XftFtFile *f; | |||
109 | int count = 0; | |||
110 | for (f = _XftFtFiles; f; f = f->next) | |||
111 | if (f->face && !f->lock) | |||
112 | ++count; | |||
113 | return count; | |||
114 | } | |||
115 | ||||
116 | static XftFtFile * | |||
117 | _XftNthFile (int n) | |||
118 | { | |||
119 | XftFtFile *f; | |||
120 | int count = 0; | |||
121 | for (f = _XftFtFiles; f; f = f->next) | |||
122 | if (f->face && !f->lock) | |||
123 | if (count++ == n) | |||
124 | break; | |||
125 | return f; | |||
126 | } | |||
127 | ||||
128 | static void | |||
129 | _XftUncacheFiles (void) | |||
130 | { | |||
131 | int n; | |||
132 | XftFtFile *f; | |||
133 | while ((n = _XftNumFiles ()) > XftMaxFreeTypeFiles) | |||
134 | { | |||
135 | f = _XftNthFile (rand () % n); | |||
| ||||
136 | if (f) | |||
137 | { | |||
138 | if (XftDebug() & XFT_DBG_REF16) | |||
139 | printf ("Discard file %s/%d from cache\n", | |||
140 | f->file, f->id); | |||
141 | FT_Done_Face (f->face); | |||
142 | f->face = NULL((void*)0); | |||
143 | } | |||
144 | } | |||
145 | } | |||
146 | ||||
147 | static FT_Face | |||
148 | _XftLockFile (XftFtFile *f) | |||
149 | { | |||
150 | ++f->lock; | |||
151 | if (!f->face) | |||
152 | { | |||
153 | if (XftDebug() & XFT_DBG_REF16) | |||
154 | printf ("Loading file %s/%d\n", f->file, f->id); | |||
155 | if (FT_New_Face (_XftFTlibrary, f->file, f->id, &f->face)) | |||
156 | --f->lock; | |||
157 | ||||
158 | f->xsize = 0; | |||
159 | f->ysize = 0; | |||
160 | f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0; | |||
161 | _XftUncacheFiles (); | |||
162 | } | |||
163 | return f->face; | |||
164 | } | |||
165 | ||||
166 | static void | |||
167 | _XftLockError (const char *reason) | |||
168 | { | |||
169 | fprintf (stderr__stderrp, "Xft: locking error %s\n", reason); | |||
170 | } | |||
171 | ||||
172 | static void | |||
173 | _XftUnlockFile (XftFtFile *f) | |||
174 | { | |||
175 | if (--f->lock < 0) | |||
176 | _XftLockError ("too many file unlocks"); | |||
177 | } | |||
178 | ||||
179 | #define X_SIZE(face,i)((face)->available_sizes[i].x_ppem) ((face)->available_sizes[i].x_ppem) | |||
180 | #define Y_SIZE(face,i)((face)->available_sizes[i].y_ppem) ((face)->available_sizes[i].y_ppem) | |||
181 | ||||
182 | _X_HIDDEN__attribute__((visibility("hidden"))) FcBool | |||
183 | _XftSetFace (XftFtFile *f, FT_F26Dot6 xsize, FT_F26Dot6 ysize, FT_Matrix *matrix) | |||
184 | { | |||
185 | FT_Face face = f->face; | |||
186 | ||||
187 | if (f->xsize != xsize || f->ysize != ysize) | |||
188 | { | |||
189 | if (XftDebug() & XFT_DBG_GLYPH32) | |||
190 | printf ("Set face size to %dx%d (%dx%d)\n", | |||
191 | (int) (xsize >> 6), (int) (ysize >> 6), (int) xsize, (int) ysize); | |||
192 | /* | |||
193 | * Bitmap only faces must match exactly, so find the closest | |||
194 | * one (height dominant search) | |||
195 | */ | |||
196 | if (!(face->face_flags & FT_FACE_FLAG_SCALABLE( 1L << 0 ))) | |||
197 | { | |||
198 | int i, best = 0; | |||
199 | ||||
200 | #define xft_abs(a)((a) < 0 ? -(a) : (a)) ((a) < 0 ? -(a) : (a)) | |||
201 | #define dist(a,b)((((a)-(b)) < 0 ? -((a)-(b)) : ((a)-(b)))) (xft_abs((a)-(b))(((a)-(b)) < 0 ? -((a)-(b)) : ((a)-(b)))) | |||
202 | ||||
203 | for (i = 1; i < face->num_fixed_sizes; i++) | |||
204 | { | |||
205 | if (dist (ysize, Y_SIZE(face,i))((((ysize)-(((face)->available_sizes[i].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[i].y_ppem))) : ((ysize )-(((face)->available_sizes[i].y_ppem))))) < | |||
206 | dist (ysize, Y_SIZE(face, best))((((ysize)-(((face)->available_sizes[best].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[best].y_ppem))) : ( (ysize)-(((face)->available_sizes[best].y_ppem))))) || | |||
207 | (dist (ysize, Y_SIZE(face, i))((((ysize)-(((face)->available_sizes[i].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[i].y_ppem))) : ((ysize )-(((face)->available_sizes[i].y_ppem))))) == | |||
208 | dist (ysize, Y_SIZE(face, best))((((ysize)-(((face)->available_sizes[best].y_ppem))) < 0 ? -((ysize)-(((face)->available_sizes[best].y_ppem))) : ( (ysize)-(((face)->available_sizes[best].y_ppem))))) && | |||
209 | dist (xsize, X_SIZE(face, i))((((xsize)-(((face)->available_sizes[i].x_ppem))) < 0 ? -((xsize)-(((face)->available_sizes[i].x_ppem))) : ((xsize )-(((face)->available_sizes[i].x_ppem))))) < | |||
210 | dist (xsize, X_SIZE(face, best))((((xsize)-(((face)->available_sizes[best].x_ppem))) < 0 ? -((xsize)-(((face)->available_sizes[best].x_ppem))) : ( (xsize)-(((face)->available_sizes[best].x_ppem))))))) | |||
211 | { | |||
212 | best = i; | |||
213 | } | |||
214 | } | |||
215 | /* | |||
216 | * Freetype 2.1.7 and earlier used width/height | |||
217 | * for matching sizes in the BDF and PCF loaders. | |||
218 | * This has been fixed for 2.1.8. Because BDF and PCF | |||
219 | * files have but a single strike per file, we can | |||
220 | * simply try both sizes. | |||
221 | */ | |||
222 | if (FT_Set_Char_Size (face, face->available_sizes[best].x_ppem, | |||
223 | face->available_sizes[best].y_ppem, 0, 0) != 0 | |||
224 | && | |||
225 | FT_Set_Char_Size (face, face->available_sizes[best].width << 6, | |||
226 | face->available_sizes[best].height << 6, | |||
227 | 0, 0) != 0) | |||
228 | { | |||
229 | return False0; | |||
230 | } | |||
231 | } | |||
232 | else | |||
233 | { | |||
234 | if (FT_Set_Char_Size (face, xsize, ysize, 0, 0)) | |||
235 | { | |||
236 | return False0; | |||
237 | } | |||
238 | } | |||
239 | f->xsize = xsize; | |||
240 | f->ysize = ysize; | |||
241 | } | |||
242 | if (!FT_Matrix_Equal (&f->matrix, matrix)((&f->matrix)->xx == (matrix)->xx && (& f->matrix)->yy == (matrix)->yy && (&f-> matrix)->xy == (matrix)->xy && (&f->matrix )->yx == (matrix)->yx)) | |||
243 | { | |||
244 | if (XftDebug() & XFT_DBG_GLYPH32) | |||
245 | printf ("Set face matrix to (%g,%g,%g,%g)\n", | |||
246 | (double) matrix->xx / 0x10000, | |||
247 | (double) matrix->xy / 0x10000, | |||
248 | (double) matrix->yx / 0x10000, | |||
249 | (double) matrix->yy / 0x10000); | |||
250 | FT_Set_Transform (face, matrix, NULL((void*)0)); | |||
251 | f->matrix = *matrix; | |||
252 | } | |||
253 | return True1; | |||
254 | } | |||
255 | ||||
256 | static void | |||
257 | _XftReleaseFile (XftFtFile *f) | |||
258 | { | |||
259 | XftFtFile **prev; | |||
260 | ||||
261 | if (--f->ref != 0) | |||
262 | return; | |||
263 | if (f->lock) | |||
264 | _XftLockError ("Attempt to close locked file"); | |||
265 | if (f->file) | |||
266 | { | |||
267 | for (prev = &_XftFtFiles; *prev; prev = &(*prev)->next) | |||
268 | { | |||
269 | if (*prev == f) | |||
270 | { | |||
271 | *prev = f->next; | |||
272 | break; | |||
273 | } | |||
274 | } | |||
275 | if (f->face) | |||
276 | FT_Done_Face (f->face); | |||
277 | } | |||
278 | XftMemFree (XFT_MEM_FILE2, | |||
279 | sizeof (XftFtFile) + (f->file ? strlen (f->file) + 1 : 0)); | |||
280 | free (f); | |||
281 | } | |||
282 | ||||
283 | /* | |||
284 | * Find a prime larger than the minimum reasonable hash size | |||
285 | */ | |||
286 | ||||
287 | static FcChar32 | |||
288 | _XftSqrt (FcChar32 a) | |||
289 | { | |||
290 | FcChar32 l, h, m; | |||
291 | ||||
292 | l = 2; | |||
293 | h = a/2; | |||
294 | while ((h-l) > 1) | |||
295 | { | |||
296 | m = (h+l) >> 1; | |||
297 | if (m * m < a) | |||
298 | l = m; | |||
299 | else | |||
300 | h = m; | |||
301 | } | |||
302 | return h; | |||
303 | } | |||
304 | ||||
305 | static FcBool | |||
306 | _XftIsPrime (FcChar32 i) | |||
307 | { | |||
308 | FcChar32 l, t; | |||
309 | ||||
310 | if (i < 2) | |||
311 | return FcFalse0; | |||
312 | if ((i & 1) == 0) | |||
313 | { | |||
314 | if (i == 2) | |||
315 | return FcTrue1; | |||
316 | return FcFalse0; | |||
317 | } | |||
318 | l = _XftSqrt (i) + 1; | |||
319 | for (t = 3; t <= l; t += 2) | |||
320 | if (i % t == 0) | |||
321 | return FcFalse0; | |||
322 | return FcTrue1; | |||
323 | } | |||
324 | ||||
325 | static FcChar32 | |||
326 | _XftHashSize (FcChar32 num_unicode) | |||
327 | { | |||
328 | /* at least 31.25 % extra space */ | |||
329 | FcChar32 hash = num_unicode + (num_unicode >> 2) + (num_unicode >> 4); | |||
330 | ||||
331 | if ((hash & 1) == 0) | |||
332 | hash++; | |||
333 | while (!_XftIsPrime (hash)) | |||
334 | hash += 2; | |||
335 | return hash; | |||
336 | } | |||
337 | ||||
338 | _X_EXPORT__attribute__((visibility("default"))) FT_Face | |||
339 | XftLockFace (XftFont *public) | |||
340 | { | |||
341 | XftFontInt *font = (XftFontInt *) public; | |||
342 | XftFontInfo *fi = &font->info; | |||
343 | FT_Face face; | |||
344 | ||||
345 | face = _XftLockFile (fi->file); | |||
| ||||
346 | /* | |||
347 | * Make sure the face is usable at the requested size | |||
348 | */ | |||
349 | if (face && !_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix)) | |||
350 | { | |||
351 | _XftUnlockFile (fi->file); | |||
352 | face = NULL((void*)0); | |||
353 | } | |||
354 | return face; | |||
355 | } | |||
356 | ||||
357 | _X_EXPORT__attribute__((visibility("default"))) void | |||
358 | XftUnlockFace (XftFont *public) | |||
359 | { | |||
360 | XftFontInt *font = (XftFontInt *) public; | |||
361 | _XftUnlockFile (font->info.file); | |||
362 | } | |||
363 | ||||
364 | static FcBool | |||
365 | XftFontInfoFill (Display *dpy, _Xconstconst FcPattern *pattern, XftFontInfo *fi) | |||
366 | { | |||
367 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True1); | |||
368 | FcChar8 *filename; | |||
369 | int id; | |||
370 | double dsize; | |||
371 | double aspect; | |||
372 | FcMatrix *font_matrix; | |||
373 | FcBool hinting, vertical_layout, autohint, global_advance; | |||
374 | int hint_style; | |||
375 | FcChar32 hash, *hashp; | |||
376 | FT_Face face; | |||
377 | int nhash; | |||
378 | FcBool bitmap; | |||
379 | ||||
380 | if (!info) | |||
381 | return FcFalse0; | |||
382 | ||||
383 | /* | |||
384 | * Initialize the whole XftFontInfo so that padding doesn't interfere with | |||
385 | * hash or XftFontInfoEqual(). | |||
386 | */ | |||
387 | ||||
388 | memset (fi, '\0', sizeof(*fi))__builtin___memset_chk (fi, '\0', sizeof(*fi), __builtin_object_size (fi, 0)); | |||
389 | ||||
390 | /* | |||
391 | * Find the associated file | |||
392 | */ | |||
393 | switch (FcPatternGetString (pattern, FC_FILE"file", 0, &filename)) { | |||
394 | case FcResultNoMatch: | |||
395 | filename = NULL((void*)0); | |||
396 | break; | |||
397 | case FcResultMatch: | |||
398 | break; | |||
399 | default: | |||
400 | goto bail0; | |||
401 | } | |||
402 | ||||
403 | switch (FcPatternGetInteger (pattern, FC_INDEX"index", 0, &id)) { | |||
404 | case FcResultNoMatch: | |||
405 | id = 0; | |||
406 | break; | |||
407 | case FcResultMatch: | |||
408 | break; | |||
409 | default: | |||
410 | goto bail0; | |||
411 | } | |||
412 | ||||
413 | if (filename) | |||
414 | fi->file = _XftGetFile (filename, id); | |||
415 | else if (FcPatternGetFTFace (pattern, FC_FT_FACE"ftface", 0, &face) == FcResultMatch | |||
416 | && face) | |||
417 | fi->file = _XftGetFaceFile (face); | |||
418 | if (!fi->file) | |||
419 | goto bail0; | |||
420 | ||||
421 | /* | |||
422 | * Compute pixel size | |||
423 | */ | |||
424 | if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE"pixelsize", 0, &dsize) != FcResultMatch) | |||
425 | goto bail1; | |||
426 | ||||
427 | if (FcPatternGetDouble (pattern, FC_ASPECT"aspect", 0, &aspect) != FcResultMatch) | |||
428 | aspect = 1.0; | |||
429 | ||||
430 | fi->ysize = (FT_F26Dot6) (dsize * 64.0); | |||
431 | fi->xsize = (FT_F26Dot6) (dsize * aspect * 64.0); | |||
432 | ||||
433 | if (XftDebug() & XFT_DBG_OPEN1) | |||
434 | printf ("XftFontInfoFill: %s: %d (%g pixels)\n", | |||
435 | (filename ? filename : (FcChar8 *) "<none>"), id, dsize); | |||
436 | /* | |||
437 | * Get antialias value | |||
438 | */ | |||
439 | switch (FcPatternGetBool (pattern, FC_ANTIALIAS"antialias", 0, &fi->antialias)) { | |||
440 | case FcResultNoMatch: | |||
441 | fi->antialias = True1; | |||
442 | break; | |||
443 | case FcResultMatch: | |||
444 | break; | |||
445 | default: | |||
446 | goto bail1; | |||
447 | } | |||
448 | ||||
449 | /* | |||
450 | * Get rgba value | |||
451 | */ | |||
452 | switch (FcPatternGetInteger (pattern, FC_RGBA"rgba", 0, &fi->rgba)) { | |||
453 | case FcResultNoMatch: | |||
454 | fi->rgba = FC_RGBA_UNKNOWN0; | |||
455 | break; | |||
456 | case FcResultMatch: | |||
457 | break; | |||
458 | default: | |||
459 | goto bail1; | |||
460 | } | |||
461 | ||||
462 | /* | |||
463 | * Get lcd_filter value | |||
464 | */ | |||
465 | switch (FcPatternGetInteger (pattern, FC_LCD_FILTER"lcdfilter", 0, &fi->lcd_filter)) { | |||
466 | case FcResultNoMatch: | |||
467 | fi->lcd_filter = FC_LCD_DEFAULT1; | |||
468 | break; | |||
469 | case FcResultMatch: | |||
470 | break; | |||
471 | default: | |||
472 | goto bail1; | |||
473 | } | |||
474 | ||||
475 | /* | |||
476 | * Get matrix and transform values | |||
477 | */ | |||
478 | switch (FcPatternGetMatrix (pattern, FC_MATRIX"matrix", 0, &font_matrix)) { | |||
479 | case FcResultNoMatch: | |||
480 | fi->matrix.xx = fi->matrix.yy = 0x10000; | |||
481 | fi->matrix.xy = fi->matrix.yx = 0; | |||
482 | break; | |||
483 | case FcResultMatch: | |||
484 | fi->matrix.xx = 0x10000L * font_matrix->xx; | |||
485 | fi->matrix.yy = 0x10000L * font_matrix->yy; | |||
486 | fi->matrix.xy = 0x10000L * font_matrix->xy; | |||
487 | fi->matrix.yx = 0x10000L * font_matrix->yx; | |||
488 | break; | |||
489 | default: | |||
490 | goto bail1; | |||
491 | } | |||
492 | ||||
493 | fi->transform = (fi->matrix.xx != 0x10000 || fi->matrix.xy != 0 || | |||
494 | fi->matrix.yx != 0 || fi->matrix.yy != 0x10000); | |||
495 | ||||
496 | /* | |||
497 | * Get render value, set to false if no Render extension present | |||
498 | */ | |||
499 | if (info->hasRender) | |||
500 | { | |||
501 | switch (FcPatternGetBool (pattern, XFT_RENDER"render", 0, &fi->render)) { | |||
502 | case FcResultNoMatch: | |||
503 | fi->render = info->hasRender; | |||
504 | break; | |||
505 | case FcResultMatch: | |||
506 | break; | |||
507 | default: | |||
508 | goto bail1; | |||
509 | } | |||
510 | } | |||
511 | else | |||
512 | fi->render = FcFalse0; | |||
513 | ||||
514 | /* | |||
515 | * Compute glyph load flags | |||
516 | */ | |||
517 | fi->load_flags = FT_LOAD_DEFAULT0x0; | |||
518 | ||||
519 | #ifndef XFT_EMBEDDED_BITMAP"embeddedbitmap" | |||
520 | #define XFT_EMBEDDED_BITMAP"embeddedbitmap" "embeddedbitmap" | |||
521 | #endif | |||
522 | ||||
523 | switch (FcPatternGetBool (pattern, XFT_EMBEDDED_BITMAP"embeddedbitmap", 0, &bitmap)) { | |||
524 | case FcResultNoMatch: | |||
525 | bitmap = FcFalse0; | |||
526 | break; | |||
527 | case FcResultMatch: | |||
528 | break; | |||
529 | default: | |||
530 | goto bail1; | |||
531 | } | |||
532 | ||||
533 | /* disable bitmaps when anti-aliasing or transforming glyphs */ | |||
534 | if ((!bitmap && fi->antialias) || fi->transform) | |||
535 | fi->load_flags |= FT_LOAD_NO_BITMAP0x8; | |||
536 | ||||
537 | /* disable hinting if requested */ | |||
538 | switch (FcPatternGetBool (pattern, FC_HINTING"hinting", 0, &hinting)) { | |||
539 | case FcResultNoMatch: | |||
540 | hinting = FcTrue1; | |||
541 | break; | |||
542 | case FcResultMatch: | |||
543 | break; | |||
544 | default: | |||
545 | goto bail1; | |||
546 | } | |||
547 | ||||
548 | switch (FcPatternGetBool (pattern, FC_EMBOLDEN"embolden", 0, &fi->embolden)) { | |||
549 | case FcResultNoMatch: | |||
550 | fi->embolden = FcFalse0; | |||
551 | break; | |||
552 | case FcResultMatch: | |||
553 | break; | |||
554 | default: | |||
555 | goto bail1; | |||
556 | } | |||
557 | ||||
558 | switch (FcPatternGetInteger (pattern, FC_HINT_STYLE"hintstyle", 0, &hint_style)) { | |||
559 | case FcResultNoMatch: | |||
560 | hint_style = FC_HINT_FULL3; | |||
561 | break; | |||
562 | case FcResultMatch: | |||
563 | break; | |||
564 | default: | |||
565 | goto bail1; | |||
566 | } | |||
567 | ||||
568 | if (!hinting | |||
569 | || hint_style == FC_HINT_NONE0 | |||
570 | ) | |||
571 | { | |||
572 | fi->load_flags |= FT_LOAD_NO_HINTING0x2; | |||
573 | } | |||
574 | ||||
575 | /* Figure out the load target, which modifies the hinting | |||
576 | * behavior of FreeType based on the intended use of the glyphs. | |||
577 | */ | |||
578 | if (fi->antialias) | |||
579 | { | |||
580 | if (FC_HINT_NONE0 < hint_style && hint_style < FC_HINT_FULL3) | |||
581 | { | |||
582 | fi->load_flags |= FT_LOAD_TARGET_LIGHT( (FT_Int32)( (FT_RENDER_MODE_LIGHT) & 15 ) << 16 ); | |||
583 | } | |||
584 | else | |||
585 | { | |||
586 | /* autohinter will snap stems to integer widths, when | |||
587 | * the LCD targets are used. | |||
588 | */ | |||
589 | switch (fi->rgba) { | |||
590 | case FC_RGBA_RGB1: | |||
591 | case FC_RGBA_BGR2: | |||
592 | fi->load_flags |= FT_LOAD_TARGET_LCD( (FT_Int32)( (FT_RENDER_MODE_LCD) & 15 ) << 16 ); | |||
593 | break; | |||
594 | case FC_RGBA_VRGB3: | |||
595 | case FC_RGBA_VBGR4: | |||
596 | fi->load_flags |= FT_LOAD_TARGET_LCD_V( (FT_Int32)( (FT_RENDER_MODE_LCD_V) & 15 ) << 16 ); | |||
597 | break; | |||
598 | } | |||
599 | } | |||
600 | } | |||
601 | else | |||
602 | fi->load_flags |= FT_LOAD_TARGET_MONO( (FT_Int32)( (FT_RENDER_MODE_MONO) & 15 ) << 16 ); | |||
603 | ||||
604 | /* set vertical layout if requested */ | |||
605 | switch (FcPatternGetBool (pattern, FC_VERTICAL_LAYOUT"verticallayout", 0, &vertical_layout)) { | |||
606 | case FcResultNoMatch: | |||
607 | vertical_layout = FcFalse0; | |||
608 | break; | |||
609 | case FcResultMatch: | |||
610 | break; | |||
611 | default: | |||
612 | goto bail1; | |||
613 | } | |||
614 | ||||
615 | if (vertical_layout) | |||
616 | fi->load_flags |= FT_LOAD_VERTICAL_LAYOUT0x10; | |||
617 | ||||
618 | /* force autohinting if requested */ | |||
619 | switch (FcPatternGetBool (pattern, FC_AUTOHINT"autohint", 0, &autohint)) { | |||
620 | case FcResultNoMatch: | |||
621 | autohint = FcFalse0; | |||
622 | break; | |||
623 | case FcResultMatch: | |||
624 | break; | |||
625 | default: | |||
626 | goto bail1; | |||
627 | } | |||
628 | ||||
629 | if (autohint) | |||
630 | fi->load_flags |= FT_LOAD_FORCE_AUTOHINT0x20; | |||
631 | ||||
632 | /* disable global advance width (for broken DynaLab TT CJK fonts) */ | |||
633 | switch (FcPatternGetBool (pattern, FC_GLOBAL_ADVANCE"globaladvance", 0, &global_advance)) { | |||
634 | case FcResultNoMatch: | |||
635 | global_advance = FcTrue1; | |||
636 | break; | |||
637 | case FcResultMatch: | |||
638 | break; | |||
639 | default: | |||
640 | goto bail1; | |||
641 | } | |||
642 | ||||
643 | if (!global_advance) | |||
644 | fi->load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH0x200; | |||
645 | ||||
646 | /* | |||
647 | * Get requested spacing value | |||
648 | */ | |||
649 | switch (FcPatternGetInteger (pattern, FC_SPACING"spacing", 0, &fi->spacing)) { | |||
650 | case FcResultNoMatch: | |||
651 | fi->spacing = FC_PROPORTIONAL0; | |||
652 | break; | |||
653 | case FcResultMatch: | |||
654 | break; | |||
655 | default: | |||
656 | goto bail1; | |||
657 | } | |||
658 | ||||
659 | /* | |||
660 | * Check for minspace | |||
661 | */ | |||
662 | ||||
663 | switch (FcPatternGetBool (pattern, FC_MINSPACE"minspace", 0, &fi->minspace)) { | |||
664 | case FcResultNoMatch: | |||
665 | fi->minspace = FcFalse0; | |||
666 | break; | |||
667 | case FcResultMatch: | |||
668 | break; | |||
669 | default: | |||
670 | goto bail1; | |||
671 | } | |||
672 | /* | |||
673 | * Check for fixed pixel spacing | |||
674 | */ | |||
675 | switch (FcPatternGetInteger (pattern, FC_CHAR_WIDTH"charwidth", 0, &fi->char_width)) { | |||
676 | case FcResultNoMatch: | |||
677 | fi->char_width = 0; | |||
678 | break; | |||
679 | case FcResultMatch: | |||
680 | if (fi->char_width) | |||
681 | fi->spacing = FC_MONO100; | |||
682 | break; | |||
683 | default: | |||
684 | goto bail1; | |||
685 | } | |||
686 | ||||
687 | /* | |||
688 | * Step over hash value in the structure | |||
689 | */ | |||
690 | hash = 0; | |||
691 | hashp = (FcChar32 *) fi + 1; | |||
692 | nhash = (sizeof (XftFontInfo) / sizeof (FcChar32)) - 1; | |||
693 | ||||
694 | while (nhash--) | |||
695 | hash += *hashp++; | |||
696 | fi->hash = hash; | |||
697 | ||||
698 | /* | |||
699 | * All done | |||
700 | */ | |||
701 | return FcTrue1; | |||
702 | ||||
703 | bail1: | |||
704 | _XftReleaseFile (fi->file); | |||
705 | fi->file = NULL((void*)0); | |||
706 | bail0: | |||
707 | return FcFalse0; | |||
708 | } | |||
709 | ||||
710 | static void | |||
711 | XftFontInfoEmpty (Display *dpy, XftFontInfo *fi) | |||
712 | { | |||
713 | if (fi->file) | |||
714 | _XftReleaseFile (fi->file); | |||
715 | } | |||
716 | ||||
717 | XftFontInfo * | |||
718 | XftFontInfoCreate (Display *dpy, _Xconstconst FcPattern *pattern) | |||
719 | { | |||
720 | XftFontInfo *fi = malloc (sizeof (XftFontInfo)); | |||
721 | ||||
722 | if (!fi) | |||
723 | return NULL((void*)0); | |||
724 | ||||
725 | if (!XftFontInfoFill (dpy, pattern, fi)) | |||
726 | { | |||
727 | free (fi); | |||
728 | fi = NULL((void*)0); | |||
729 | } | |||
730 | XftMemAlloc (XFT_MEM_FONT1, sizeof (XftFontInfo)); | |||
731 | return fi; | |||
732 | } | |||
733 | ||||
734 | _X_EXPORT__attribute__((visibility("default"))) void | |||
735 | XftFontInfoDestroy (Display *dpy, XftFontInfo *fi) | |||
736 | { | |||
737 | XftFontInfoEmpty (dpy, fi); | |||
738 | XftMemFree (XFT_MEM_FONT1, sizeof (XftFontInfo)); | |||
739 | free (fi); | |||
740 | } | |||
741 | ||||
742 | _X_EXPORT__attribute__((visibility("default"))) FcChar32 | |||
743 | XftFontInfoHash (_Xconstconst XftFontInfo *fi) | |||
744 | { | |||
745 | return fi->hash; | |||
746 | } | |||
747 | ||||
748 | _X_EXPORT__attribute__((visibility("default"))) FcBool | |||
749 | XftFontInfoEqual (_Xconstconst XftFontInfo *a, _Xconstconst XftFontInfo *b) | |||
750 | { | |||
751 | return memcmp ((void *) a, (void *) b, sizeof (XftFontInfo)) == 0; | |||
752 | } | |||
753 | ||||
754 | _X_EXPORT__attribute__((visibility("default"))) XftFont * | |||
755 | XftFontOpenInfo (Display *dpy, | |||
756 | FcPattern *pattern, | |||
757 | XftFontInfo *fi) | |||
758 | { | |||
759 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True1); | |||
760 | FT_Face face; | |||
761 | XftFont **bucket; | |||
762 | XftFontInt *font; | |||
763 | XRenderPictFormat *format; | |||
764 | FcCharSet *charset; | |||
765 | FcChar32 num_unicode; | |||
766 | FcChar32 hash_value; | |||
767 | FcChar32 rehash_value; | |||
768 | FcBool antialias; | |||
769 | int max_glyph_memory; | |||
770 | int alloc_size; | |||
771 | int ascent, descent, height; | |||
772 | int i; | |||
773 | int num_glyphs; | |||
774 | ||||
775 | if (!info) | |||
776 | return NULL((void*)0); | |||
777 | /* | |||
778 | * Find a matching previously opened font | |||
779 | */ | |||
780 | bucket = &info->fontHash[fi->hash % XFT_NUM_FONT_HASH127]; | |||
781 | for (font = (XftFontInt *) *bucket; font; font = (XftFontInt *) font->hash_next) | |||
782 | if (XftFontInfoEqual (&font->info, fi)) | |||
783 | { | |||
784 | if (!font->ref++) | |||
785 | --info->num_unref_fonts; | |||
786 | FcPatternDestroy (pattern); | |||
787 | return &font->public; | |||
788 | } | |||
789 | ||||
790 | /* | |||
791 | * No existing font, create another. | |||
792 | */ | |||
793 | ||||
794 | if (XftDebug () & XFT_DBG_CACHE128) | |||
795 | printf ("New font %s/%d size %dx%d\n", | |||
796 | fi->file->file, fi->file->id, | |||
797 | (int) fi->xsize >> 6, (int) fi->ysize >> 6); | |||
798 | ||||
799 | if (FcPatternGetInteger (pattern, XFT_MAX_GLYPH_MEMORY"maxglyphmemory", 0, | |||
800 | &max_glyph_memory) != FcResultMatch) | |||
801 | max_glyph_memory = XFT_FONT_MAX_GLYPH_MEMORY(1024 * 1024); | |||
802 | ||||
803 | face = _XftLockFile (fi->file); | |||
804 | if (!face) | |||
805 | goto bail0; | |||
806 | ||||
807 | if (!_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix)) | |||
808 | goto bail1; | |||
809 | ||||
810 | /* | |||
811 | * Get the set of Unicode codepoints covered by the font. | |||
812 | * If the incoming pattern doesn't provide this data, go | |||
813 | * off and compute it. Yes, this is expensive, but it's | |||
814 | * required to map Unicode to glyph indices. | |||
815 | */ | |||
816 | if (FcPatternGetCharSet (pattern, FC_CHARSET"charset", 0, &charset) == FcResultMatch) | |||
817 | charset = FcCharSetCopy (charset); | |||
818 | else | |||
819 | charset = FcFreeTypeCharSet (face, FcConfigGetBlanks (NULL((void*)0))); | |||
820 | ||||
821 | antialias = fi->antialias; | |||
822 | if (!(face->face_flags & FT_FACE_FLAG_SCALABLE( 1L << 0 ))) | |||
823 | antialias = FcFalse0; | |||
824 | ||||
825 | /* | |||
826 | * Find the appropriate picture format | |||
827 | */ | |||
828 | if (fi->render) | |||
829 | { | |||
830 | if (antialias) | |||
831 | { | |||
832 | switch (fi->rgba) { | |||
833 | case FC_RGBA_RGB1: | |||
834 | case FC_RGBA_BGR2: | |||
835 | case FC_RGBA_VRGB3: | |||
836 | case FC_RGBA_VBGR4: | |||
837 | format = XRenderFindStandardFormat (dpy, PictStandardARGB320); | |||
838 | break; | |||
839 | default: | |||
840 | format = XRenderFindStandardFormat (dpy, PictStandardA82); | |||
841 | break; | |||
842 | } | |||
843 | } | |||
844 | else | |||
845 | { | |||
846 | format = XRenderFindStandardFormat (dpy, PictStandardA14); | |||
847 | } | |||
848 | ||||
849 | if (!format) | |||
850 | goto bail2; | |||
851 | } | |||
852 | else | |||
853 | format = NULL((void*)0); | |||
854 | ||||
855 | if (charset) | |||
856 | { | |||
857 | num_unicode = FcCharSetCount (charset); | |||
858 | hash_value = _XftHashSize (num_unicode); | |||
859 | rehash_value = hash_value - 2; | |||
860 | } | |||
861 | else | |||
862 | { | |||
863 | num_unicode = 0; | |||
864 | hash_value = 0; | |||
865 | rehash_value = 0; | |||
866 | } | |||
867 | ||||
868 | /* | |||
869 | * Sometimes the glyphs are numbered 1..n, other times 0..n-1, | |||
870 | * accept either numbering scheme by making room in the table | |||
871 | */ | |||
872 | num_glyphs = face->num_glyphs + 1; | |||
873 | alloc_size = (sizeof (XftFontInt) + | |||
874 | num_glyphs * sizeof (XftGlyph *) + | |||
875 | hash_value * sizeof (XftUcsHash)); | |||
876 | font = malloc (alloc_size); | |||
877 | ||||
878 | if (!font) | |||
879 | goto bail2; | |||
880 | ||||
881 | XftMemAlloc (XFT_MEM_FONT1, alloc_size); | |||
882 | ||||
883 | /* | |||
884 | * Public fields | |||
885 | */ | |||
886 | if (fi->transform) | |||
887 | { | |||
888 | FT_Vector vector; | |||
889 | ||||
890 | vector.x = 0; | |||
891 | vector.y = face->size->metrics.descender; | |||
892 | FT_Vector_Transform (&vector, &fi->matrix); | |||
893 | descent = -(vector.y >> 6); | |||
894 | ||||
895 | vector.x = 0; | |||
896 | vector.y = face->size->metrics.ascender; | |||
897 | FT_Vector_Transform (&vector, &fi->matrix); | |||
898 | ascent = vector.y >> 6; | |||
899 | ||||
900 | if (fi->minspace) | |||
901 | height = ascent + descent; | |||
902 | else | |||
903 | { | |||
904 | vector.x = 0; | |||
905 | vector.y = face->size->metrics.height; | |||
906 | FT_Vector_Transform (&vector, &fi->matrix); | |||
907 | height = vector.y >> 6; | |||
908 | } | |||
909 | } | |||
910 | else | |||
911 | { | |||
912 | descent = -(face->size->metrics.descender >> 6); | |||
913 | ascent = face->size->metrics.ascender >> 6; | |||
914 | if (fi->minspace) | |||
915 | height = ascent + descent; | |||
916 | else | |||
917 | height = face->size->metrics.height >> 6; | |||
918 | } | |||
919 | font->public.ascent = ascent; | |||
920 | font->public.descent = descent; | |||
921 | font->public.height = height; | |||
922 | ||||
923 | if (fi->char_width) | |||
924 | font->public.max_advance_width = fi->char_width; | |||
925 | else | |||
926 | { | |||
927 | if (fi->transform) | |||
928 | { | |||
929 | FT_Vector vector; | |||
930 | vector.x = face->size->metrics.max_advance; | |||
931 | vector.y = 0; | |||
932 | FT_Vector_Transform (&vector, &fi->matrix); | |||
933 | font->public.max_advance_width = vector.x >> 6; | |||
934 | } | |||
935 | else | |||
936 | font->public.max_advance_width = face->size->metrics.max_advance >> 6; | |||
937 | } | |||
938 | font->public.charset = charset; | |||
939 | font->public.pattern = pattern; | |||
940 | ||||
941 | /* | |||
942 | * Management fields | |||
943 | */ | |||
944 | font->ref = 1; | |||
945 | ||||
946 | font->next = info->fonts; | |||
947 | info->fonts = &font->public; | |||
948 | ||||
949 | font->hash_next = *bucket; | |||
950 | *bucket = &font->public; | |||
951 | ||||
952 | /* | |||
953 | * Copy the info over | |||
954 | */ | |||
955 | font->info = *fi; | |||
956 | /* | |||
957 | * reset the antialias field. It can't | |||
958 | * be set correctly until the font is opened, | |||
959 | * which doesn't happen in XftFontInfoFill | |||
960 | */ | |||
961 | font->info.antialias = antialias; | |||
962 | /* | |||
963 | * bump XftFile reference count | |||
964 | */ | |||
965 | font->info.file->ref++; | |||
966 | ||||
967 | /* | |||
968 | * Per glyph information | |||
969 | */ | |||
970 | font->glyphs = (XftGlyph **) (font + 1); | |||
971 | memset (font->glyphs, '\0', num_glyphs * sizeof (XftGlyph *))__builtin___memset_chk (font->glyphs, '\0', num_glyphs * sizeof (XftGlyph *), __builtin_object_size (font->glyphs, 0)); | |||
972 | font->num_glyphs = num_glyphs; | |||
973 | /* | |||
974 | * Unicode hash table information | |||
975 | */ | |||
976 | font->hash_table = (XftUcsHash *) (font->glyphs + font->num_glyphs); | |||
977 | for (i = 0; i < hash_value; i++) | |||
978 | { | |||
979 | font->hash_table[i].ucs4 = ((FcChar32) ~0); | |||
980 | font->hash_table[i].glyph = 0; | |||
981 | } | |||
982 | font->hash_value = hash_value; | |||
983 | font->rehash_value = rehash_value; | |||
984 | /* | |||
985 | * X specific fields | |||
986 | */ | |||
987 | font->glyphset = 0; | |||
988 | font->format = format; | |||
989 | ||||
990 | /* | |||
991 | * Glyph memory management fields | |||
992 | */ | |||
993 | font->glyph_memory = 0; | |||
994 | font->max_glyph_memory = max_glyph_memory; | |||
995 | font->use_free_glyphs = info->use_free_glyphs; | |||
996 | ||||
997 | _XftUnlockFile (fi->file); | |||
998 | ||||
999 | return &font->public; | |||
1000 | ||||
1001 | bail2: | |||
1002 | FcCharSetDestroy (charset); | |||
1003 | bail1: | |||
1004 | _XftUnlockFile (fi->file); | |||
1005 | bail0: | |||
1006 | return NULL((void*)0); | |||
1007 | } | |||
1008 | ||||
1009 | _X_EXPORT__attribute__((visibility("default"))) XftFont * | |||
1010 | XftFontOpenPattern (Display *dpy, FcPattern *pattern) | |||
1011 | { | |||
1012 | XftFontInfo info; | |||
1013 | XftFont *font; | |||
1014 | ||||
1015 | if (!XftFontInfoFill (dpy, pattern, &info)) | |||
1016 | return NULL((void*)0); | |||
1017 | ||||
1018 | font = XftFontOpenInfo (dpy, pattern, &info); | |||
1019 | XftFontInfoEmpty (dpy, &info); | |||
1020 | return font; | |||
1021 | } | |||
1022 | ||||
1023 | _X_EXPORT__attribute__((visibility("default"))) XftFont * | |||
1024 | XftFontCopy (Display *dpy, XftFont *public) | |||
1025 | { | |||
1026 | XftFontInt *font = (XftFontInt *) public; | |||
1027 | ||||
1028 | font->ref++; | |||
1029 | return public; | |||
1030 | } | |||
1031 | ||||
1032 | static void | |||
1033 | XftFontDestroy (Display *dpy, XftFont *public) | |||
1034 | { | |||
1035 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False0); | |||
1036 | XftFontInt *font = (XftFontInt *) public; | |||
1037 | int i; | |||
1038 | ||||
1039 | /* note reduction in memory use */ | |||
1040 | if (info) | |||
1041 | info->glyph_memory -= font->glyph_memory; | |||
1042 | /* Clean up the info */ | |||
1043 | XftFontInfoEmpty (dpy, &font->info); | |||
1044 | /* Free the glyphset */ | |||
1045 | if (font->glyphset) | |||
1046 | XRenderFreeGlyphSet (dpy, font->glyphset); | |||
1047 | /* Free the glyphs */ | |||
1048 | for (i = 0; i < font->num_glyphs; i++) | |||
1049 | { | |||
1050 | XftGlyph *xftg = font->glyphs[i]; | |||
1051 | if (xftg) | |||
1052 | { | |||
1053 | if (xftg->bitmap) | |||
1054 | free (xftg->bitmap); | |||
1055 | free (xftg); | |||
1056 | } | |||
1057 | } | |||
1058 | ||||
1059 | /* Free the pattern and the charset */ | |||
1060 | FcPatternDestroy (font->public.pattern); | |||
1061 | FcCharSetDestroy (font->public.charset); | |||
1062 | ||||
1063 | /* Finally, free the font structure */ | |||
1064 | XftMemFree (XFT_MEM_FONT1, sizeof (XftFontInt) + | |||
1065 | font->num_glyphs * sizeof (XftGlyph *) + | |||
1066 | font->hash_value * sizeof (XftUcsHash)); | |||
1067 | free (font); | |||
1068 | } | |||
1069 | ||||
1070 | static XftFont * | |||
1071 | XftFontFindNthUnref (XftDisplayInfo *info, int n) | |||
1072 | { | |||
1073 | XftFont *public; | |||
1074 | XftFontInt *font; | |||
1075 | ||||
1076 | for (public = info->fonts; public; public = font->next) | |||
1077 | { | |||
1078 | font = (XftFontInt*) public; | |||
1079 | if (!font->ref && !n--) | |||
1080 | break; | |||
1081 | } | |||
1082 | return public; | |||
1083 | } | |||
1084 | ||||
1085 | _X_HIDDEN__attribute__((visibility("hidden"))) void | |||
1086 | XftFontManageMemory (Display *dpy) | |||
1087 | { | |||
1088 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False0); | |||
1089 | XftFont **prev; | |||
1090 | XftFont *public; | |||
1091 | XftFontInt *font; | |||
1092 | ||||
1093 | if (!info) | |||
1094 | return; | |||
1095 | while (info->num_unref_fonts > info->max_unref_fonts) | |||
1096 | { | |||
1097 | public = XftFontFindNthUnref (info, rand() % info->num_unref_fonts); | |||
1098 | font = (XftFontInt *) public; | |||
1099 | ||||
1100 | if (XftDebug () & XFT_DBG_CACHE128) | |||
1101 | printf ("freeing unreferenced font %s/%d size %dx%d\n", | |||
1102 | font->info.file->file, font->info.file->id, | |||
1103 | (int) font->info.xsize >> 6, (int) font->info.ysize >> 6); | |||
1104 | ||||
1105 | /* Unhook from display list */ | |||
1106 | for (prev = &info->fonts; *prev; prev = &(*(XftFontInt **) prev)->next) | |||
1107 | { | |||
1108 | if (*prev == public) | |||
1109 | { | |||
1110 | *prev = font->next; | |||
1111 | break; | |||
1112 | } | |||
1113 | } | |||
1114 | /* Unhook from hash list */ | |||
1115 | for (prev = &info->fontHash[font->info.hash % XFT_NUM_FONT_HASH127]; | |||
1116 | *prev; | |||
1117 | prev = &(*(XftFontInt **) prev)->hash_next) | |||
1118 | { | |||
1119 | if (*prev == public) | |||
1120 | { | |||
1121 | *prev = font->hash_next; | |||
1122 | break; | |||
1123 | } | |||
1124 | } | |||
1125 | /* Destroy the font */ | |||
1126 | XftFontDestroy (dpy, public); | |||
1127 | --info->num_unref_fonts; | |||
1128 | } | |||
1129 | } | |||
1130 | ||||
1131 | _X_EXPORT__attribute__((visibility("default"))) void | |||
1132 | XftFontClose (Display *dpy, XftFont *public) | |||
1133 | { | |||
1134 | XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False0); | |||
1135 | XftFontInt *font = (XftFontInt *) public; | |||
1136 | ||||
1137 | if (--font->ref != 0) | |||
1138 | return; | |||
1139 | ||||
1140 | if (info) | |||
1141 | { | |||
1142 | ++info->num_unref_fonts; | |||
1143 | XftFontManageMemory (dpy); | |||
1144 | } | |||
1145 | else | |||
1146 | { | |||
1147 | XftFontDestroy (dpy, public); | |||
1148 | } | |||
1149 | } | |||
1150 | ||||
1151 | _X_EXPORT__attribute__((visibility("default"))) FcBool | |||
1152 | XftInitFtLibrary (void) | |||
1153 | { | |||
1154 | if (_XftFTlibrary) | |||
1155 | return FcTrue1; | |||
1156 | if (FT_Init_FreeType (&_XftFTlibrary)) | |||
1157 | return FcFalse0; | |||
1158 | return FcTrue1; | |||
1159 | } |