summaryrefslogtreecommitdiff
path: root/src/xftfreetype.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xftfreetype.c')
-rw-r--r--src/xftfreetype.c1048
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;
+}