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 FT_Library _XftFTlibrary;
26
27 #define FT_Matrix_Equal(a,b) ((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 *
_XftGetFile(const FcChar8 * file,int id)39 _XftGetFile (const FcChar8 *file, int id)
40 {
41 XftFtFile *f;
42
43 if (!XftInitFtLibrary ())
44 return NULL;
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_REF)
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;
60
61 XftMemAlloc (XFT_MEM_FILE, (int)(sizeof (XftFtFile) + strlen ((char *) file) + 1));
62 if (XftDebug () & XFT_DBG_REF)
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;
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 *
_XftGetFaceFile(FT_Face face)83 _XftGetFaceFile (FT_Face face)
84 {
85 XftFtFile *f;
86
87 f = malloc (sizeof (XftFtFile));
88 if (!f)
89 return NULL;
90 XftMemAlloc (XFT_MEM_FILE, sizeof(XftFtFile));
91 f->next = NULL;
92
93 f->ref = 1;
94
95 f->file = NULL;
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
_XftNumFiles(void)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 *
_XftNthFile(int n)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
_XftUncacheFiles(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_REF)
139 printf ("Discard file %s/%d from cache\n",
140 f->file, f->id);
141 FT_Done_Face (f->face);
142 f->face = NULL;
143 }
144 }
145 }
146
147 static FT_Face
_XftLockFile(XftFtFile * f)148 _XftLockFile (XftFtFile *f)
149 {
150 ++f->lock;
151 if (!f->face)
152 {
153 if (XftDebug() & XFT_DBG_REF)
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
_XftLockError(const char * reason)167 _XftLockError (const char *reason)
168 {
169 fprintf (stderr, "Xft: locking error %s\n", reason);
170 }
171
172 static void
_XftUnlockFile(XftFtFile * f)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)
180 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
181
182 _X_HIDDEN FcBool
_XftSetFace(XftFtFile * f,FT_F26Dot6 xsize,FT_F26Dot6 ysize,FT_Matrix * matrix)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_GLYPH)
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))
197 {
198 int i, best = 0;
199
200 #define xft_abs(a) ((a) < 0 ? -(a) : (a))
201 #define dist(a,b) (xft_abs((a)-(b)))
202
203 for (i = 1; i < face->num_fixed_sizes; i++)
204 {
205 if (dist (ysize, Y_SIZE(face,i)) <
206 dist (ysize, Y_SIZE(face, best)) ||
207 (dist (ysize, Y_SIZE(face, i)) ==
208 dist (ysize, Y_SIZE(face, best)) &&
209 dist (xsize, X_SIZE(face, i)) <
210 dist (xsize, X_SIZE(face, best))))
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 False;
230 }
231 }
232 else
233 {
234 if (FT_Set_Char_Size (face, xsize, ysize, 0, 0))
235 {
236 return False;
237 }
238 }
239 f->xsize = xsize;
240 f->ysize = ysize;
241 }
242 if (!FT_Matrix_Equal (&f->matrix, matrix))
243 {
244 if (XftDebug() & XFT_DBG_GLYPH)
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);
251 f->matrix = *matrix;
252 }
253 return True;
254 }
255
256 static void
_XftReleaseFile(XftFtFile * f)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_FILE,
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
_XftSqrt(FcChar32 a)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
_XftIsPrime(FcChar32 i)306 _XftIsPrime (FcChar32 i)
307 {
308 FcChar32 l, t;
309
310 if (i < 2)
311 return FcFalse;
312 if ((i & 1) == 0)
313 {
314 if (i == 2)
315 return FcTrue;
316 return FcFalse;
317 }
318 l = _XftSqrt (i) + 1;
319 for (t = 3; t <= l; t += 2)
320 if (i % t == 0)
321 return FcFalse;
322 return FcTrue;
323 }
324
325 static FcChar32
_XftHashSize(FcChar32 num_unicode)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 FT_Face
XftLockFace(XftFont * public)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;
353 }
354 return face;
355 }
356
357 _X_EXPORT void
XftUnlockFace(XftFont * public)358 XftUnlockFace (XftFont *public)
359 {
360 XftFontInt *font = (XftFontInt *) public;
361 _XftUnlockFile (font->info.file);
362 }
363
364 static FcBool
XftFontInfoFill(Display * dpy,_Xconst FcPattern * pattern,XftFontInfo * fi)365 XftFontInfoFill (Display *dpy, _Xconst FcPattern *pattern, XftFontInfo *fi)
366 {
367 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
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 FcFalse;
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, 0, &filename)) {
394 case FcResultNoMatch:
395 filename = NULL;
396 break;
397 case FcResultMatch:
398 break;
399 default:
400 goto bail0;
401 }
402
403 switch (FcPatternGetInteger (pattern, FC_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, 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, 0, &dsize) != FcResultMatch)
425 goto bail1;
426
427 if (FcPatternGetDouble (pattern, FC_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_OPEN)
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, 0, &fi->antialias)) {
440 case FcResultNoMatch:
441 fi->antialias = True;
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, 0, &fi->rgba)) {
453 case FcResultNoMatch:
454 fi->rgba = FC_RGBA_UNKNOWN;
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, 0, &fi->lcd_filter)) {
466 case FcResultNoMatch:
467 fi->lcd_filter = FC_LCD_DEFAULT;
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, 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 = (FT_Fixed)(0x10000L * font_matrix->xx);
485 fi->matrix.yy = (FT_Fixed)(0x10000L * font_matrix->yy);
486 fi->matrix.xy = (FT_Fixed)(0x10000L * font_matrix->xy);
487 fi->matrix.yx = (FT_Fixed)(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, 0, &fi->render)) {
502 case FcResultTypeMismatch:
503 /*
504 * Fontconfig no longer supports xft's custom values in
505 * text patterns, so any name specifying render:true or
506 * render:false will have an invalid type in the resulting
507 * pattern. Just ignore that case so that the app doesn't
508 * just fail
509 */
510 /* fall through ... */
511 case FcResultNoMatch:
512 fi->render = info->hasRender;
513 break;
514 case FcResultMatch:
515 break;
516 default:
517 goto bail1;
518 }
519 }
520 else
521 fi->render = FcFalse;
522
523 /*
524 * Compute glyph load flags
525 */
526 fi->load_flags = FT_LOAD_DEFAULT;
527
528 #ifndef XFT_EMBEDDED_BITMAP
529 #define XFT_EMBEDDED_BITMAP "embeddedbitmap"
530 #endif
531
532 switch (FcPatternGetBool (pattern, XFT_EMBEDDED_BITMAP, 0, &bitmap)) {
533 case FcResultNoMatch:
534 bitmap = FcFalse;
535 break;
536 case FcResultMatch:
537 break;
538 default:
539 goto bail1;
540 }
541
542 /* disable bitmaps when anti-aliasing or transforming glyphs */
543 if ((!bitmap && fi->antialias) || fi->transform)
544 fi->load_flags |= FT_LOAD_NO_BITMAP;
545
546 /* disable hinting if requested */
547 switch (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting)) {
548 case FcResultNoMatch:
549 hinting = FcTrue;
550 break;
551 case FcResultMatch:
552 break;
553 default:
554 goto bail1;
555 }
556
557 switch (FcPatternGetBool (pattern, FC_EMBOLDEN, 0, &fi->embolden)) {
558 case FcResultNoMatch:
559 fi->embolden = FcFalse;
560 break;
561 case FcResultMatch:
562 break;
563 default:
564 goto bail1;
565 }
566
567 switch (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style)) {
568 case FcResultNoMatch:
569 hint_style = FC_HINT_FULL;
570 break;
571 case FcResultMatch:
572 break;
573 default:
574 goto bail1;
575 }
576
577 if (!hinting
578 || hint_style == FC_HINT_NONE
579 )
580 {
581 fi->load_flags |= FT_LOAD_NO_HINTING;
582 }
583
584 /* Figure out the load target, which modifies the hinting
585 * behavior of FreeType based on the intended use of the glyphs.
586 */
587 if (fi->antialias)
588 {
589 if (FC_HINT_NONE < hint_style && hint_style < FC_HINT_FULL)
590 {
591 fi->load_flags |= FT_LOAD_TARGET_LIGHT;
592 }
593 else
594 {
595 /* autohinter will snap stems to integer widths, when
596 * the LCD targets are used.
597 */
598 switch (fi->rgba) {
599 case FC_RGBA_RGB:
600 case FC_RGBA_BGR:
601 fi->load_flags |= FT_LOAD_TARGET_LCD;
602 break;
603 case FC_RGBA_VRGB:
604 case FC_RGBA_VBGR:
605 fi->load_flags |= FT_LOAD_TARGET_LCD_V;
606 break;
607 }
608 }
609 }
610 else
611 fi->load_flags |= FT_LOAD_TARGET_MONO;
612
613 /* set vertical layout if requested */
614 switch (FcPatternGetBool (pattern, FC_VERTICAL_LAYOUT, 0, &vertical_layout)) {
615 case FcResultNoMatch:
616 vertical_layout = FcFalse;
617 break;
618 case FcResultMatch:
619 break;
620 default:
621 goto bail1;
622 }
623
624 if (vertical_layout)
625 fi->load_flags |= FT_LOAD_VERTICAL_LAYOUT;
626
627 /* force autohinting if requested */
628 switch (FcPatternGetBool (pattern, FC_AUTOHINT, 0, &autohint)) {
629 case FcResultNoMatch:
630 autohint = FcFalse;
631 break;
632 case FcResultMatch:
633 break;
634 default:
635 goto bail1;
636 }
637
638 if (autohint)
639 fi->load_flags |= FT_LOAD_FORCE_AUTOHINT;
640
641 /* disable global advance width (for broken DynaLab TT CJK fonts) */
642 switch (FcPatternGetBool (pattern, FC_GLOBAL_ADVANCE, 0, &global_advance)) {
643 case FcResultNoMatch:
644 global_advance = FcTrue;
645 break;
646 case FcResultMatch:
647 break;
648 default:
649 goto bail1;
650 }
651
652 if (!global_advance)
653 fi->load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
654
655 /*
656 * Get requested spacing value
657 */
658 switch (FcPatternGetInteger (pattern, FC_SPACING, 0, &fi->spacing)) {
659 case FcResultNoMatch:
660 fi->spacing = FC_PROPORTIONAL;
661 break;
662 case FcResultMatch:
663 break;
664 default:
665 goto bail1;
666 }
667
668 /*
669 * Check for minspace
670 */
671
672 switch (FcPatternGetBool (pattern, FC_MINSPACE, 0, &fi->minspace)) {
673 case FcResultNoMatch:
674 fi->minspace = FcFalse;
675 break;
676 case FcResultMatch:
677 break;
678 default:
679 goto bail1;
680 }
681 /*
682 * Check for fixed pixel spacing
683 */
684 switch (FcPatternGetInteger (pattern, FC_CHAR_WIDTH, 0, &fi->char_width)) {
685 case FcResultNoMatch:
686 fi->char_width = 0;
687 break;
688 case FcResultMatch:
689 if (fi->char_width)
690 fi->spacing = FC_MONO;
691 break;
692 default:
693 goto bail1;
694 }
695
696 /*
697 * Step over hash value in the structure
698 */
699 hash = 0;
700 hashp = (FcChar32 *) fi + 1;
701 nhash = (sizeof (XftFontInfo) / sizeof (FcChar32)) - 1;
702
703 while (nhash--)
704 hash += *hashp++;
705 fi->hash = hash;
706
707 /*
708 * All done
709 */
710 return FcTrue;
711
712 bail1:
713 _XftReleaseFile (fi->file);
714 fi->file = NULL;
715 bail0:
716 return FcFalse;
717 }
718
719 static void
XftFontInfoEmpty(Display * dpy,XftFontInfo * fi)720 XftFontInfoEmpty (Display *dpy, XftFontInfo *fi)
721 {
722 if (fi->file)
723 _XftReleaseFile (fi->file);
724 }
725
726 XftFontInfo *
XftFontInfoCreate(Display * dpy,_Xconst FcPattern * pattern)727 XftFontInfoCreate (Display *dpy, _Xconst FcPattern *pattern)
728 {
729 XftFontInfo *fi = malloc (sizeof (XftFontInfo));
730
731 if (!fi)
732 return NULL;
733
734 if (!XftFontInfoFill (dpy, pattern, fi))
735 {
736 free (fi);
737 fi = NULL;
738 }
739 XftMemAlloc (XFT_MEM_FONT, sizeof (XftFontInfo));
740 return fi;
741 }
742
743 _X_EXPORT void
XftFontInfoDestroy(Display * dpy,XftFontInfo * fi)744 XftFontInfoDestroy (Display *dpy, XftFontInfo *fi)
745 {
746 XftFontInfoEmpty (dpy, fi);
747 XftMemFree (XFT_MEM_FONT, sizeof (XftFontInfo));
748 free (fi);
749 }
750
751 _X_EXPORT FcChar32
XftFontInfoHash(_Xconst XftFontInfo * fi)752 XftFontInfoHash (_Xconst XftFontInfo *fi)
753 {
754 return fi->hash;
755 }
756
757 _X_EXPORT FcBool
XftFontInfoEqual(_Xconst XftFontInfo * a,_Xconst XftFontInfo * b)758 XftFontInfoEqual (_Xconst XftFontInfo *a, _Xconst XftFontInfo *b)
759 {
760 return memcmp ((void *) a, (void *) b, sizeof (XftFontInfo)) == 0;
761 }
762
763 _X_EXPORT XftFont *
XftFontOpenInfo(Display * dpy,FcPattern * pattern,XftFontInfo * fi)764 XftFontOpenInfo (Display *dpy,
765 FcPattern *pattern,
766 XftFontInfo *fi)
767 {
768 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
769 FT_Face face;
770 XftFont **bucket;
771 XftFontInt *font;
772 XRenderPictFormat *format;
773 FcCharSet *charset;
774 FcChar32 num_unicode;
775 FcChar32 hash_value;
776 FcChar32 rehash_value;
777 FcBool antialias;
778 int max_glyph_memory;
779 int alloc_size;
780 int ascent, descent, height;
781 int i;
782 int num_glyphs;
783
784 if (!info)
785 return NULL;
786 /*
787 * Find a matching previously opened font
788 */
789 bucket = &info->fontHash[fi->hash % XFT_NUM_FONT_HASH];
790 for (font = (XftFontInt *) *bucket; font; font = (XftFontInt *) font->hash_next)
791 if (XftFontInfoEqual (&font->info, fi))
792 {
793 if (!font->ref++)
794 --info->num_unref_fonts;
795 FcPatternDestroy (pattern);
796 return &font->public;
797 }
798
799 /*
800 * No existing font, create another.
801 */
802
803 if (XftDebug () & XFT_DBG_CACHE)
804 printf ("New font %s/%d size %dx%d\n",
805 fi->file->file, fi->file->id,
806 (int) fi->xsize >> 6, (int) fi->ysize >> 6);
807
808 if (FcPatternGetInteger (pattern, XFT_MAX_GLYPH_MEMORY, 0,
809 &max_glyph_memory) != FcResultMatch)
810 max_glyph_memory = XFT_FONT_MAX_GLYPH_MEMORY;
811
812 face = _XftLockFile (fi->file);
813 if (!face)
814 goto bail0;
815
816 if (!_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix))
817 goto bail1;
818
819 /*
820 * Get the set of Unicode codepoints covered by the font.
821 * If the incoming pattern doesn't provide this data, go
822 * off and compute it. Yes, this is expensive, but it's
823 * required to map Unicode to glyph indices.
824 */
825 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) == FcResultMatch)
826 charset = FcCharSetCopy (charset);
827 else
828 charset = FcFreeTypeCharSet (face, FcConfigGetBlanks (NULL));
829
830 antialias = fi->antialias;
831 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
832 antialias = FcFalse;
833
834 /*
835 * Find the appropriate picture format
836 */
837 if (fi->render)
838 {
839 if (antialias)
840 {
841 switch (fi->rgba) {
842 case FC_RGBA_RGB:
843 case FC_RGBA_BGR:
844 case FC_RGBA_VRGB:
845 case FC_RGBA_VBGR:
846 format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
847 break;
848 default:
849 format = XRenderFindStandardFormat (dpy, PictStandardA8);
850 break;
851 }
852 }
853 else
854 {
855 format = XRenderFindStandardFormat (dpy, PictStandardA1);
856 }
857
858 if (!format)
859 goto bail2;
860 }
861 else
862 format = NULL;
863
864 if (charset)
865 {
866 num_unicode = FcCharSetCount (charset);
867 hash_value = _XftHashSize (num_unicode);
868 rehash_value = hash_value - 2;
869 }
870 else
871 {
872 num_unicode = 0;
873 hash_value = 0;
874 rehash_value = 0;
875 }
876
877 /*
878 * Sometimes the glyphs are numbered 1..n, other times 0..n-1,
879 * accept either numbering scheme by making room in the table
880 */
881 num_glyphs = (int)face->num_glyphs + 1;
882 alloc_size = (sizeof (XftFontInt) +
883 (size_t)num_glyphs * sizeof (XftGlyph *) +
884 hash_value * sizeof (XftUcsHash));
885 font = malloc ((size_t)alloc_size);
886
887 if (!font)
888 goto bail2;
889
890 XftMemAlloc (XFT_MEM_FONT, alloc_size);
891
892 /*
893 * Public fields
894 */
895 if (fi->transform)
896 {
897 FT_Vector vector;
898
899 vector.x = 0;
900 vector.y = face->size->metrics.descender;
901 FT_Vector_Transform (&vector, &fi->matrix);
902 descent = (int)(-(vector.y >> 6));
903
904 vector.x = 0;
905 vector.y = face->size->metrics.ascender;
906 FT_Vector_Transform (&vector, &fi->matrix);
907 ascent = (int)(vector.y >> 6);
908
909 if (fi->minspace)
910 height = ascent + descent;
911 else
912 {
913 vector.x = 0;
914 vector.y = face->size->metrics.height;
915 FT_Vector_Transform (&vector, &fi->matrix);
916 height = (int)(vector.y >> 6);
917 }
918 }
919 else
920 {
921 descent = -(int)(face->size->metrics.descender >> 6);
922 ascent = (int)(face->size->metrics.ascender >> 6);
923 if (fi->minspace)
924 height = ascent + descent;
925 else
926 height = (int)(face->size->metrics.height >> 6);
927 }
928 font->public.ascent = ascent;
929 font->public.descent = descent;
930 font->public.height = height;
931
932 if (fi->char_width)
933 font->public.max_advance_width = fi->char_width;
934 else
935 {
936 if (fi->transform)
937 {
938 FT_Vector vector;
939 vector.x = face->size->metrics.max_advance;
940 vector.y = 0;
941 FT_Vector_Transform (&vector, &fi->matrix);
942 font->public.max_advance_width = (int)(vector.x >> 6);
943 }
944 else
945 font->public.max_advance_width = (int)(face->size->metrics.max_advance >> 6);
946 }
947 font->public.charset = charset;
948 font->public.pattern = pattern;
949
950 /*
951 * Management fields
952 */
953 font->ref = 1;
954
955 font->next = info->fonts;
956 info->fonts = &font->public;
957
958 font->hash_next = *bucket;
959 *bucket = &font->public;
960
961 /*
962 * Copy the info over
963 */
964 font->info = *fi;
965 /*
966 * reset the antialias field. It can't
967 * be set correctly until the font is opened,
968 * which doesn't happen in XftFontInfoFill
969 */
970 font->info.antialias = antialias;
971 /*
972 * bump XftFile reference count
973 */
974 font->info.file->ref++;
975
976 /*
977 * Per glyph information
978 */
979 font->glyphs = (XftGlyph **) (font + 1);
980 memset (font->glyphs, '\0', (size_t)num_glyphs * sizeof (XftGlyph *));
981 font->num_glyphs = num_glyphs;
982 /*
983 * Unicode hash table information
984 */
985 font->hash_table = (XftUcsHash *) (font->glyphs + font->num_glyphs);
986 for (i = 0; i < hash_value; i++)
987 {
988 font->hash_table[i].ucs4 = ((FcChar32) ~0);
989 font->hash_table[i].glyph = 0;
990 }
991 font->hash_value = (int)hash_value;
992 font->rehash_value = (int)rehash_value;
993 /*
994 * X specific fields
995 */
996 font->glyphset = 0;
997 font->format = format;
998
999 /*
1000 * Glyph memory management fields
1001 */
1002 font->glyph_memory = 0;
1003 font->max_glyph_memory = (unsigned long)max_glyph_memory;
1004 font->use_free_glyphs = info->use_free_glyphs;
1005
1006 _XftUnlockFile (fi->file);
1007
1008 return &font->public;
1009
1010 bail2:
1011 FcCharSetDestroy (charset);
1012 bail1:
1013 _XftUnlockFile (fi->file);
1014 bail0:
1015 return NULL;
1016 }
1017
1018 _X_EXPORT XftFont *
XftFontOpenPattern(Display * dpy,FcPattern * pattern)1019 XftFontOpenPattern (Display *dpy, FcPattern *pattern)
1020 {
1021 XftFontInfo info;
1022 XftFont *font;
1023
1024 if (!XftFontInfoFill (dpy, pattern, &info))
1025 return NULL;
1026
1027 font = XftFontOpenInfo (dpy, pattern, &info);
1028 XftFontInfoEmpty (dpy, &info);
1029 return font;
1030 }
1031
1032 _X_EXPORT XftFont *
XftFontCopy(Display * dpy,XftFont * public)1033 XftFontCopy (Display *dpy, XftFont *public)
1034 {
1035 XftFontInt *font = (XftFontInt *) public;
1036
1037 font->ref++;
1038 return public;
1039 }
1040
1041 static void
XftFontDestroy(Display * dpy,XftFont * public)1042 XftFontDestroy (Display *dpy, XftFont *public)
1043 {
1044 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False);
1045 XftFontInt *font = (XftFontInt *) public;
1046 int i;
1047
1048 /* note reduction in memory use */
1049 if (info)
1050 info->glyph_memory -= font->glyph_memory;
1051 /* Clean up the info */
1052 XftFontInfoEmpty (dpy, &font->info);
1053 /* Free the glyphset */
1054 if (font->glyphset)
1055 XRenderFreeGlyphSet (dpy, font->glyphset);
1056 /* Free the glyphs */
1057 for (i = 0; i < font->num_glyphs; i++)
1058 {
1059 XftGlyph *xftg = font->glyphs[i];
1060 if (xftg)
1061 {
1062 if (xftg->bitmap)
1063 free (xftg->bitmap);
1064 free (xftg);
1065 }
1066 }
1067
1068 /* Free the pattern and the charset */
1069 FcPatternDestroy (font->public.pattern);
1070 FcCharSetDestroy (font->public.charset);
1071
1072 /* Finally, free the font structure */
1073 XftMemFree (XFT_MEM_FONT, (sizeof (XftFontInt) +
1074 (size_t)font->num_glyphs * sizeof (XftGlyph *) +
1075 (size_t)font->hash_value * sizeof (XftUcsHash)));
1076 free (font);
1077 }
1078
1079 static XftFont *
XftFontFindNthUnref(XftDisplayInfo * info,int n)1080 XftFontFindNthUnref (XftDisplayInfo *info, int n)
1081 {
1082 XftFont *public;
1083 XftFontInt *font;
1084
1085 for (public = info->fonts; public; public = font->next)
1086 {
1087 font = (XftFontInt*) public;
1088 if (!font->ref && !n--)
1089 break;
1090 }
1091 return public;
1092 }
1093
1094 _X_HIDDEN void
XftFontManageMemory(Display * dpy)1095 XftFontManageMemory (Display *dpy)
1096 {
1097 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False);
1098 XftFont **prev;
1099 XftFont *public;
1100 XftFontInt *font;
1101
1102 if (!info)
1103 return;
1104 while (info->num_unref_fonts > info->max_unref_fonts)
1105 {
1106 public = XftFontFindNthUnref (info, rand() % info->num_unref_fonts);
1107 font = (XftFontInt *) public;
1108
1109 if (XftDebug () & XFT_DBG_CACHE)
1110 printf ("freeing unreferenced font %s/%d size %dx%d\n",
1111 font->info.file->file, font->info.file->id,
1112 (int) font->info.xsize >> 6, (int) font->info.ysize >> 6);
1113
1114 /* Unhook from display list */
1115 for (prev = &info->fonts; *prev; prev = &(*(XftFontInt **) prev)->next)
1116 {
1117 if (*prev == public)
1118 {
1119 *prev = font->next;
1120 break;
1121 }
1122 }
1123 /* Unhook from hash list */
1124 for (prev = &info->fontHash[font->info.hash % XFT_NUM_FONT_HASH];
1125 *prev;
1126 prev = &(*(XftFontInt **) prev)->hash_next)
1127 {
1128 if (*prev == public)
1129 {
1130 *prev = font->hash_next;
1131 break;
1132 }
1133 }
1134 /* Destroy the font */
1135 XftFontDestroy (dpy, public);
1136 --info->num_unref_fonts;
1137 }
1138 }
1139
1140 _X_EXPORT void
XftFontClose(Display * dpy,XftFont * public)1141 XftFontClose (Display *dpy, XftFont *public)
1142 {
1143 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False);
1144 XftFontInt *font = (XftFontInt *) public;
1145
1146 if (--font->ref != 0)
1147 return;
1148
1149 if (info)
1150 {
1151 ++info->num_unref_fonts;
1152 XftFontManageMemory (dpy);
1153 }
1154 else
1155 {
1156 XftFontDestroy (dpy, public);
1157 }
1158 }
1159
1160 _X_EXPORT FcBool
XftInitFtLibrary(void)1161 XftInitFtLibrary (void)
1162 {
1163 if (_XftFTlibrary)
1164 return FcTrue;
1165 if (FT_Init_FreeType (&_XftFTlibrary))
1166 return FcFalse;
1167 return FcTrue;
1168 }
1169