File: | xftfreetype.c |
Location: | line 863, column 2 |
Description: | Value stored to 'num_unicode' is never read |
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); |
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 (stderrstderr, "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)); |
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; |
Value stored to 'num_unicode' is never read | |
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 *)); |
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 | } |