diff options
Diffstat (limited to 'src/cairo_ft_font.c')
-rw-r--r-- | src/cairo_ft_font.c | 1257 |
1 files changed, 787 insertions, 470 deletions
diff --git a/src/cairo_ft_font.c b/src/cairo_ft_font.c index b928b04fc..44e1b0e84 100644 --- a/src/cairo_ft_font.c +++ b/src/cairo_ft_font.c @@ -1,29 +1,40 @@ -/* - * Copyright © 2003 Red Hat Inc. +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2005 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it either under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation + * (the "LGPL") or, at your option, under the terms of the Mozilla + * Public License Version 1.1 (the "MPL"). If you do not alter this + * notice, a recipient may use your version of this file under either + * the MPL or the LGPL. + * + * You should have received a copy of the LGPL along with this library + * in the file COPYING-LGPL-2.1; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the MPL along with this library + * in the file COPYING-MPL-1.1 * - * 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 Red Hat Inc. not be used - * in advertising or publicity pertaining to distribution of the software - * without specific, written prior permission. Red Hat Inc. makes no - * representations about the suitability of this software for any purpose. - * It is provided "as is" without express or implied warranty. + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ * - * RED HAT INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL RED HAT INC. 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. + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY + * OF ANY KIND, either express or implied. See the LGPL or the MPL for + * the specific language governing rights and limitations. * - * Author: Graydon Hoare <graydon@redhat.com> + * The Original Code is the cairo graphics library. + * + * The Initial Developer of the Original Code is Red Hat, Inc. + * + * Contributor(s): + * Graydon Hoare <graydon@redhat.com> + * Owen Taylor <otaylor@redhat.com> */ -#include "cairoint.h" -#include "cairo-ft.h" +#include "cairo-ft-private.h" #include <fontconfig/fontconfig.h> #include <fontconfig/fcfreetype.h> @@ -38,19 +49,9 @@ #define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0)) #define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0) -/* - * First we make a private, sharable implementation object which can be - * stored both in a private cache and in public font objects (including - * those connected to fonts we don't own) +/* This is the max number of FT_face objects we keep open at once */ - -typedef struct { - int refcount; - - FT_Face face; - int owns_face; - -} ft_font_val_t; +#define MAX_OPEN_FACES 10 /* * The simple 2x2 matrix is converted into separate scale and shape @@ -62,141 +63,126 @@ typedef struct { double shape[2][2]; } ft_font_transform_t; -static ft_font_val_t * -_create_from_face (FT_Face face, int owns_face) -{ - ft_font_val_t *tmp = malloc (sizeof(ft_font_val_t)); - if (tmp) { - tmp->refcount = 1; - tmp->face = face; - tmp->owns_face = owns_face; - FT_Set_Char_Size (face, - DOUBLE_TO_26_6 (1.0), - DOUBLE_TO_26_6 (1.0), - 0, 0); - } - return tmp; -} +/* + * We create an object that corresponds to a single font on the disk; + * (identified by a filename/id pair) these are shared between all + * fonts using that file. For cairo_ft_font_create_for_ft_face(), we + * just create a one-off version with a permanent face value. + */ -static void -_reference_font_val (ft_font_val_t *f) -{ - f->refcount++; -} +typedef struct { + cairo_unscaled_font_t base; -static void -_destroy_font_val (ft_font_val_t *f) -{ - if (--(f->refcount) > 0) - return; + int from_face; /* from cairo_ft_font_create_for_ft_face()? */ + FT_Face face; /* provided or cached face */ - if (f->owns_face) - FT_Done_Face (f->face); + /* only set if from_face is false */ + FT_Library library; + char *filename; + int id; - free (f); -} + /* We temporarily scale the unscaled font as neede */ + int have_scale; + cairo_font_scale_t current_scale; + double x_scale; /* Extracted X scale factor */ + double y_scale; /* Extracted Y scale factor */ + + int lock; /* count of how many times this font has been locked */ +} ft_unscaled_font_t; -static ft_font_val_t * -_create_from_library_and_pattern (FT_Library ft_library, FcPattern *pattern) -{ - ft_font_val_t *f = NULL; - char *filename = NULL; - int owns_face = 0; - FT_Face face = NULL; - FcPattern *resolved = NULL; - FcResult result = FcResultMatch; +const cairo_font_backend_t cairo_ft_font_backend; - if (pattern == NULL) - goto FAIL; +static ft_unscaled_font_t * +_ft_unscaled_font_create_from_face (FT_Face face) +{ + ft_unscaled_font_t *unscaled = malloc (sizeof(ft_unscaled_font_t)); + if (!unscaled) + return NULL; + + unscaled->from_face = 1; + unscaled->face = face; - FcConfigSubstitute (0, pattern, FcMatchPattern); - FcDefaultSubstitute (pattern); + unscaled->library = NULL; + unscaled->filename = NULL; + unscaled->id = 0; - resolved = FcFontMatch (0, pattern, &result); - if (!resolved) - goto FAIL; + unscaled->have_scale = 0; + unscaled->lock = 0; - if (result != FcResultMatch) - goto FREE_RESOLVED; + _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled, + &cairo_ft_font_backend); + return unscaled; +} + +static ft_unscaled_font_t * +_ft_unscaled_font_create_from_filename (FT_Library library, + const char *filename, + int id) +{ + ft_unscaled_font_t *unscaled; + char *new_filename; - /* If the pattern has an FT_Face object, use that. */ - if (FcPatternGetFTFace (resolved, FC_FT_FACE, 0, &face) != FcResultMatch - || face == NULL) - { - /* otherwise it had better have a filename */ - result = FcPatternGetString (resolved, FC_FILE, 0, (FcChar8 **)(&filename)); - - if (result == FcResultMatch) - if (FT_New_Face (ft_library, filename, 0, &face)) - goto FREE_RESOLVED; - - if (face == NULL) - goto FREE_RESOLVED; - - owns_face = 1; + new_filename = strdup (filename); + if (!new_filename) + return NULL; + + unscaled = malloc (sizeof (ft_unscaled_font_t)); + if (!unscaled) { + free (new_filename); + return NULL; } + + unscaled->from_face = 0; + unscaled->face = NULL; - f = _create_from_face (face, owns_face); - - FcPatternDestroy (resolved); - return f; + unscaled->library = library; + unscaled->filename = new_filename; + unscaled->id = id; - FREE_RESOLVED: - if (resolved) - FcPatternDestroy (resolved); - - FAIL: - return NULL; + unscaled->have_scale = 0; + unscaled->lock = 0; + + _cairo_unscaled_font_init ((cairo_unscaled_font_t *)unscaled, + &cairo_ft_font_backend); + return unscaled; } - -/* - * We then make the user-exposed structure out of one of these impls, such - * that it is reasonably cheap to copy and/or destroy. Unfortunately this - * duplicates a certain amount of the caching machinery in the font cache, - * but that's unavoidable as we also provide an FcPattern resolution API, - * which is not part of cairo's generic font finding system. - */ - -typedef struct { - cairo_unscaled_font_t base; - FcPattern *pattern; - ft_font_val_t *val; -} cairo_ft_font_t; - -/* - * We then make a key and entry type which are compatible with the generic - * cache system. This cache serves to share single ft_font_val_t instances - * between fonts (or between font lifecycles). +/* + * We keep a global cache from [file/id] => [ft_unscaled_font_t]. This + * hash isn't limited in size. However, we limit the number of + * FT_Face objects we keep around; when we've exceeeded that + * limit and need to create a new FT_Face, we dump the FT_Face from + * a random ft_unscaled_font_t. */ typedef struct { cairo_cache_entry_base_t base; - FcPattern *pattern; + char *filename; + int id; } cairo_ft_cache_key_t; typedef struct { cairo_ft_cache_key_t key; - ft_font_val_t *val; + ft_unscaled_font_t *unscaled; } cairo_ft_cache_entry_t; -/* - * Then we create a cache which maps FcPattern keys to the refcounted - * ft_font_val_t values. - */ - typedef struct { cairo_cache_t base; FT_Library lib; + int n_faces; /* Number of open FT_Face objects */ } ft_cache_t; - static unsigned long _ft_font_cache_hash (void *cache, void *key) { - cairo_ft_cache_key_t *in; - in = (cairo_ft_cache_key_t *) key; - return FcPatternHash (in->pattern); + cairo_ft_cache_key_t *in = (cairo_ft_cache_key_t *) key; + unsigned long hash; + + /* 1607 is just a random prime. */ + hash = _cairo_hash_string (in->filename); + hash += ((unsigned long) in->id) * 1607; + + return hash; } static int @@ -208,10 +194,10 @@ _ft_font_cache_keys_equal (void *cache, cairo_ft_cache_key_t *b; a = (cairo_ft_cache_key_t *) k1; b = (cairo_ft_cache_key_t *) k2; - - return FcPatternEqual (a->pattern, b->pattern); -} + return strcmp (a->filename, b->filename) == 0 && + a->id == b->id; +} static cairo_status_t _ft_font_cache_create_entry (void *cache, @@ -226,27 +212,33 @@ _ft_font_cache_create_entry (void *cache, if (entry == NULL) return CAIRO_STATUS_NO_MEMORY; - entry->key.pattern = FcPatternDuplicate (k->pattern); - if (!entry->key.pattern) { + entry->unscaled = _ft_unscaled_font_create_from_filename (ftcache->lib, + k->filename, + k->id); + if (!entry->unscaled) { free (entry); return CAIRO_STATUS_NO_MEMORY; } - - entry->val = _create_from_library_and_pattern (ftcache->lib, entry->key.pattern); - entry->key.base.memory = 1; - + + entry->key.base.memory = 0; + entry->key.filename = entry->unscaled->filename; + entry->key.id = entry->unscaled->id; + *return_entry = entry; return CAIRO_STATUS_SUCCESS; } +/* Entries are never spontaneously destroyed; but only when + * we remove them from the cache specifically. We free entry->unscaled + * in the code that removes the entry from the cache + */ static void _ft_font_cache_destroy_entry (void *cache, void *entry) { cairo_ft_cache_entry_t *e = (cairo_ft_cache_entry_t *) entry; - FcPatternDestroy (e->key.pattern); - _destroy_font_val (e->val); + free (e); } @@ -291,11 +283,12 @@ _get_global_ft_cache (void) if (_cairo_cache_init (&_global_ft_cache->base, &_ft_font_cache_backend, - CAIRO_FT_CACHE_NUM_FONTS_DEFAULT)) + 0)) /* No memory limit */ goto FAIL; if (FT_Init_FreeType (&_global_ft_cache->lib)) goto FAIL; + _global_ft_cache->n_faces = 0; } return &_global_ft_cache->base; @@ -306,30 +299,304 @@ _get_global_ft_cache (void) return NULL; } -/* implement the backend interface */ +/* Finds or creates a ft_unscaled_font for the filename/id from pattern. + * Returns a new reference to the unscaled font. + */ +static ft_unscaled_font_t * +_ft_unscaled_font_get_for_pattern (FcPattern *pattern) +{ + cairo_ft_cache_entry_t *entry; + cairo_ft_cache_key_t key; + cairo_cache_t *cache; + cairo_status_t status; + FcChar8 *filename; + int created_entry; + + if (FcPatternGetString (pattern, FC_FILE, 0, &filename) != FcResultMatch) + return NULL; + key.filename = (char *)filename; + + if (FcPatternGetInteger (pattern, FC_INDEX, 0, &key.id) != FcResultMatch) + return NULL; + + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + if (cache == NULL) { + _unlock_global_ft_cache (); + return NULL; + } + + status = _cairo_cache_lookup (cache, &key, (void **) &entry, &created_entry); + _unlock_global_ft_cache (); + if (status) + return NULL; + + if (!created_entry) + _cairo_unscaled_font_reference ((cairo_unscaled_font_t *)entry->unscaled); + + return entry->unscaled; +} + +static int +_has_unlocked_face (void *entry) +{ + cairo_ft_cache_entry_t *e = entry; -const cairo_font_backend_t cairo_ft_font_backend; + return (e->unscaled->lock == 0 && e->unscaled->face); +} + +/* Ensures that an unscaled font has a face object. If we exceed + * MAX_OPEN_FACES, try to close some. + */ +static FT_Face +_ft_unscaled_font_lock_face (ft_unscaled_font_t *unscaled) +{ + ft_cache_t *ftcache; + FT_Face face = NULL; + + if (unscaled->face) { + unscaled->lock++; + return unscaled->face; + } -static cairo_unscaled_font_t * -_cairo_ft_font_create (const char *family, + assert (!unscaled->from_face); + + _lock_global_ft_cache (); + ftcache = (ft_cache_t *) _get_global_ft_cache (); + assert (ftcache != NULL); + + while (ftcache->n_faces >= MAX_OPEN_FACES) { + cairo_ft_cache_entry_t *entry; + + entry = _cairo_cache_random_entry ((cairo_cache_t *)ftcache, _has_unlocked_face); + if (entry) { + FT_Done_Face (entry->unscaled->face); + entry->unscaled->face = NULL; + entry->unscaled->have_scale = 0; + ftcache->n_faces--; + } else { + break; + } + } + + if (FT_New_Face (ftcache->lib, + unscaled->filename, + unscaled->id, + &face) != FT_Err_Ok) + goto FAIL; + + unscaled->face = face; + unscaled->lock++; + ftcache->n_faces++; + + FAIL: + _unlock_global_ft_cache (); + return face; +} + +/* Unlock unscaled font locked with _ft_unscaled_font_lock_face + */ +static void +_ft_unscaled_font_unlock_face (ft_unscaled_font_t *unscaled) +{ + assert (unscaled->lock > 0); + + unscaled->lock--; +} + +static void +_compute_transform (ft_font_transform_t *sf, + cairo_font_scale_t *sc) +{ + cairo_matrix_t normalized; + double tx, ty; + + /* The font matrix has x and y "scale" components which we extract and + * use as character scale values. These influence the way freetype + * chooses hints, as well as selecting different bitmaps in + * hand-rendered fonts. We also copy the normalized matrix to + * freetype's transformation. + */ + + cairo_matrix_set_affine (&normalized, + sc->matrix[0][0], + sc->matrix[0][1], + sc->matrix[1][0], + sc->matrix[1][1], + 0, 0); + + _cairo_matrix_compute_scale_factors (&normalized, + &sf->x_scale, &sf->y_scale, + /* XXX */ 1); + cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); + cairo_matrix_get_affine (&normalized, + &sf->shape[0][0], &sf->shape[0][1], + &sf->shape[1][0], &sf->shape[1][1], + &tx, &ty); +} + +/* Temporarily scales an unscaled font to the give scale. We catch + * scaling to the same size, since changing a FT_Face is expensive. + */ +static void +_ft_unscaled_font_set_scale (ft_unscaled_font_t *unscaled, + cairo_font_scale_t *scale) +{ + ft_font_transform_t sf; + FT_Matrix mat; + + assert (unscaled->face != NULL); + + if (unscaled->have_scale && + scale->matrix[0][0] == unscaled->current_scale.matrix[0][0] && + scale->matrix[0][1] == unscaled->current_scale.matrix[0][1] && + scale->matrix[1][0] == unscaled->current_scale.matrix[1][0] && + scale->matrix[1][1] == unscaled->current_scale.matrix[1][1]) + return; + + unscaled->have_scale = 1; + unscaled->current_scale = *scale; + + _compute_transform (&sf, scale); + + unscaled->x_scale = sf.x_scale; + unscaled->y_scale = sf.y_scale; + + mat.xx = DOUBLE_TO_16_16(sf.shape[0][0]); + mat.yx = - DOUBLE_TO_16_16(sf.shape[0][1]); + mat.xy = - DOUBLE_TO_16_16(sf.shape[1][0]); + mat.yy = DOUBLE_TO_16_16(sf.shape[1][1]); + + FT_Set_Transform(unscaled->face, &mat, NULL); + + FT_Set_Pixel_Sizes(unscaled->face, + (FT_UInt) sf.x_scale, + (FT_UInt) sf.y_scale); +} + +/* implement the font backend interface */ + +typedef struct { + cairo_font_t base; + FcPattern *pattern; + int load_flags; + ft_unscaled_font_t *unscaled; +} cairo_ft_font_t; + +/* for compatibility with older freetype versions */ +#ifndef FT_LOAD_TARGET_MONO +#define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME +#endif + +/* The load flags passed to FT_Load_Glyph control aspects like hinting and + * antialiasing. Here we compute them from the fields of a FcPattern. + */ +static int +_get_load_flags (FcPattern *pattern) +{ + FcBool antialias, hinting, autohint; +#ifdef FC_HINT_STYLE + int hintstyle; +#endif + int load_flags = 0; + + /* disable antialiasing if requested */ + if (FcPatternGetBool (pattern, + FC_ANTIALIAS, 0, &antialias) != FcResultMatch) + antialias = FcTrue; + + if (antialias) + load_flags |= FT_LOAD_NO_BITMAP; + else + load_flags |= FT_LOAD_TARGET_MONO; + + /* disable hinting if requested */ + if (FcPatternGetBool (pattern, + FC_HINTING, 0, &hinting) != FcResultMatch) + hinting = FcTrue; + +#ifdef FC_HINT_STYLE + if (FcPatternGetInteger (pattern, FC_HINT_STYLE, 0, &hintstyle) != FcResultMatch) + hintstyle = FC_HINT_FULL; + + if (!hinting || hintstyle == FC_HINT_NONE) + load_flags |= FT_LOAD_NO_HINTING; + + switch (hintstyle) { + case FC_HINT_SLIGHT: + case FC_HINT_MEDIUM: + load_flags |= FT_LOAD_TARGET_LIGHT; + break; + default: + load_flags |= FT_LOAD_TARGET_NORMAL; + break; + } +#else /* !FC_HINT_STYLE */ + if (!hinting) + load_flags |= FT_LOAD_NO_HINTING; +#endif /* FC_FHINT_STYLE */ + + /* force autohinting if requested */ + if (FcPatternGetBool (pattern, + FC_AUTOHINT, 0, &autohint) != FcResultMatch) + autohint = FcFalse; + + if (autohint) + load_flags |= FT_LOAD_FORCE_AUTOHINT; + + return load_flags; +} + +/* Like the public cairo_ft_font_create, but takes a cairo_font_scale_t, + * rather than a cairo_font_t + */ +static cairo_font_t * +_ft_font_create (FcPattern *pattern, + cairo_font_scale_t *scale) +{ + cairo_ft_font_t *f = NULL; + ft_unscaled_font_t *unscaled = NULL; + + unscaled = _ft_unscaled_font_get_for_pattern (pattern); + if (unscaled == NULL) + return NULL; + + f = malloc (sizeof(cairo_ft_font_t)); + if (f == NULL) + goto FREE_UNSCALED; + + f->unscaled = unscaled; + f->pattern = pattern; + FcPatternReference (pattern); + f->load_flags = _get_load_flags (pattern); + + _cairo_font_init ((cairo_font_t *)f, scale, &cairo_ft_font_backend); + + return (cairo_font_t *)f; + + FREE_UNSCALED: + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled); + + return NULL; +} + +static cairo_status_t +_cairo_ft_font_create (const char *family, cairo_font_slant_t slant, - cairo_font_weight_t weight) + cairo_font_weight_t weight, + cairo_font_scale_t *scale, + cairo_font_t **font) { - cairo_status_t status; - cairo_ft_font_t *font = NULL; + FcPattern *pattern, *resolved; + cairo_font_t *new_font; + FcResult result; int fcslant; int fcweight; - cairo_cache_t *cache; - cairo_ft_cache_entry_t *entry; - cairo_ft_cache_key_t key; - - key.pattern = FcPatternCreate (); - if (key.pattern == NULL) - goto FAIL; + ft_font_transform_t sf; - font = malloc (sizeof (cairo_ft_font_t)); - if (font == NULL) - goto FREE_PATTERN; + pattern = FcPatternCreate (); + if (!pattern) + return CAIRO_STATUS_NO_MEMORY; switch (weight) { @@ -356,46 +623,44 @@ _cairo_ft_font_create (const char *family, break; } - FcPatternAddString (key.pattern, FC_FAMILY, family); - FcPatternAddInteger (key.pattern, FC_SLANT, fcslant); - FcPatternAddInteger (key.pattern, FC_WEIGHT, fcweight); - - if (_cairo_unscaled_font_init (&font->base, &cairo_ft_font_backend)) + if (!FcPatternAddString (pattern, FC_FAMILY, family)) goto FREE_PATTERN; - - _lock_global_ft_cache (); - cache = _get_global_ft_cache (); - if (cache == NULL) { - _unlock_global_ft_cache (); + if (!FcPatternAddInteger (pattern, FC_SLANT, fcslant)) + goto FREE_PATTERN; + if (!FcPatternAddInteger (pattern, FC_WEIGHT, fcweight)) goto FREE_PATTERN; - } - status = _cairo_cache_lookup (cache, &key, (void **) &entry); - _unlock_global_ft_cache (); + _compute_transform (&sf, scale); - if (status) - goto FREE_PATTERN; + FcPatternAddInteger (pattern, FC_PIXEL_SIZE, sf.y_scale); - font->pattern = FcPatternDuplicate (entry->key.pattern); - if (font->pattern == NULL) + FcConfigSubstitute (NULL, pattern, FcMatchPattern); + FcDefaultSubstitute (pattern); + + resolved = FcFontMatch (NULL, pattern, &result); + if (!resolved) goto FREE_PATTERN; - font->val = entry->val; - _reference_font_val (font->val); - - return &font->base; + new_font = _ft_font_create (resolved, scale); - FREE_PATTERN: - FcPatternDestroy (key.pattern); + FcPatternDestroy (resolved); + FcPatternDestroy (pattern); - FAIL: - return NULL; + if (new_font) { + *font = new_font; + return CAIRO_STATUS_SUCCESS; + } else { + return CAIRO_STATUS_NO_MEMORY; /* A guess */ + } -} + FREE_PATTERN: + FcPatternDestroy (pattern); + return CAIRO_STATUS_NO_MEMORY; +} static void -_cairo_ft_font_destroy (void *abstract_font) +_cairo_ft_font_destroy_font (void *abstract_font) { cairo_ft_font_t * font = abstract_font; @@ -405,179 +670,94 @@ _cairo_ft_font_destroy (void *abstract_font) if (font->pattern != NULL) FcPatternDestroy (font->pattern); - _destroy_font_val (font->val); + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)font->unscaled); free (font); } static void -_utf8_to_ucs4 (char const *utf8, - FT_ULong **ucs4, - int *nchars) +_cairo_ft_font_destroy_unscaled_font (void *abstract_font) { - int len = 0, step = 0; - int n = 0, alloc = 0; - FcChar32 u = 0; + ft_unscaled_font_t *unscaled = abstract_font; - if (utf8 == NULL || ucs4 == NULL || nchars == NULL) - return; + if (!unscaled->from_face) { + cairo_cache_t *cache; + cairo_ft_cache_key_t key; + + _lock_global_ft_cache (); + cache = _get_global_ft_cache (); + assert (cache); - len = strlen (utf8); - alloc = len; - *ucs4 = malloc (sizeof (FT_ULong) * alloc); - if (*ucs4 == NULL) - return; - - while (len && (step = FcUtf8ToUcs4(utf8, &u, len)) > 0) - { - if (n == alloc) - { - alloc *= 2; - *ucs4 = realloc (*ucs4, sizeof (FT_ULong) * alloc); - if (*ucs4 == NULL) - return; - } - (*ucs4)[n++] = u; - len -= step; - utf8 += step; + key.filename = unscaled->filename; + key.id = unscaled->id; + + _cairo_cache_remove (cache, &key); + + _unlock_global_ft_cache (); } - *nchars = n; -} - -/* - * Split a matrix into the component pieces of scale and shape - */ - -static void -_cairo_ft_font_compute_transform (ft_font_transform_t *sf, cairo_font_scale_t *sc) -{ - cairo_matrix_t normalized; - double tx, ty; - /* The font matrix has x and y "scale" components which we extract and - * use as character scale values. These influence the way freetype - * chooses hints, as well as selecting different bitmaps in - * hand-rendered fonts. We also copy the normalized matrix to - * freetype's transformation. - */ - - cairo_matrix_set_affine (&normalized, - sc->matrix[0][0], - sc->matrix[0][1], - sc->matrix[1][0], - sc->matrix[1][1], - 0, 0); - - _cairo_matrix_compute_scale_factors (&normalized, - &sf->x_scale, &sf->y_scale, - /* XXX */ 1); - cairo_matrix_scale (&normalized, 1.0 / sf->x_scale, 1.0 / sf->y_scale); - cairo_matrix_get_affine (&normalized, - &sf->shape[0][0], &sf->shape[0][1], - &sf->shape[1][0], &sf->shape[1][1], - &tx, &ty); -} - -/* - * Set the font transformation - */ - -static void -_cairo_ft_font_install_transform (ft_font_transform_t *sf, FT_Face face) -{ - FT_Matrix mat; - - mat.xx = DOUBLE_TO_16_16(sf->shape[0][0]); - mat.yx = -DOUBLE_TO_16_16(sf->shape[0][1]); - mat.xy = -DOUBLE_TO_16_16(sf->shape[1][0]); - mat.yy = DOUBLE_TO_16_16(sf->shape[1][1]); + if (unscaled == NULL) + return; - FT_Set_Transform(face, &mat, NULL); + if (!unscaled->from_face && unscaled->face) + FT_Done_Face (unscaled->face); - FT_Set_Char_Size(face, - (FT_F26Dot6) (sf->x_scale * 64.0), - (FT_F26Dot6) (sf->y_scale * 64.0), - 0, 0); + if (unscaled->filename) + free (unscaled->filename); + + free (unscaled); } static void -_install_font_scale (cairo_font_scale_t *sc, FT_Face face) +_cairo_ft_font_get_glyph_cache_key (void *abstract_font, + cairo_glyph_cache_key_t *key) { - cairo_matrix_t normalized; - double x_scale, y_scale; - double xx, xy, yx, yy, tx, ty; - FT_Matrix mat; - - /* The font matrix has x and y "scale" components which we extract and - * use as character scale values. These influence the way freetype - * chooses hints, as well as selecting different bitmaps in - * hand-rendered fonts. We also copy the normalized matrix to - * freetype's transformation. - */ - - cairo_matrix_set_affine (&normalized, - sc->matrix[0][0], - sc->matrix[0][1], - sc->matrix[1][0], - sc->matrix[1][1], - 0, 0); - - _cairo_matrix_compute_scale_factors (&normalized, &x_scale, &y_scale, - /* XXX */ 1); - cairo_matrix_scale (&normalized, 1.0 / x_scale, 1.0 / y_scale); - cairo_matrix_get_affine (&normalized, - &xx /* 00 */ , &yx /* 01 */, - &xy /* 10 */, &yy /* 11 */, - &tx, &ty); - - mat.xx = DOUBLE_TO_16_16(xx); - mat.xy = -DOUBLE_TO_16_16(xy); - mat.yx = -DOUBLE_TO_16_16(yx); - mat.yy = DOUBLE_TO_16_16(yy); - - FT_Set_Transform(face, &mat, NULL); + cairo_ft_font_t *font = abstract_font; - FT_Set_Pixel_Sizes(face, - (FT_UInt) x_scale, - (FT_UInt) y_scale); + key->unscaled = (cairo_unscaled_font_t *)font->unscaled; + key->scale = font->base.scale; + key->flags = font->load_flags; } static cairo_status_t _cairo_ft_font_text_to_glyphs (void *abstract_font, - cairo_font_scale_t *sc, const unsigned char *utf8, cairo_glyph_t **glyphs, int *nglyphs) { double x = 0., y = 0.; size_t i; - FT_ULong *ucs4 = NULL; + uint32_t *ucs4 = NULL; cairo_ft_font_t *font = abstract_font; - FT_Face face = font->val->face; + FT_Face face; cairo_glyph_cache_key_t key; cairo_image_glyph_cache_entry_t *val; - cairo_cache_t *cache; + cairo_cache_t *cache = NULL; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - key.unscaled = &font->base; - key.scale = *sc; + _cairo_ft_font_get_glyph_cache_key (font, &key); - _utf8_to_ucs4 (utf8, &ucs4, nglyphs); - - if (ucs4 == NULL) - return CAIRO_STATUS_NO_MEMORY; + status = _cairo_utf8_to_ucs4 (utf8, -1, &ucs4, nglyphs); + if (!CAIRO_OK (status)) + return status; - *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); - if (*glyphs == NULL) - { - free (ucs4); - return CAIRO_STATUS_NO_MEMORY; + face = cairo_ft_font_lock_face ((cairo_font_t *)font); + if (!face) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL1; } _cairo_lock_global_image_glyph_cache (); cache = _cairo_get_global_image_glyph_cache (); if (cache == NULL) { - _cairo_unlock_global_image_glyph_cache (); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; + } + + *glyphs = (cairo_glyph_t *) malloc ((*nglyphs) * (sizeof (cairo_glyph_t))); + if (*glyphs == NULL) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL2; } for (i = 0; i < *nglyphs; i++) @@ -589,51 +769,62 @@ _cairo_ft_font_text_to_glyphs (void *abstract_font, val = NULL; key.index = (*glyphs)[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &val) + if (_cairo_cache_lookup (cache, &key, (void **) &val, NULL) != CAIRO_STATUS_SUCCESS || val == NULL) continue; x += val->extents.x_advance; y += val->extents.y_advance; } - _cairo_unlock_global_image_glyph_cache (); + FAIL2: + if (cache) + _cairo_unlock_global_image_glyph_cache (); + + cairo_ft_font_unlock_face ((cairo_font_t *)font); + + FAIL1: free (ucs4); - return CAIRO_STATUS_SUCCESS; + + return status; } static cairo_status_t _cairo_ft_font_font_extents (void *abstract_font, - cairo_font_scale_t *sc, cairo_font_extents_t *extents) { cairo_ft_font_t *font = abstract_font; - FT_Face face = font->val->face; - FT_Size_Metrics *metrics = &face->size->metrics; - ft_font_transform_t sf; + FT_Face face; + FT_Size_Metrics *metrics; + + face = _ft_unscaled_font_lock_face (font->unscaled); + if (!face) + return CAIRO_STATUS_NO_MEMORY; - _cairo_ft_font_compute_transform (&sf, sc); - _cairo_ft_font_install_transform (&sf, face); + metrics = &face->size->metrics; + _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale); + /* * Get to unscaled metrics so that the upper level can get back to * user space */ - extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / sf.y_scale; - extents->descent = DOUBLE_FROM_26_6(metrics->descender) / sf.y_scale; - extents->height = DOUBLE_FROM_26_6(metrics->height) / sf.y_scale; - extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / sf.x_scale; + extents->ascent = DOUBLE_FROM_26_6(metrics->ascender) / font->unscaled->y_scale; + extents->descent = DOUBLE_FROM_26_6(metrics->descender) / font->unscaled->y_scale; + extents->height = DOUBLE_FROM_26_6(metrics->height) / font->unscaled->y_scale; + extents->max_x_advance = DOUBLE_FROM_26_6(metrics->max_advance) / font->unscaled->x_scale; /* FIXME: this doesn't do vertical layout atm. */ extents->max_y_advance = 0.0; + _ft_unscaled_font_unlock_face (font->unscaled); + return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_ft_font_glyph_extents (void *abstract_font, - cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents) @@ -670,14 +861,13 @@ _cairo_ft_font_glyph_extents (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; + _cairo_ft_font_get_glyph_cache_key (font, &key); for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL) continue; @@ -721,7 +911,6 @@ _cairo_ft_font_glyph_extents (void *abstract_font, static cairo_status_t _cairo_ft_font_glyph_bbox (void *abstract_font, - cairo_font_scale_t *sc, const cairo_glyph_t *glyphs, int num_glyphs, cairo_box_t *bbox) @@ -747,16 +936,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; - + _cairo_ft_font_get_glyph_cache_key (font, &key); + for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL) continue; @@ -785,12 +973,15 @@ _cairo_ft_font_glyph_bbox (void *abstract_font, static cairo_status_t _cairo_ft_font_show_glyphs (void *abstract_font, - cairo_font_scale_t *sc, cairo_operator_t operator, - cairo_surface_t *source, + cairo_pattern_t *pattern, cairo_surface_t *surface, int source_x, int source_y, + int dest_x, + int dest_y, + unsigned int width, + unsigned int height, const cairo_glyph_t *glyphs, int num_glyphs) { @@ -798,9 +989,9 @@ _cairo_ft_font_show_glyphs (void *abstract_font, cairo_cache_t *cache; cairo_glyph_cache_key_t key; cairo_ft_font_t *font = abstract_font; + cairo_surface_pattern_t glyph_pattern; cairo_status_t status; - - double x, y; + int x, y; int i; _cairo_lock_global_image_glyph_cache (); @@ -808,47 +999,54 @@ _cairo_ft_font_show_glyphs (void *abstract_font, if (cache == NULL || font == NULL - || source == NULL + || pattern == NULL || surface == NULL || glyphs == NULL) { _cairo_unlock_global_image_glyph_cache (); return CAIRO_STATUS_NO_MEMORY; } - key.unscaled = &font->base; - key.scale = *sc; + key.unscaled = (cairo_unscaled_font_t *)font->unscaled; + key.scale = font->base.scale; + key.flags = font->load_flags; for (i = 0; i < num_glyphs; i++) { img = NULL; key.index = glyphs[i].index; - if (_cairo_cache_lookup (cache, &key, (void **) &img) + if (_cairo_cache_lookup (cache, &key, (void **) &img, NULL) != CAIRO_STATUS_SUCCESS || img == NULL || img->image == NULL) continue; - x = glyphs[i].x; - y = glyphs[i].y; + x = (int) floor (glyphs[i].x + 0.5); + y = (int) floor (glyphs[i].y + 0.5); + + _cairo_pattern_init_for_surface (&glyph_pattern, &(img->image->base)); - status = _cairo_surface_composite (operator, source, - &(img->image->base), + status = _cairo_surface_composite (operator, pattern, + &glyph_pattern.base, surface, - source_x + x + img->size.x, - source_y + y + img->size.y, + x + img->size.x, + y + img->size.y, 0, 0, x + img->size.x, y + img->size.y, (double) img->size.width, (double) img->size.height); + _cairo_pattern_fini (&glyph_pattern.base); + if (status) { - _cairo_unlock_global_image_glyph_cache (); + _cairo_unlock_global_image_glyph_cache (); return status; } } + _cairo_unlock_global_image_glyph_cache (); + return CAIRO_STATUS_SUCCESS; } @@ -932,7 +1130,6 @@ _cubic_to (FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *closur static cairo_status_t _cairo_ft_font_glyph_path (void *abstract_font, - cairo_font_scale_t *sc, cairo_glyph_t *glyphs, int num_glyphs, cairo_path_t *path) @@ -940,6 +1137,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, int i; cairo_ft_font_t *font = abstract_font; FT_GlyphSlot glyph; + FT_Face face; FT_Error error; FT_Outline_Funcs outline_funcs = { _move_to, @@ -949,10 +1147,12 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, /* shift */ 0, /* delta */ }; + + face = cairo_ft_font_lock_face (abstract_font); + if (!face) + return CAIRO_STATUS_NO_MEMORY; - glyph = font->val->face->glyph; - - _install_font_scale (sc, font->val->face); + glyph = face->glyph; for (i = 0; i < num_glyphs; i++) { @@ -961,7 +1161,7 @@ _cairo_ft_font_glyph_path (void *abstract_font, 0, DOUBLE_TO_16_16 (-1.0), }; - error = FT_Load_Glyph (font->val->face, glyphs[i].index, FT_LOAD_DEFAULT); + error = FT_Load_Glyph (font->unscaled->face, glyphs[i].index, font->load_flags | FT_LOAD_NO_BITMAP); /* XXX: What to do in this error case? */ if (error) continue; @@ -977,32 +1177,39 @@ _cairo_ft_font_glyph_path (void *abstract_font, FT_Outline_Decompose (&glyph->outline, &outline_funcs, path); } _cairo_path_close_path (path); + + cairo_ft_font_unlock_face (abstract_font); return CAIRO_STATUS_SUCCESS; } - static cairo_status_t -_cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) +_cairo_ft_font_create_glyph (cairo_image_glyph_cache_entry_t *val) { - cairo_ft_font_t *font = (cairo_ft_font_t *)val->key.unscaled; + ft_unscaled_font_t *unscaled = (ft_unscaled_font_t *)val->key.unscaled; FT_GlyphSlot glyphslot; unsigned int width, height, stride; + FT_Face face; FT_Outline *outline; FT_BBox cbox; FT_Bitmap bitmap; FT_Glyph_Metrics *metrics; - ft_font_transform_t sf; + cairo_status_t status = CAIRO_STATUS_SUCCESS; - glyphslot = font->val->face->glyph; + glyphslot = unscaled->face->glyph; metrics = &glyphslot->metrics; - _cairo_ft_font_compute_transform (&sf, &val->key.scale); - _cairo_ft_font_install_transform (&sf, font->val->face); - - if (FT_Load_Glyph (font->val->face, val->key.index, FT_LOAD_DEFAULT) != 0) + face = _ft_unscaled_font_lock_face (unscaled); + if (!face) return CAIRO_STATUS_NO_MEMORY; + _ft_unscaled_font_set_scale (unscaled, &val->key.scale); + + if (FT_Load_Glyph (face, val->key.index, val->key.flags) != 0) { + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } + /* * Note: the font's coordinate system is upside down from ours, so the * Y coordinates of the bearing and advance need to be negated. @@ -1011,11 +1218,11 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) * by FreeType */ - val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / sf.x_scale; - val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / sf.y_scale; + val->extents.x_bearing = DOUBLE_FROM_26_6 (metrics->horiBearingX) / unscaled->x_scale; + val->extents.y_bearing = -DOUBLE_FROM_26_6 (metrics->horiBearingY) / unscaled->y_scale; - val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / sf.x_scale; - val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / sf.y_scale; + val->extents.width = DOUBLE_FROM_26_6 (metrics->width) / unscaled->x_scale; + val->extents.height = DOUBLE_FROM_26_6 (metrics->height) / unscaled->y_scale; /* * use untransformed advance values @@ -1023,8 +1230,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) should provide FT_LOAD_VERTICAL_LAYOUT */ - val->extents.x_advance = DOUBLE_FROM_26_6 (font->val->face->glyph->metrics.horiAdvance) / sf.x_scale; - val->extents.y_advance = 0 / sf.y_scale; + val->extents.x_advance = DOUBLE_FROM_26_6 (face->glyph->metrics.horiAdvance) / unscaled->x_scale; + val->extents.y_advance = 0 / unscaled->y_scale; outline = &glyphslot->outline; @@ -1052,14 +1259,16 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) bitmap.buffer = calloc (1, stride * height); if (bitmap.buffer == NULL) { - return CAIRO_STATUS_NO_MEMORY; - }; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; + } FT_Outline_Translate (outline, -cbox.xMin, -cbox.yMin); if (FT_Outline_Get_Bitmap (glyphslot->library, outline, &bitmap) != 0) { free (bitmap.buffer); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; } val->image = (cairo_image_surface_t *) @@ -1068,7 +1277,8 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) width, height, stride); if (val->image == NULL) { free (bitmap.buffer); - return CAIRO_STATUS_NO_MEMORY; + status = CAIRO_STATUS_NO_MEMORY; + goto FAIL; } _cairo_image_surface_assume_ownership_of_data (val->image); @@ -1084,138 +1294,245 @@ _cairo_ft_font_create_glyph(cairo_image_glyph_cache_entry_t *val) val->size.x = (short) (cbox.xMin >> 6); val->size.y = - (short) (cbox.yMax >> 6); - return CAIRO_STATUS_SUCCESS; + FAIL: + _ft_unscaled_font_unlock_face (unscaled); + + return status; } const cairo_font_backend_t cairo_ft_font_backend = { _cairo_ft_font_create, - _cairo_ft_font_destroy, + _cairo_ft_font_destroy_font, + _cairo_ft_font_destroy_unscaled_font, _cairo_ft_font_font_extents, _cairo_ft_font_text_to_glyphs, _cairo_ft_font_glyph_extents, _cairo_ft_font_glyph_bbox, _cairo_ft_font_show_glyphs, _cairo_ft_font_glyph_path, + _cairo_ft_font_get_glyph_cache_key, _cairo_ft_font_create_glyph }; - /* implement the platform-specific interface */ +/** + * cairo_ft_font_create: + * @pattern: A fully resolved fontconfig + * pattern. A pattern can be resolved, by, among other things, calling + * FcConfigSubstitute(), FcDefaultSubstitute(), then + * FcFontMatch(). Cairo will call FcPatternReference() on this + * pattern, so you should not further modify the pattern, but you can + * release your reference to the pattern with FcPatternDestroy() if + * you no longer need to access it. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font for the FreeType font backend based on a + * fontconfig pattern. This font can then be used with + * cairo_set_font(), cairo_font_glyph_extents(), or FreeType backend + * specific functions like cairo_ft_font_lock_face(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ cairo_font_t * -cairo_ft_font_create (FT_Library ft_library, FcPattern *pattern) +cairo_ft_font_create (FcPattern *pattern, + cairo_matrix_t *scale) { - cairo_font_scale_t scale; - cairo_font_t *scaled; - cairo_ft_font_t *f = NULL; - ft_font_val_t *v = NULL; - FcPattern *dup; - - scale.matrix[0][0] = 1.; - scale.matrix[0][1] = 0.; - scale.matrix[1][0] = 0.; - scale.matrix[1][1] = 1.; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - goto FAIL; - - dup = FcPatternDuplicate(pattern); - if (dup == NULL) - goto FREE_SCALED; - - v = _create_from_library_and_pattern (ft_library, pattern); - if (v == NULL) - goto FREE_PATTERN; - - f = malloc (sizeof(cairo_ft_font_t)); - if (f == NULL) - goto FREE_VAL; - - if (_cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend)) - goto FREE_VAL; - - f->pattern = dup; - f->val = v; - - _cairo_font_init (scaled, &scale, &f->base); - - return scaled; - - FREE_VAL: - _destroy_font_val (v); - - FREE_PATTERN: - FcPatternDestroy (dup); + cairo_font_scale_t sc; + double tx, ty; - FREE_SCALED: - free (scaled); + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + &tx, &ty); - FAIL: - return NULL; + return _ft_font_create (pattern, &sc); } +/** + * cairo_ft_font_create_for_ft_face: + * @face: A FreeType face object, already opened. This must + * be kept around until the font object's refcount drops to + * zero and it is freed. The font object can be kept alive by + * internal caching, so it's safest to keep the face object + * around forever. + * @load_flags: The flags to pass to FT_Load_Glyph when loading + * glyphs from the font. These flags control aspects of + * rendering such as hinting and antialiasing. See the FreeType + * docs for full information. + * @scale: The scale at which this font will be used. The + * scale is given by multiplying the font matrix (see + * cairo_transform_font()) by the current transformation matrix. + * The translation elements of the resulting matrix are ignored. + * + * Creates a new font forthe FreeType font backend from a pre-opened + * FreeType face. This font can then be used with cairo_set_font(), + * cairo_font_glyph_extents(), or FreeType backend specific + * functions like cairo_ft_font_lock_face() Cairo will determine the + * pixel size and transformation from the @scale parameter and call + * FT_Set_Transform() and FT_Set_Pixel_Sizes(). + * + * Return value: a newly created #cairo_font_t. Free with + * cairo_font_destroy() when you are done using it. + **/ cairo_font_t * -cairo_ft_font_create_for_ft_face (FT_Face face) +cairo_ft_font_create_for_ft_face (FT_Face face, + int load_flags, + cairo_matrix_t *scale) { - cairo_font_scale_t scale; - cairo_font_t *scaled; cairo_ft_font_t *f = NULL; - ft_font_val_t *v = NULL; - - scale.matrix[0][0] = 1.; - scale.matrix[0][1] = 0.; - scale.matrix[1][0] = 0.; - scale.matrix[1][1] = 1.; - - scaled = malloc (sizeof (cairo_font_t)); - if (scaled == NULL) - goto FAIL; + ft_unscaled_font_t *unscaled = NULL; + cairo_font_scale_t sc; + double tx, ty; - v = _create_from_face (face, 0); - if (v == NULL) - goto FREE_SCALED; + unscaled = _ft_unscaled_font_create_from_face (face); + if (unscaled == NULL) + return NULL; f = malloc (sizeof(cairo_ft_font_t)); if (f == NULL) - goto FREE_VAL; + goto FREE_UNSCALED; - _cairo_unscaled_font_init (&f->base, &cairo_ft_font_backend); + f->unscaled = unscaled; f->pattern = NULL; - f->val = v; + f->load_flags = load_flags; - _cairo_font_init (scaled, &scale, &f->base); + cairo_matrix_get_affine (scale, + &sc.matrix[0][0], &sc.matrix[0][1], + &sc.matrix[1][0], &sc.matrix[1][1], + &tx, &ty); - return scaled; + _cairo_font_init ((cairo_font_t *)f, &sc, &cairo_ft_font_backend); - FREE_VAL: - _destroy_font_val (v); + return (cairo_font_t *)f; - FREE_SCALED: - free (scaled); + FREE_UNSCALED: + _cairo_unscaled_font_destroy ((cairo_unscaled_font_t *)unscaled); - FAIL: return NULL; } + +/** + * cairo_ft_font_lock_face: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * cairo_ft_font_lock_face() gets the #FT_Face object from a FreeType + * backend font and scales it appropriately for the font. You must + * release the face with cairo_ft_font_unlock_face() + * when you are done using it. Since the #FT_Face object can be + * shared between multiple #cairo_font_t objects, you must not + * lock any other font objects until you unlock this one. A count is + * kept of the number of times cairo_ft_font_lock_face() is + * called. cairo_ft_font_unlock_face() must be called the same number + * of times. + * + * You must be careful when using this function in a library or in a + * threaded application, because other threads may lock faces that + * share the same #FT_Face object. For this reason, you must call + * cairo_ft_lock() before locking any face objects, and + * cairo_ft_unlock() after you are done. (These functions are not yet + * implemented, so this function cannot be currently safely used in a + * threaded application.) + + * Return value: The #FT_Face object for @font, scaled appropriately. + **/ FT_Face -cairo_ft_font_face (cairo_font_t *abstract_font) +cairo_ft_font_lock_face (cairo_font_t *abstract_font) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + FT_Face face; - if (font == NULL || font->val == NULL) - return NULL; + face = _ft_unscaled_font_lock_face (font->unscaled); + if (!face) + return NULL; + + _ft_unscaled_font_set_scale (font->unscaled, &font->base.scale); + + return face; +} - return font->val->face; +/** + * cairo_ft_font_unlock_face: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * Releases a face obtained with cairo_ft_font_lock_face(). See the + * documentation for that function for full details. + **/ +void +cairo_ft_font_unlock_face (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + + _ft_unscaled_font_unlock_face (font->unscaled); } +/** + * cairo_ft_font_get_pattern: + * @ft_font: A #cairo_font_t from the FreeType font backend. Such an + * object can be created with cairo_ft_font_create() or + * cairo_ft_font_create_for_ft_face(). On some platforms the font from + * cairo_current_font() will also be a FreeType font, but using this + * functionality with fonts you don't create yourself is not + * recommended. + * + * cairo_ft_font_get_pattern() gets the #FcPattern for a FreeType + * backend font. + + * Return value: The #FcPattenr for @font. The return value is owned + * by the font, so you must not modify it, and must call + * FcPatternReference() to keep a persistant reference to the + * pattern. If the font was created with cairo_ft_font_create_for_ft_face() + * returns %NULL. + **/ FcPattern * -cairo_ft_font_pattern (cairo_font_t *abstract_font) +cairo_ft_font_get_pattern (cairo_font_t *abstract_font) { - cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font->unscaled; + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; if (font == NULL) return NULL; return font->pattern; } + +/* We expose our unscaled font implementation internally for the the + * PDF backend, which needs to keep track of the the different + * fonts-on-disk used by a document, so it can embed them. + */ +cairo_unscaled_font_t * +_cairo_ft_font_get_unscaled_font (cairo_font_t *abstract_font) +{ + cairo_ft_font_t *font = (cairo_ft_font_t *) abstract_font; + + return (cairo_unscaled_font_t *)font->unscaled; +} + +/* This differs from _cairo_ft_scaled_font_lock_face in that it doesn't + * set the scale on the face, but just returns it at the last scale. + */ +FT_Face +_cairo_ft_unscaled_font_lock_face (cairo_unscaled_font_t *unscaled_font) +{ + return _ft_unscaled_font_lock_face ((ft_unscaled_font_t *)unscaled_font); +} + +void +_cairo_ft_unscaled_font_unlock_face (cairo_unscaled_font_t *unscaled_font) +{ + _ft_unscaled_font_unlock_face ((ft_unscaled_font_t *)unscaled_font); +} |