2 * Copyright © 2000 Keith Packard
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.
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.
25 _X_HIDDEN FT_Library _XftFTlibrary;
27 #define FT_Matrix_Equal(a,b) ((a)->xx == (b)->xx && \
28 (a)->yy == (b)->yy && \
29 (a)->xy == (b)->xy && \
32 * List of all open files (each face in a file is managed separately)
35 static XftFtFile *_XftFtFiles;
36 static int XftMaxFreeTypeFiles = 5;
39 _XftGetFile (const FcChar8 *file, int id)
43 if (!XftInitFtLibrary ())
46 for (f = _XftFtFiles; f; f = f->next)
48 if (!strcmp (f->file, (char *) file) && f->id == id)
51 if (XftDebug () & XFT_DBG_REF)
52 printf ("FontFile %s/%d matches existing (%d)\n",
57 f = malloc (sizeof (XftFtFile) + strlen ((char *) file) + 1);
61 XftMemAlloc (XFT_MEM_FILE, sizeof (XftFtFile) + strlen ((char *) file) + 1);
62 if (XftDebug () & XFT_DBG_REF)
63 printf ("FontFile %s/%d matches new\n",
65 f->next = _XftFtFiles;
70 f->file = (char *) (f+1);
71 strcpy (f->file, (char *) file);
78 f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0;
83 _XftGetFaceFile (FT_Face face)
87 f = malloc (sizeof (XftFtFile));
90 XftMemAlloc (XFT_MEM_FILE, sizeof(XftFtFile));
101 f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0;
110 for (f = _XftFtFiles; f; f = f->next)
111 if (f->face && !f->lock)
121 for (f = _XftFtFiles; f; f = f->next)
122 if (f->face && !f->lock)
129 _XftUncacheFiles (void)
133 while ((n = _XftNumFiles ()) > XftMaxFreeTypeFiles)
135 f = _XftNthFile (rand () % n);
138 if (XftDebug() & XFT_DBG_REF)
139 printf ("Discard file %s/%d from cache\n",
141 FT_Done_Face (f->face);
148 _XftLockFile (XftFtFile *f)
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))
160 f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0;
167 _XftLockError (const char *reason)
169 fprintf (stderr, "Xft: locking error %s\n", reason);
173 _XftUnlockFile (XftFtFile *f)
176 _XftLockError ("too many file unlocks");
179 #define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
180 #define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
183 _XftSetFace (XftFtFile *f, FT_F26Dot6 xsize, FT_F26Dot6 ysize, FT_Matrix *matrix)
185 FT_Face face = f->face;
187 if (f->xsize != xsize || f->ysize != ysize)
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);
193 * Bitmap only faces must match exactly, so find the closest
194 * one (height dominant search)
196 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
200 #define xft_abs(a) ((a) < 0 ? -(a) : (a))
201 #define dist(a,b) (xft_abs((a)-(b)))
203 for (i = 1; i < face->num_fixed_sizes; i++)
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))))
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.
222 if (FT_Set_Char_Size (face, face->available_sizes[best].x_ppem,
223 face->available_sizes[best].y_ppem, 0, 0) != 0
225 FT_Set_Char_Size (face, face->available_sizes[best].width << 6,
226 face->available_sizes[best].height << 6,
234 if (FT_Set_Char_Size (face, xsize, ysize, 0, 0))
242 if (!FT_Matrix_Equal (&f->matrix, matrix))
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);
257 _XftReleaseFile (XftFtFile *f)
264 _XftLockError ("Attempt to close locked file");
267 for (prev = &_XftFtFiles; *prev; prev = &(*prev)->next)
276 FT_Done_Face (f->face);
278 XftMemFree (XFT_MEM_FILE,
279 sizeof (XftFtFile) + (f->file ? strlen (f->file) + 1 : 0));
284 * Find a prime larger than the minimum reasonable hash size
288 _XftSqrt (FcChar32 a)
306 _XftIsPrime (FcChar32 i)
318 l = _XftSqrt (i) + 1;
319 for (t = 3; t <= l; t += 2)
326 _XftHashSize (FcChar32 num_unicode)
328 /* at least 31.25 % extra space */
329 FcChar32 hash = num_unicode + (num_unicode >> 2) + (num_unicode >> 4);
333 while (!_XftIsPrime (hash))
339 XftLockFace (XftFont *public)
341 XftFontInt *font = (XftFontInt *) public;
342 XftFontInfo *fi = &font->info;
345 face = _XftLockFile (fi->file);
347 * Make sure the face is usable at the requested size
349 if (face && !_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix))
351 _XftUnlockFile (fi->file);
358 XftUnlockFace (XftFont *public)
360 XftFontInt *font = (XftFontInt *) public;
361 _XftUnlockFile (font->info.file);
365 XftFontInfoFill (Display *dpy, _Xconst FcPattern *pattern, XftFontInfo *fi)
367 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
372 FcMatrix *font_matrix;
373 FcBool hinting, vertical_layout, autohint, global_advance;
375 FcChar32 hash, *hashp;
384 * Initialize the whole XftFontInfo so that padding doesn't interfere with
385 * hash or XftFontInfoEqual().
388 memset (fi, '\0', sizeof(*fi));
391 * Find the associated file
393 switch (FcPatternGetString (pattern, FC_FILE, 0, &filename)) {
394 case FcResultNoMatch:
403 switch (FcPatternGetInteger (pattern, FC_INDEX, 0, &id)) {
404 case FcResultNoMatch:
414 fi->file = _XftGetFile (filename, id);
415 else if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &face) == FcResultMatch
417 fi->file = _XftGetFaceFile (face);
424 if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch)
427 if (FcPatternGetDouble (pattern, FC_ASPECT, 0, &aspect) != FcResultMatch)
430 fi->ysize = (FT_F26Dot6) (dsize * 64.0);
431 fi->xsize = (FT_F26Dot6) (dsize * aspect * 64.0);
433 if (XftDebug() & XFT_DBG_OPEN)
434 printf ("XftFontInfoFill: %s: %d (%g pixels)\n",
435 (filename ? filename : (FcChar8 *) "<none>"), id, dsize);
437 * Get antialias value
439 switch (FcPatternGetBool (pattern, FC_ANTIALIAS, 0, &fi->antialias)) {
440 case FcResultNoMatch:
441 fi->antialias = True;
452 switch (FcPatternGetInteger (pattern, FC_RGBA, 0, &fi->rgba)) {
453 case FcResultNoMatch:
454 fi->rgba = FC_RGBA_UNKNOWN;
463 * Get lcd_filter value
465 switch (FcPatternGetInteger (pattern, FC_LCD_FILTER, 0, &fi->lcd_filter)) {
466 case FcResultNoMatch:
467 fi->lcd_filter = FC_LCD_DEFAULT;
476 * Get matrix and transform values
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;
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;
493 fi->transform = (fi->matrix.xx != 0x10000 || fi->matrix.xy != 0 ||
494 fi->matrix.yx != 0 || fi->matrix.yy != 0x10000);
497 * Get render value, set to false if no Render extension present
501 switch (FcPatternGetBool (pattern, XFT_RENDER, 0, &fi->render)) {
502 case FcResultNoMatch:
503 fi->render = info->hasRender;
512 fi->render = FcFalse;
515 * Compute glyph load flags
517 fi->load_flags = FT_LOAD_DEFAULT;
519 #ifndef XFT_EMBEDDED_BITMAP
520 #define XFT_EMBEDDED_BITMAP "embeddedbitmap"
523 switch (FcPatternGetBool (pattern, XFT_EMBEDDED_BITMAP, 0, &bitmap)) {
524 case FcResultNoMatch:
533 /* disable bitmaps when anti-aliasing or transforming glyphs */
534 if ((!bitmap && fi->antialias) || fi->transform)
535 fi->load_flags |= FT_LOAD_NO_BITMAP;
537 /* disable hinting if requested */
538 switch (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting)) {
539 case FcResultNoMatch:
548 switch (FcPatternGetBool (pattern, FC_EMBOLDEN, 0, &fi->embolden)) {
549 case FcResultNoMatch:
550 fi->embolden = FcFalse;
558 switch (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hint_style)) {
559 case FcResultNoMatch:
560 hint_style = FC_HINT_FULL;
569 || hint_style == FC_HINT_NONE
572 fi->load_flags |= FT_LOAD_NO_HINTING;
575 /* Figure out the load target, which modifies the hinting
576 * behavior of FreeType based on the intended use of the glyphs.
580 if (FC_HINT_NONE < hint_style && hint_style < FC_HINT_FULL)
582 fi->load_flags |= FT_LOAD_TARGET_LIGHT;
586 /* autohinter will snap stems to integer widths, when
587 * the LCD targets are used.
592 fi->load_flags |= FT_LOAD_TARGET_LCD;
596 fi->load_flags |= FT_LOAD_TARGET_LCD_V;
602 fi->load_flags |= FT_LOAD_TARGET_MONO;
604 /* set vertical layout if requested */
605 switch (FcPatternGetBool (pattern, FC_VERTICAL_LAYOUT, 0, &vertical_layout)) {
606 case FcResultNoMatch:
607 vertical_layout = FcFalse;
616 fi->load_flags |= FT_LOAD_VERTICAL_LAYOUT;
618 /* force autohinting if requested */
619 switch (FcPatternGetBool (pattern, FC_AUTOHINT, 0, &autohint)) {
620 case FcResultNoMatch:
630 fi->load_flags |= FT_LOAD_FORCE_AUTOHINT;
632 /* disable global advance width (for broken DynaLab TT CJK fonts) */
633 switch (FcPatternGetBool (pattern, FC_GLOBAL_ADVANCE, 0, &global_advance)) {
634 case FcResultNoMatch:
635 global_advance = FcTrue;
644 fi->load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
647 * Get requested spacing value
649 switch (FcPatternGetInteger (pattern, FC_SPACING, 0, &fi->spacing)) {
650 case FcResultNoMatch:
651 fi->spacing = FC_PROPORTIONAL;
663 switch (FcPatternGetBool (pattern, FC_MINSPACE, 0, &fi->minspace)) {
664 case FcResultNoMatch:
665 fi->minspace = FcFalse;
673 * Check for fixed pixel spacing
675 switch (FcPatternGetInteger (pattern, FC_CHAR_WIDTH, 0, &fi->char_width)) {
676 case FcResultNoMatch:
681 fi->spacing = FC_MONO;
688 * Step over hash value in the structure
691 hashp = (FcChar32 *) fi + 1;
692 nhash = (sizeof (XftFontInfo) / sizeof (FcChar32)) - 1;
704 _XftReleaseFile (fi->file);
711 XftFontInfoEmpty (Display *dpy, XftFontInfo *fi)
714 _XftReleaseFile (fi->file);
718 XftFontInfoCreate (Display *dpy, _Xconst FcPattern *pattern)
720 XftFontInfo *fi = malloc (sizeof (XftFontInfo));
725 if (!XftFontInfoFill (dpy, pattern, fi))
730 XftMemAlloc (XFT_MEM_FONT, sizeof (XftFontInfo));
735 XftFontInfoDestroy (Display *dpy, XftFontInfo *fi)
737 XftFontInfoEmpty (dpy, fi);
738 XftMemFree (XFT_MEM_FONT, sizeof (XftFontInfo));
743 XftFontInfoHash (_Xconst XftFontInfo *fi)
749 XftFontInfoEqual (_Xconst XftFontInfo *a, _Xconst XftFontInfo *b)
751 return memcmp ((void *) a, (void *) b, sizeof (XftFontInfo)) == 0;
755 XftFontOpenInfo (Display *dpy,
759 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True);
763 XRenderPictFormat *format;
765 FcChar32 num_unicode;
767 FcChar32 rehash_value;
769 int max_glyph_memory;
771 int ascent, descent, height;
778 * Find a matching previously opened font
780 bucket = &info->fontHash[fi->hash % XFT_NUM_FONT_HASH];
781 for (font = (XftFontInt *) *bucket; font; font = (XftFontInt *) font->hash_next)
782 if (XftFontInfoEqual (&font->info, fi))
785 --info->num_unref_fonts;
786 FcPatternDestroy (pattern);
787 return &font->public;
791 * No existing font, create another.
794 if (XftDebug () & XFT_DBG_CACHE)
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);
799 if (FcPatternGetInteger (pattern, XFT_MAX_GLYPH_MEMORY, 0,
800 &max_glyph_memory) != FcResultMatch)
801 max_glyph_memory = XFT_FONT_MAX_GLYPH_MEMORY;
803 face = _XftLockFile (fi->file);
807 if (!_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix))
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.
816 if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) == FcResultMatch)
817 charset = FcCharSetCopy (charset);
819 charset = FcFreeTypeCharSet (face, FcConfigGetBlanks (NULL));
821 antialias = fi->antialias;
822 if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
826 * Find the appropriate picture format
837 format = XRenderFindStandardFormat (dpy, PictStandardARGB32);
840 format = XRenderFindStandardFormat (dpy, PictStandardA8);
846 format = XRenderFindStandardFormat (dpy, PictStandardA1);
857 num_unicode = FcCharSetCount (charset);
858 hash_value = _XftHashSize (num_unicode);
859 rehash_value = hash_value - 2;
869 * Sometimes the glyphs are numbered 1..n, other times 0..n-1,
870 * accept either numbering scheme by making room in the table
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);
881 XftMemAlloc (XFT_MEM_FONT, alloc_size);
891 vector.y = face->size->metrics.descender;
892 FT_Vector_Transform (&vector, &fi->matrix);
893 descent = -(vector.y >> 6);
896 vector.y = face->size->metrics.ascender;
897 FT_Vector_Transform (&vector, &fi->matrix);
898 ascent = vector.y >> 6;
901 height = ascent + descent;
905 vector.y = face->size->metrics.height;
906 FT_Vector_Transform (&vector, &fi->matrix);
907 height = vector.y >> 6;
912 descent = -(face->size->metrics.descender >> 6);
913 ascent = face->size->metrics.ascender >> 6;
915 height = ascent + descent;
917 height = face->size->metrics.height >> 6;
919 font->public.ascent = ascent;
920 font->public.descent = descent;
921 font->public.height = height;
924 font->public.max_advance_width = fi->char_width;
930 vector.x = face->size->metrics.max_advance;
932 FT_Vector_Transform (&vector, &fi->matrix);
933 font->public.max_advance_width = vector.x >> 6;
936 font->public.max_advance_width = face->size->metrics.max_advance >> 6;
938 font->public.charset = charset;
939 font->public.pattern = pattern;
946 font->next = info->fonts;
947 info->fonts = &font->public;
949 font->hash_next = *bucket;
950 *bucket = &font->public;
957 * reset the antialias field. It can't
958 * be set correctly until the font is opened,
959 * which doesn't happen in XftFontInfoFill
961 font->info.antialias = antialias;
963 * bump XftFile reference count
965 font->info.file->ref++;
968 * Per glyph information
970 font->glyphs = (XftGlyph **) (font + 1);
971 memset (font->glyphs, '\0', num_glyphs * sizeof (XftGlyph *));
972 font->num_glyphs = num_glyphs;
974 * Unicode hash table information
976 font->hash_table = (XftUcsHash *) (font->glyphs + font->num_glyphs);
977 for (i = 0; i < hash_value; i++)
979 font->hash_table[i].ucs4 = ((FcChar32) ~0);
980 font->hash_table[i].glyph = 0;
982 font->hash_value = hash_value;
983 font->rehash_value = rehash_value;
988 font->format = format;
991 * Glyph memory management fields
993 font->glyph_memory = 0;
994 font->max_glyph_memory = max_glyph_memory;
995 font->use_free_glyphs = info->use_free_glyphs;
997 _XftUnlockFile (fi->file);
999 return &font->public;
1002 FcCharSetDestroy (charset);
1004 _XftUnlockFile (fi->file);
1010 XftFontOpenPattern (Display *dpy, FcPattern *pattern)
1015 if (!XftFontInfoFill (dpy, pattern, &info))
1018 font = XftFontOpenInfo (dpy, pattern, &info);
1019 XftFontInfoEmpty (dpy, &info);
1024 XftFontCopy (Display *dpy, XftFont *public)
1026 XftFontInt *font = (XftFontInt *) public;
1033 XftFontDestroy (Display *dpy, XftFont *public)
1035 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False);
1036 XftFontInt *font = (XftFontInt *) public;
1039 /* note reduction in memory use */
1041 info->glyph_memory -= font->glyph_memory;
1042 /* Clean up the info */
1043 XftFontInfoEmpty (dpy, &font->info);
1044 /* Free the glyphset */
1046 XRenderFreeGlyphSet (dpy, font->glyphset);
1047 /* Free the glyphs */
1048 for (i = 0; i < font->num_glyphs; i++)
1050 XftGlyph *xftg = font->glyphs[i];
1054 free (xftg->bitmap);
1059 /* Free the pattern and the charset */
1060 FcPatternDestroy (font->public.pattern);
1061 FcCharSetDestroy (font->public.charset);
1063 /* Finally, free the font structure */
1064 XftMemFree (XFT_MEM_FONT, sizeof (XftFontInt) +
1065 font->num_glyphs * sizeof (XftGlyph *) +
1066 font->hash_value * sizeof (XftUcsHash));
1071 XftFontFindNthUnref (XftDisplayInfo *info, int n)
1076 for (public = info->fonts; public; public = font->next)
1078 font = (XftFontInt*) public;
1079 if (!font->ref && !n--)
1086 XftFontManageMemory (Display *dpy)
1088 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False);
1095 while (info->num_unref_fonts > info->max_unref_fonts)
1097 public = XftFontFindNthUnref (info, rand() % info->num_unref_fonts);
1098 font = (XftFontInt *) public;
1100 if (XftDebug () & XFT_DBG_CACHE)
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);
1105 /* Unhook from display list */
1106 for (prev = &info->fonts; *prev; prev = &(*(XftFontInt **) prev)->next)
1108 if (*prev == public)
1114 /* Unhook from hash list */
1115 for (prev = &info->fontHash[font->info.hash % XFT_NUM_FONT_HASH];
1117 prev = &(*(XftFontInt **) prev)->hash_next)
1119 if (*prev == public)
1121 *prev = font->hash_next;
1125 /* Destroy the font */
1126 XftFontDestroy (dpy, public);
1127 --info->num_unref_fonts;
1132 XftFontClose (Display *dpy, XftFont *public)
1134 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False);
1135 XftFontInt *font = (XftFontInt *) public;
1137 if (--font->ref != 0)
1142 ++info->num_unref_fonts;
1143 XftFontManageMemory (dpy);
1147 XftFontDestroy (dpy, public);
1152 XftInitFtLibrary (void)
1156 if (FT_Init_FreeType (&_XftFTlibrary))