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