diff options
Diffstat (limited to 'src/xftfreetype.c')
-rw-r--r-- | src/xftfreetype.c | 1048 |
1 files changed, 1048 insertions, 0 deletions
diff --git a/src/xftfreetype.c b/src/xftfreetype.c new file mode 100644 index 0000000..1d3a473 --- /dev/null +++ b/src/xftfreetype.c @@ -0,0 +1,1048 @@ +/* + * $XFree86: xc/lib/Xft/xftfreetype.c,v 1.29 2002/10/11 17:53:02 keithp Exp $ + * + * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "xftint.h" +#include <X11/Xlibint.h> + +FT_Library _XftFTlibrary; + +#define FT_Matrix_Equal(a,b) ((a)->xx == (b)->xx && \ + (a)->yy == (b)->yy && \ + (a)->xy == (b)->xy && \ + (a)->yx == (b)->yx) +/* + * List of all open files (each face in a file is managed separately) + */ + +static XftFtFile *_XftFtFiles; +int XftMaxFreeTypeFiles = 5; + +static XftFtFile * +_XftGetFile (const FcChar8 *file, int id) +{ + XftFtFile *f; + + if (!XftInitFtLibrary ()) + return 0; + + for (f = _XftFtFiles; f; f = f->next) + { + if (!strcmp (f->file, (void *) file) && f->id == id) + { + ++f->ref; + if (XftDebug () & XFT_DBG_REF) + printf ("FontFile %s/%d matches existing (%d)\n", + file, id, f->ref); + return f; + } + } + f = malloc (sizeof (XftFtFile) + strlen ((char *) file) + 1); + if (!f) + return 0; + + XftMemAlloc (XFT_MEM_FILE, sizeof (XftFtFile) + strlen ((char *) file) + 1); + if (XftDebug () & XFT_DBG_REF) + printf ("FontFile %s/%d matches new\n", + file, id); + f->next = _XftFtFiles; + _XftFtFiles = f; + + f->ref = 1; + + f->file = (char *) (f+1); + strcpy (f->file, (void *) file); + f->id = id; + + f->lock = 0; + f->face = 0; + f->xsize = 0; + f->ysize = 0; + return f; +} + +static XftFtFile * +_XftGetFaceFile (FT_Face face) +{ + XftFtFile *f; + + f = malloc (sizeof (XftFtFile)); + if (!f) + return 0; + XftMemAlloc (XFT_MEM_FILE, sizeof(XftFtFile)); + f->next = 0; + + f->ref = 1; + + f->file = 0; + f->id = 0; + f->lock = 0; + f->face = face; + f->xsize = 0; + f->ysize = 0; + return f; +} + +static int +_XftNumFiles (void) +{ + XftFtFile *f; + int count = 0; + for (f = _XftFtFiles; f; f = f->next) + if (f->face && !f->lock) + ++count; + return count; +} + +static XftFtFile * +_XftNthFile (int n) +{ + XftFtFile *f; + int count = 0; + for (f = _XftFtFiles; f; f = f->next) + if (f->face && !f->lock) + if (count++ == n) + break; + return f; +} + +static void +_XftUncacheFiles (void) +{ + int n; + XftFtFile *f; + while ((n = _XftNumFiles ()) > XftMaxFreeTypeFiles) + { + f = _XftNthFile (rand () % n); + if (f) + { + if (XftDebug() & XFT_DBG_REF) + printf ("Discard file %s/%d from cache\n", + f->file, f->id); + FT_Done_Face (f->face); + f->face = 0; + } + } +} + +static FT_Face +_XftLockFile (XftFtFile *f) +{ + ++f->lock; + if (!f->face) + { + if (XftDebug() & XFT_DBG_REF) + printf ("Loading file %s/%d\n", f->file, f->id); + if (FT_New_Face (_XftFTlibrary, f->file, f->id, &f->face)) + --f->lock; + + f->xsize = 0; + f->ysize = 0; + f->matrix.xx = f->matrix.xy = f->matrix.yx = f->matrix.yy = 0; + _XftUncacheFiles (); + } + return f->face; +} + +static void +_XftLockError (char *reason) +{ + fprintf (stderr, "Xft: locking error %s\n", reason); +} + +static void +_XftUnlockFile (XftFtFile *f) +{ + if (--f->lock < 0) + _XftLockError ("too many file unlocks"); +} + +FcBool +_XftSetFace (XftFtFile *f, FT_F26Dot6 xsize, FT_F26Dot6 ysize, FT_Matrix *matrix) +{ + FT_Face face = f->face; + + if (f->xsize != xsize || f->ysize != ysize) + { + if (XftDebug() & XFT_DBG_GLYPH) + printf ("Set face size to %dx%d (%dx%d)\n", + (int) (xsize >> 6), (int) (ysize >> 6), (int) xsize, (int) ysize); + if (FT_Set_Char_Size (face, xsize, ysize, 0, 0)) + return False; + f->xsize = xsize; + f->ysize = ysize; + } + if (!FT_Matrix_Equal (&f->matrix, matrix)) + { + if (XftDebug() & XFT_DBG_GLYPH) + printf ("Set face matrix to (%g,%g,%g,%g)\n", + (double) matrix->xx / 0x10000, + (double) matrix->xy / 0x10000, + (double) matrix->yx / 0x10000, + (double) matrix->yy / 0x10000); + FT_Set_Transform (face, matrix, 0); + f->matrix = *matrix; + } + return True; +} + +static void +_XftReleaseFile (XftFtFile *f) +{ + XftFtFile **prev; + + if (--f->ref != 0) + return; + if (f->lock) + _XftLockError ("Attempt to close locked file"); + if (f->file) + { + for (prev = &_XftFtFiles; *prev; prev = &(*prev)->next) + { + if (*prev == f) + { + *prev = f->next; + break; + } + } + if (f->face) + FT_Done_Face (f->face); + } + XftMemFree (XFT_MEM_FILE, sizeof (XftFtFile) + strlen (f->file) + 1); + free (f); +} + +/* + * Find a prime larger than the minimum reasonable hash size + */ + +static FcChar32 +_XftSqrt (FcChar32 a) +{ + FcChar32 l, h, m; + + l = 2; + h = a/2; + while ((h-l) > 1) + { + m = (h+l) >> 1; + if (m * m < a) + l = m; + else + h = m; + } + return h; +} + +static FcBool +_XftIsPrime (FcChar32 i) +{ + FcChar32 l, t; + + if (i < 2) + return FcFalse; + if ((i & 1) == 0) + { + if (i == 2) + return FcTrue; + return FcFalse; + } + l = _XftSqrt (i) + 1; + for (t = 3; t <= l; t += 2) + if (i % t == 0) + return FcFalse; + return FcTrue; +} + +static FcChar32 +_XftHashSize (FcChar32 num_unicode) +{ + /* at least 31.25 % extra space */ + FcChar32 hash = num_unicode + (num_unicode >> 2) + (num_unicode >> 4); + + if ((hash & 1) == 0) + hash++; + while (!_XftIsPrime (hash)) + hash += 2; + return hash; +} + +FT_Face +XftLockFace (XftFont *public) +{ + XftFontInt *font = (XftFontInt *) public; + XftFontInfo *fi = &font->info; + FT_Face face; + + face = _XftLockFile (fi->file); + /* + * Make sure the face is usable at the requested size + */ + if (face && !_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix)) + { + _XftUnlockFile (fi->file); + face = 0; + } + return face; +} + +void +XftUnlockFace (XftFont *public) +{ + XftFontInt *font = (XftFontInt *) public; + _XftUnlockFile (font->info.file); +} + +static FcBool +XftFontInfoFill (Display *dpy, _Xconst FcPattern *pattern, XftFontInfo *fi) +{ + XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); + FcChar8 *filename; + int id; + double dsize; + double aspect; + FcMatrix *font_matrix; + FcBool hinting, vertical_layout, autohint, global_advance; + FcChar32 hash, *hashp; + FT_Face face; + int nhash; + + if (!info) + return FcFalse; + + /* + * Find the associated file + */ + switch (FcPatternGetString (pattern, FC_FILE, 0, &filename)) { + case FcResultNoMatch: + filename = 0; + break; + case FcResultMatch: + break; + default: + goto bail0; + } + + switch (FcPatternGetInteger (pattern, FC_INDEX, 0, &id)) { + case FcResultNoMatch: + id = 0; + break; + case FcResultMatch: + break; + default: + goto bail0; + } + + if (filename) + fi->file = _XftGetFile (filename, id); + else if (FcPatternGetFTFace (pattern, FC_FT_FACE, 0, &face) == FcResultMatch + && face) + fi->file = _XftGetFaceFile (face); + else + fi->file = 0; + if (!fi->file) + goto bail0; + + /* + * Compute pixel size + */ + if (FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &dsize) != FcResultMatch) + goto bail1; + + if (FcPatternGetDouble (pattern, FC_ASPECT, 0, &aspect) != FcResultMatch) + aspect = 1.0; + + fi->ysize = (FT_F26Dot6) (dsize * 64.0); + fi->xsize = (FT_F26Dot6) (dsize * aspect * 64.0); + + if (XftDebug() & XFT_DBG_OPEN) + printf ("XftFontInfoFill: %s: %d (%g pixels)\n", + (filename ? filename : (FcChar8 *) "<none>"), id, dsize); + /* + * Get antialias value + */ + switch (FcPatternGetBool (pattern, FC_ANTIALIAS, 0, &fi->antialias)) { + case FcResultNoMatch: + fi->antialias = True; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + + /* + * Get rgba value + */ + switch (FcPatternGetInteger (pattern, FC_RGBA, 0, &fi->rgba)) { + case FcResultNoMatch: + fi->rgba = FC_RGBA_UNKNOWN; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + + /* + * Get matrix and transform values + */ + switch (FcPatternGetMatrix (pattern, FC_MATRIX, 0, &font_matrix)) { + case FcResultNoMatch: + fi->matrix.xx = fi->matrix.yy = 0x10000; + fi->matrix.xy = fi->matrix.yx = 0; + break; + case FcResultMatch: + fi->matrix.xx = 0x10000L * font_matrix->xx; + fi->matrix.yy = 0x10000L * font_matrix->yy; + fi->matrix.xy = 0x10000L * font_matrix->xy; + fi->matrix.yx = 0x10000L * font_matrix->yx; + break; + default: + goto bail1; + } + + fi->transform = (fi->matrix.xx != 0x10000 || fi->matrix.xy != 0 || + fi->matrix.yx != 0 || fi->matrix.yy != 0x10000); + + /* + * Get render value, set to false if no Render extension present + */ + if (info->hasRender) + { + switch (FcPatternGetBool (pattern, XFT_RENDER, 0, &fi->render)) { + case FcResultNoMatch: + fi->render = info->hasRender; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + } + else + fi->render = FcFalse; + + /* + * Compute glyph load flags + */ + fi->load_flags = FT_LOAD_DEFAULT; + + /* disable bitmaps when anti-aliasing or transforming glyphs */ + if (fi->antialias || fi->transform) + fi->load_flags |= FT_LOAD_NO_BITMAP; + + /* disable hinting if requested */ + switch (FcPatternGetBool (pattern, FC_HINTING, 0, &hinting)) { + case FcResultNoMatch: + hinting = FcTrue; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + + if (!hinting) + fi->load_flags |= FT_LOAD_NO_HINTING; + + /* set vertical layout if requested */ + switch (FcPatternGetBool (pattern, FC_VERTICAL_LAYOUT, 0, &vertical_layout)) { + case FcResultNoMatch: + vertical_layout = FcFalse; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + + if (vertical_layout) + fi->load_flags |= FT_LOAD_VERTICAL_LAYOUT; + + /* force autohinting if requested */ + switch (FcPatternGetBool (pattern, FC_AUTOHINT, 0, &autohint)) { + case FcResultNoMatch: + autohint = FcFalse; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + + if (autohint) + fi->load_flags |= FT_LOAD_FORCE_AUTOHINT; + + /* disable global advance width (for broken DynaLab TT CJK fonts) */ + switch (FcPatternGetBool (pattern, FC_GLOBAL_ADVANCE, 0, &global_advance)) { + case FcResultNoMatch: + global_advance = FcTrue; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + + if (!global_advance) + fi->load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + + /* + * Get requested spacing value + */ + switch (FcPatternGetInteger (pattern, FC_SPACING, 0, &fi->spacing)) { + case FcResultNoMatch: + fi->spacing = FC_PROPORTIONAL; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + + /* + * Check for minspace + */ + + switch (FcPatternGetBool (pattern, FC_MINSPACE, 0, &fi->minspace)) { + case FcResultNoMatch: + fi->minspace = FcFalse; + break; + case FcResultMatch: + break; + default: + goto bail1; + } + /* + * Check for fixed pixel spacing + */ + switch (FcPatternGetInteger (pattern, FC_CHAR_WIDTH, 0, &fi->char_width)) { + case FcResultNoMatch: + fi->char_width = 0; + break; + case FcResultMatch: + if (fi->char_width) + fi->spacing = FC_MONO; + break; + default: + goto bail1; + } + + /* + * Step over hash value in the structure + */ + hash = 0; + hashp = (FcChar32 *) fi + 1; + nhash = (sizeof (XftFontInfo) / sizeof (FcChar32)) - 1; + + while (nhash--) + hash += *hashp++; + fi->hash = hash; + + /* + * All done + */ + return FcTrue; + +bail1: + _XftReleaseFile (fi->file); + fi->file = 0; +bail0: + return FcFalse; +} + +static void +XftFontInfoEmpty (Display *dpy, XftFontInfo *fi) +{ + if (fi->file) + _XftReleaseFile (fi->file); +} + +XftFontInfo * +XftFontInfoCreate (Display *dpy, _Xconst FcPattern *pattern) +{ + XftFontInfo *fi = malloc (sizeof (XftFontInfo)); + + if (!fi) + return 0; + + if (!XftFontInfoFill (dpy, pattern, fi)) + { + free (fi); + fi = 0; + } + XftMemAlloc (XFT_MEM_FONT, sizeof (XftFontInfo)); + return fi; +} + +void +XftFontInfoDestroy (Display *dpy, XftFontInfo *fi) +{ + XftFontInfoEmpty (dpy, fi); + XftMemFree (XFT_MEM_FONT, sizeof (XftFontInfo)); + free (fi); +} + +FcChar32 +XftFontInfoHash (_Xconst XftFontInfo *fi) +{ + return fi->hash; +} + +FcBool +XftFontInfoEqual (_Xconst XftFontInfo *a, _Xconst XftFontInfo *b) +{ + return memcmp ((void *) a, (void *) b, sizeof (XftFontInfo)) == 0; +} + +XftFont * +XftFontOpenInfo (Display *dpy, + FcPattern *pattern, + XftFontInfo *fi) +{ + XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); + FT_Face face; + XftFont **bucket; + XftFontInt *font; + XRenderPictFormat pf, *format; + FcCharSet *charset; + FcChar32 num_unicode; + FcChar32 hash_value; + FcChar32 rehash_value; + FcBool antialias; + int max_glyph_memory; + int alloc_size; + int ascent, descent, height; + int i; + + if (!info) + return 0; + /* + * Find a matching previously opened font + */ + bucket = &info->fontHash[fi->hash % XFT_NUM_FONT_HASH]; + for (font = (XftFontInt *) *bucket; font; font = (XftFontInt *) font->hash_next) + if (XftFontInfoEqual (&font->info, fi)) + { + if (!font->ref++) + --info->num_unref_fonts; + FcPatternDestroy (pattern); + return &font->public; + } + + /* + * No existing font, create another. + */ + + if (XftDebug () & XFT_DBG_CACHE) + printf ("New font %s/%d size %dx%d\n", + fi->file->file, fi->file->id, + (int) fi->xsize >> 6, (int) fi->ysize >> 6); + + if (FcPatternGetInteger (pattern, XFT_MAX_GLYPH_MEMORY, 0, + &max_glyph_memory) != FcResultMatch) + max_glyph_memory = XFT_FONT_MAX_GLYPH_MEMORY; + + face = _XftLockFile (fi->file); + if (!face) + goto bail0; + + if (!_XftSetFace (fi->file, fi->xsize, fi->ysize, &fi->matrix)) + goto bail1; + + /* + * Get the set of Unicode codepoints covered by the font. + * If the incoming pattern doesn't provide this data, go + * off and compute it. Yes, this is expensive, but it's + * required to map Unicode to glyph indices. + */ + if (FcPatternGetCharSet (pattern, FC_CHARSET, 0, &charset) != FcResultMatch) + charset = FcFreeTypeCharSet (face, FcConfigGetBlanks (0)); + + antialias = fi->antialias; + if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) + antialias = FcFalse; + + /* + * Find the appropriate picture format + */ + if (fi->render) + { + if (antialias) + { + switch (fi->rgba) { + case FC_RGBA_RGB: + case FC_RGBA_BGR: + case FC_RGBA_VRGB: + case FC_RGBA_VBGR: + pf.depth = 32; + pf.type = PictTypeDirect; + pf.direct.alpha = 24; + pf.direct.alphaMask = 0xff; + pf.direct.red = 16; + pf.direct.redMask = 0xff; + pf.direct.green = 8; + pf.direct.greenMask = 0xff; + pf.direct.blue = 0; + pf.direct.blueMask = 0xff; + format = XRenderFindFormat(dpy, + PictFormatType| + PictFormatDepth| + PictFormatAlpha| + PictFormatAlphaMask| + PictFormatRed| + PictFormatRedMask| + PictFormatGreen| + PictFormatGreenMask| + PictFormatBlue| + PictFormatBlueMask, + &pf, 0); + break; + default: + pf.depth = 8; + pf.type = PictTypeDirect; + pf.direct.alpha = 0; + pf.direct.alphaMask = 0xff; + format = XRenderFindFormat(dpy, + PictFormatType| + PictFormatDepth| + PictFormatAlpha| + PictFormatAlphaMask, + &pf, 0); + break; + } + } + else + { + pf.depth = 1; + pf.type = PictTypeDirect; + pf.direct.alpha = 0; + pf.direct.alphaMask = 0x1; + format = XRenderFindFormat(dpy, + PictFormatType| + PictFormatDepth| + PictFormatAlpha| + PictFormatAlphaMask, + &pf, 0); + } + + if (!format) + goto bail0; + } + else + format = 0; + + if (charset) + { + num_unicode = FcCharSetCount (charset); + hash_value = _XftHashSize (num_unicode); + rehash_value = hash_value - 2; + } + else + { + num_unicode = 0; + hash_value = 0; + rehash_value = 0; + } + + alloc_size = (sizeof (XftFontInt) + + face->num_glyphs * sizeof (XftGlyph *) + + hash_value * sizeof (XftUcsHash)); + font = malloc (alloc_size); + + if (!font) + goto bail1; + + XftMemAlloc (XFT_MEM_FONT, alloc_size); + + /* + * Public fields + */ + if (fi->transform) + { + FT_Vector vector; + + vector.x = 0; + vector.y = face->size->metrics.descender; + FT_Vector_Transform (&vector, &fi->matrix); + descent = -(vector.y >> 6); + + vector.x = 0; + vector.y = face->size->metrics.ascender; + FT_Vector_Transform (&vector, &fi->matrix); + ascent = vector.y >> 6; + + if (fi->minspace) + height = ascent + descent; + else + { + vector.x = 0; + vector.y = face->size->metrics.height; + FT_Vector_Transform (&vector, &fi->matrix); + height = vector.y >> 6; + } + } + else + { + descent = -(face->size->metrics.descender >> 6); + ascent = face->size->metrics.ascender >> 6; + if (fi->minspace) + height = ascent + descent; + else + height = face->size->metrics.height >> 6; + } + font->public.ascent = ascent; + font->public.descent = descent; + font->public.height = height; + + if (fi->char_width) + font->public.max_advance_width = fi->char_width; + else + { + if (fi->transform) + { + FT_Vector vector; + vector.x = face->size->metrics.max_advance; + vector.y = 0; + FT_Vector_Transform (&vector, &fi->matrix); + font->public.max_advance_width = vector.x >> 6; + } + else + font->public.max_advance_width = face->size->metrics.max_advance >> 6; + } + font->public.charset = charset; + font->public.pattern = pattern; + + /* + * Management fields + */ + font->ref = 1; + + font->next = info->fonts; + info->fonts = &font->public; + + font->hash_next = *bucket; + *bucket = &font->public; + + /* + * Copy the info over + */ + font->info = *fi; + /* + * reset the antialias field. It can't + * be set correctly until the font is opened, + * which doesn't happen in XftFontInfoFill + */ + font->info.antialias = antialias; + /* + * bump XftFile reference count + */ + font->info.file->ref++; + + /* + * Per glyph information + */ + font->glyphs = (XftGlyph **) (font + 1); + memset (font->glyphs, '\0', face->num_glyphs * sizeof (XftGlyph *)); + font->num_glyphs = face->num_glyphs; + /* + * Unicode hash table information + */ + font->hash_table = (XftUcsHash *) (font->glyphs + font->num_glyphs); + for (i = 0; i < hash_value; i++) + { + font->hash_table[i].ucs4 = ((FcChar32) ~0); + font->hash_table[i].glyph = 0; + } + font->hash_value = hash_value; + font->rehash_value = rehash_value; + /* + * X specific fields + */ + font->glyphset = 0; + font->format = format; + + /* + * Glyph memory management fields + */ + font->glyph_memory = 0; + font->max_glyph_memory = max_glyph_memory; + font->use_free_glyphs = info->use_free_glyphs; + + _XftUnlockFile (fi->file); + + return &font->public; + +bail1: + _XftUnlockFile (fi->file); +bail0: + return 0; +} + +XftFont * +XftFontOpenPattern (Display *dpy, FcPattern *pattern) +{ + XftFontInfo info; + XftFont *font; + + if (!XftFontInfoFill (dpy, pattern, &info)) + return 0; + + font = XftFontOpenInfo (dpy, pattern, &info); + XftFontInfoEmpty (dpy, &info); + return font; +} + +XftFont * +XftFontCopy (Display *dpy, XftFont *public) +{ + XftFontInt *font = (XftFontInt *) public; + + font->ref++; + return public; +} + +static void +XftFontDestroy (Display *dpy, XftFont *public) +{ + XftFontInt *font = (XftFontInt *) public; + int i; + + /* Clean up the info */ + XftFontInfoEmpty (dpy, &font->info); + /* Free the glyphset */ + if (font->glyphset) + XRenderFreeGlyphSet (dpy, font->glyphset); + /* Free the glyphs */ + for (i = 0; i < font->num_glyphs; i++) + { + XftGlyph *xftg = font->glyphs[i]; + if (xftg) + { + if (xftg->bitmap) + free (xftg->bitmap); + free (xftg); + } + } + + /* Finally, free the font structure */ + XftMemFree (XFT_MEM_FONT, sizeof (XftFontInt) + + font->num_glyphs * sizeof (XftGlyph *) + + font->hash_value * sizeof (XftUcsHash)); + free (font); +} + +static XftFont * +XftFontFindNthUnref (XftDisplayInfo *info, int n) +{ + XftFont *public; + XftFontInt *font; + + for (public = info->fonts; public; public = font->next) + { + font = (XftFontInt*) public; + if (!font->ref && !n--) + break; + } + return public; +} + +void +XftFontManageMemory (Display *dpy) +{ + XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); + XftFont **prev; + XftFont *public; + XftFontInt *font; + + if (!info) + return; + while (info->num_unref_fonts > info->max_unref_fonts) + { + public = XftFontFindNthUnref (info, rand() % info->num_unref_fonts); + font = (XftFontInt *) public; + + if (XftDebug () & XFT_DBG_CACHE) + printf ("freeing unreferenced font %s/%d size %dx%d\n", + font->info.file->file, font->info.file->id, + (int) font->info.xsize >> 6, (int) font->info.ysize >> 6); + + /* Unhook from display list */ + for (prev = &info->fonts; *prev; prev = &(*(XftFontInt **) prev)->next) + { + if (*prev == public) + { + *prev = font->next; + break; + } + } + /* Unhook from hash list */ + for (prev = &info->fontHash[font->info.hash % XFT_NUM_FONT_HASH]; + *prev; + prev = &(*(XftFontInt **) prev)->hash_next) + { + if (*prev == public) + { + *prev = font->hash_next; + break; + } + } + /* Destroy the font */ + XftFontDestroy (dpy, public); + --info->num_unref_fonts; + } +} + +void +XftFontClose (Display *dpy, XftFont *public) +{ + XftDisplayInfo *info = _XftDisplayInfoGet (dpy, False); + XftFontInt *font = (XftFontInt *) public; + + if (--font->ref != 0) + return; + + if (info) + { + ++info->num_unref_fonts; + XftFontManageMemory (dpy); + } + else + { + XftFontDestroy (dpy, public); + } +} + +FcBool +XftInitFtLibrary (void) +{ + if (_XftFTlibrary) + return FcTrue; + if (FT_Init_FreeType (&_XftFTlibrary)) + return FcFalse; + return FcTrue; +} |