📄 cairo-ft-font.c
字号:
/* cairo - a vector graphics library with display and print output * * Copyright © 2000 Keith Packard * 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 * * 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/ * * 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. * * 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> * Keith Packard <keithp@keithp.com> * Carl Worth <cworth@cworth.org> */#include <float.h>#include "cairo-ft-private.h"#include <fontconfig/fontconfig.h>#include <fontconfig/fcfreetype.h>#include <ft2build.h>#include FT_FREETYPE_H#include FT_OUTLINE_H#include FT_IMAGE_H#if HAVE_FT_GLYPHSLOT_EMBOLDEN#include FT_SYNTHESIS_H#endif#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 64.0))#define DOUBLE_FROM_26_6(t) ((double)(t) / 64.0)#define DOUBLE_TO_16_16(d) ((FT_Fixed)((d) * 65536.0))#define DOUBLE_FROM_16_16(t) ((double)(t) / 65536.0)/* This is the max number of FT_face objects we keep open at once */#define MAX_OPEN_FACES 10/* * The simple 2x2 matrix is converted into separate scale and shape * factors so that hinting works right */typedef struct _cairo_ft_font_transform { double x_scale, y_scale; double shape[2][2];} cairo_ft_font_transform_t;/* * 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_face_create_for_ft_face(), we * just create a one-off version with a permanent face value. */typedef struct _cairo_ft_font_face cairo_ft_font_face_t;struct _cairo_ft_unscaled_font { cairo_unscaled_font_t base; cairo_bool_t from_face; /* from cairo_ft_font_face_create_for_ft_face()? */ FT_Face face; /* provided or cached face */ /* only set if from_face is false */ char *filename; int id; /* We temporarily scale the unscaled font as needed */ cairo_bool_t have_scale; cairo_matrix_t current_scale; double x_scale; /* Extracted X scale factor */ double y_scale; /* Extracted Y scale factor */ cairo_bool_t have_shape; /* true if the current scale has a non-scale component*/ cairo_matrix_t current_shape; int lock; /* count of how many times this font has been locked */ cairo_ft_font_face_t *faces; /* Linked list of faces for this font */};static int_cairo_ft_unscaled_font_keys_equal (const void *key_a, const void *key_b);static void_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled);typedef enum _cairo_ft_extra_flags { CAIRO_FT_OPTIONS_HINT_METRICS = (1 << 0), CAIRO_FT_OPTIONS_EMBOLDEN = (1 << 1)} cairo_ft_extra_flags_t;typedef struct _cairo_ft_options { cairo_font_options_t base; int load_flags; /* flags for FT_Load_Glyph */ cairo_ft_extra_flags_t extra_flags; /* other flags that affect results */} cairo_ft_options_t;struct _cairo_ft_font_face { cairo_font_face_t base; cairo_ft_unscaled_font_t *unscaled; cairo_ft_options_t ft_options; cairo_ft_font_face_t *next;};static const cairo_unscaled_font_backend_t cairo_ft_unscaled_font_backend;/* * We maintain a hash table to map file/id => cairo_ft_unscaled_font_t. * The hash table itself 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 cairo_ft_unscaled_font_t which has an unlocked FT_Face, (if * there are any). */typedef struct _cairo_ft_unscaled_font_map { cairo_hash_table_t *hash_table; FT_Library ft_library; int num_open_faces;} cairo_ft_unscaled_font_map_t;static cairo_ft_unscaled_font_map_t *cairo_ft_unscaled_font_map = NULL;CAIRO_MUTEX_DECLARE(cairo_ft_unscaled_font_map_mutex);static void_font_map_release_face_lock_held (cairo_ft_unscaled_font_map_t *font_map, cairo_ft_unscaled_font_t *unscaled){ if (unscaled->face) { FT_Done_Face (unscaled->face); unscaled->face = NULL; unscaled->have_scale = FALSE; font_map->num_open_faces--; }}static void_cairo_ft_unscaled_font_map_create (void){ cairo_ft_unscaled_font_map_t *font_map; /* This function is only intended to be called from * _cairo_ft_unscaled_font_map_lock. So we'll crash if we can * detect some other call path. */ assert (cairo_ft_unscaled_font_map == NULL); font_map = malloc (sizeof (cairo_ft_unscaled_font_map_t)); if (font_map == NULL) goto FAIL; font_map->hash_table = _cairo_hash_table_create (_cairo_ft_unscaled_font_keys_equal); if (font_map->hash_table == NULL) goto FAIL; if (FT_Init_FreeType (&font_map->ft_library)) goto FAIL; font_map->num_open_faces = 0; cairo_ft_unscaled_font_map = font_map; return;FAIL: if (font_map) { if (font_map->hash_table) _cairo_hash_table_destroy (font_map->hash_table); free (font_map); } cairo_ft_unscaled_font_map = NULL;}static void_cairo_ft_unscaled_font_map_destroy (void){ cairo_ft_unscaled_font_t *unscaled; cairo_ft_unscaled_font_map_t *font_map; CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex); if (cairo_ft_unscaled_font_map) { font_map = cairo_ft_unscaled_font_map; /* This is rather inefficient, but destroying the hash table * is something we only do during debugging, (during * cairo_debug_reset_static_data), when efficiency is not * relevant. */ while (1) { unscaled = _cairo_hash_table_random_entry (font_map->hash_table, NULL); if (unscaled == NULL) break; _cairo_hash_table_remove (font_map->hash_table, &unscaled->base.hash_entry); _font_map_release_face_lock_held (font_map, unscaled); _cairo_ft_unscaled_font_fini (unscaled); free (unscaled); } assert (font_map->num_open_faces == 0); FT_Done_FreeType (font_map->ft_library); _cairo_hash_table_destroy (font_map->hash_table); free (font_map); cairo_ft_unscaled_font_map = NULL; } CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);}static cairo_ft_unscaled_font_map_t *_cairo_ft_unscaled_font_map_lock (void){ CAIRO_MUTEX_LOCK (cairo_ft_unscaled_font_map_mutex); if (cairo_ft_unscaled_font_map == NULL) { _cairo_ft_unscaled_font_map_create (); if (cairo_ft_unscaled_font_map == NULL) { CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex); return NULL; } } return cairo_ft_unscaled_font_map;}static void_cairo_ft_unscaled_font_map_unlock (void){ CAIRO_MUTEX_UNLOCK (cairo_ft_unscaled_font_map_mutex);}static void_cairo_ft_unscaled_font_init_key (cairo_ft_unscaled_font_t *key, char *filename, int id){ unsigned long hash; key->filename = filename; key->id = id; /* 1607 is just an arbitrary prime. */ hash = _cairo_hash_string (filename); hash += ((unsigned long) id) * 1607; key->base.hash_entry.hash = hash;}/** * _cairo_ft_unscaled_font_init: * * Initialize a cairo_ft_unscaled_font_t. * * There are two basic flavors of cairo_ft_unscaled_font_t, one * created from an FT_Face and the other created from a filename/id * pair. These two flavors are identified as from_face and !from_face. * * To initialize a from_face font, pass filename==NULL, id=0 and the * desired face. * * To initialize a !from_face font, pass the filename/id as desired * and face==NULL. * * Note that the code handles these two flavors in very distinct * ways. For example there is a hash_table mapping * filename/id->cairo_unscaled_font_t in the !from_face case, but no * parallel in the from_face case, (where the calling code would have * to do its own mapping to ensure similar sharing). **/static cairo_status_t_cairo_ft_unscaled_font_init (cairo_ft_unscaled_font_t *unscaled, const char *filename, int id, FT_Face face){ _cairo_unscaled_font_init (&unscaled->base, &cairo_ft_unscaled_font_backend); if (face) { unscaled->from_face = TRUE; unscaled->face = face; unscaled->filename = NULL; unscaled->id = 0; } else { char *filename_copy; unscaled->from_face = FALSE; unscaled->face = NULL; filename_copy = strdup (filename); if (filename_copy == NULL) return CAIRO_STATUS_NO_MEMORY; _cairo_ft_unscaled_font_init_key (unscaled, filename_copy, id); } unscaled->have_scale = FALSE; unscaled->lock = 0; unscaled->faces = NULL; return CAIRO_STATUS_SUCCESS;}cairo_bool_t_cairo_unscaled_font_is_ft (cairo_unscaled_font_t *unscaled_font){ return unscaled_font->backend == &cairo_ft_unscaled_font_backend;}/** * _cairo_ft_unscaled_font_fini: * * Free all data associated with a cairo_ft_unscaled_font_t. * * CAUTION: The unscaled->face field must be NULL before calling this * function. This is because the cairo_ft_unscaled_font_map keeps a * count of these faces (font_map->num_open_faces) so it maintains the * unscaled->face field while it has its lock held. See * _font_map_release_face_lock_held(). **/static void_cairo_ft_unscaled_font_fini (cairo_ft_unscaled_font_t *unscaled){ assert (unscaled->face == NULL); if (unscaled->filename) { free (unscaled->filename); unscaled->filename = NULL; }}static int_cairo_ft_unscaled_font_keys_equal (const void *key_a, const void *key_b){ const cairo_ft_unscaled_font_t *unscaled_a = key_a; const cairo_ft_unscaled_font_t *unscaled_b = key_b; return (strcmp (unscaled_a->filename, unscaled_b->filename) == 0 && unscaled_a->id == unscaled_b->id);}/* Finds or creates a cairo_ft_unscaled_font for the filename/id from * pattern. Returns a new reference to the unscaled font. */static cairo_ft_unscaled_font_t *_cairo_ft_unscaled_font_create_for_pattern (FcPattern *pattern){ cairo_ft_unscaled_font_t key, *unscaled; cairo_ft_unscaled_font_map_t *font_map; cairo_status_t status; FcChar8 *fc_filename; char *filename; int id; if (FcPatternGetString (pattern, FC_FILE, 0, &fc_filename) != FcResultMatch) goto UNWIND; filename = (char *) fc_filename; if (FcPatternGetInteger (pattern, FC_INDEX, 0, &id) != FcResultMatch) goto UNWIND; font_map = _cairo_ft_unscaled_font_map_lock (); if (font_map == NULL) goto UNWIND; _cairo_ft_unscaled_font_init_key (&key, filename, id); /* Return existing unscaled font if it exists in the hash table. */ if (_cairo_hash_table_lookup (font_map->hash_table, &key.base.hash_entry, (cairo_hash_entry_t **) &unscaled)) { _cairo_ft_unscaled_font_map_unlock (); _cairo_unscaled_font_reference (&unscaled->base); return unscaled; } /* Otherwise create it and insert into hash table. */ unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); if (unscaled == NULL) goto UNWIND_FONT_MAP_LOCK; status = _cairo_ft_unscaled_font_init (unscaled, filename, id, NULL); if (status) goto UNWIND_UNSCALED_MALLOC; status = _cairo_hash_table_insert (font_map->hash_table, &unscaled->base.hash_entry); if (status) goto UNWIND_UNSCALED_FONT_INIT; _cairo_ft_unscaled_font_map_unlock (); return unscaled;UNWIND_UNSCALED_FONT_INIT: _cairo_ft_unscaled_font_fini (unscaled);UNWIND_UNSCALED_MALLOC: free (unscaled);UNWIND_FONT_MAP_LOCK: _cairo_ft_unscaled_font_map_unlock ();UNWIND: return NULL;}static cairo_ft_unscaled_font_t *_cairo_ft_unscaled_font_create_from_face (FT_Face face){ cairo_status_t status; cairo_ft_unscaled_font_t *unscaled; unscaled = malloc (sizeof (cairo_ft_unscaled_font_t)); if (unscaled == NULL) return NULL; status = _cairo_ft_unscaled_font_init (unscaled, NULL, 0, face); if (status) { free (unscaled); return NULL; } return unscaled;}static void_cairo_ft_unscaled_font_destroy (void *abstract_font){ cairo_ft_unscaled_font_t *unscaled = abstract_font;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -