summaryrefslogtreecommitdiff
path: root/pango/pangocoretext-fontmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'pango/pangocoretext-fontmap.c')
-rw-r--r--pango/pangocoretext-fontmap.c952
1 files changed, 952 insertions, 0 deletions
diff --git a/pango/pangocoretext-fontmap.c b/pango/pangocoretext-fontmap.c
new file mode 100644
index 00000000..b8cf671f
--- /dev/null
+++ b/pango/pangocoretext-fontmap.c
@@ -0,0 +1,952 @@
+/* Pango
+ * pangocoretext-fontmap.c
+ *
+ * Copyright (C) 2000-2003 Red Hat, Inc.
+ * Copyright (C) 2005-2007 Imendio AB
+ * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "pango-fontmap.h"
+#include "pangocoretext-private.h"
+#include "pango-impl-utils.h"
+#include "modules.h"
+
+#include <Carbon/Carbon.h>
+
+typedef struct _FontHashKey FontHashKey;
+
+struct _PangoCoreTextFamily
+{
+ PangoFontFamily parent_instance;
+
+ char *family_name;
+
+ guint is_monospace : 1;
+
+ PangoFontFace **faces;
+ gint n_faces;
+};
+
+#define PANGO_TYPE_CORE_TEXT_FAMILY (pango_core_text_family_get_type ())
+#define PANGO_CORE_TEXT_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CORE_TEXT_FAMILY, PangoCoreTextFamily))
+#define PANGO_IS_CORE_TEXT_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CORE_TEXT_FAMILY))
+
+#define PANGO_TYPE_CORE_TEXT_FACE (pango_core_text_face_get_type ())
+#define PANGO_CORE_TEXT_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CORE_TEXT_FACE, PangoCoreTextFace))
+#define PANGO_IS_CORE_TEXT_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CORE_TEXT_FACE))
+
+struct _PangoCoreTextFace
+{
+ PangoFontFace parent_instance;
+
+ PangoCoreTextFamily *family;
+
+ PangoCoverage *coverage;
+
+ char *postscript_name;
+ char *style_name;
+
+ float weight;
+ int traits;
+};
+
+static GType pango_core_text_family_get_type (void);
+static GType pango_core_text_face_get_type (void);
+
+static gpointer pango_core_text_family_parent_class;
+static gpointer pango_core_text_face_parent_class;
+
+static const char *
+get_real_family (const char *family_name)
+{
+ switch (family_name[0])
+ {
+ case 'm':
+ case 'M':
+ if (g_ascii_strcasecmp (family_name, "monospace") == 0)
+ return "Courier";
+ break;
+ case 's':
+ case 'S':
+ if (g_ascii_strcasecmp (family_name, "sans") == 0)
+ return "Helvetica";
+ else if (g_ascii_strcasecmp (family_name, "serif") == 0)
+ return "Times";
+ break;
+ }
+
+ return family_name;
+}
+
+static gchar *
+gchar_from_cf_string (CFStringRef str)
+{
+ CFIndex len;
+ gchar *buffer;
+
+ /* GetLength returns the number of UTF-16 pairs, so this number
+ * times 2 should definitely gives us enough space for UTF8.
+ * We add one for the terminating zero.
+ */
+ len = CFStringGetLength (str) * 2 + 1;
+ buffer = g_new0 (char, len);
+ CFStringGetCString (str, buffer, len, kCFStringEncodingUTF8);
+
+ return buffer;
+}
+
+static PangoCoverage *
+pango_coverage_from_cf_charset (CFCharacterSetRef charset)
+{
+ CFIndex i, length;
+ CFDataRef bitmap;
+ const UInt8 *ptr;
+ PangoCoverage *coverage;
+
+ coverage = pango_coverage_new ();
+
+ bitmap = CFCharacterSetCreateBitmapRepresentation (kCFAllocatorDefault,
+ charset);
+
+ /* We only handle the BMP plane */
+ length = MIN (CFDataGetLength (bitmap), 8192);
+ ptr = CFDataGetBytePtr (bitmap);
+
+ /* FIXME: can and should this be done more efficiently? */
+ for (i = 0; i < length; i++)
+ {
+ int j;
+
+ for (j = 0; j < 8; j++)
+ pango_coverage_set (coverage, i * 8 + j,
+ ((ptr[i] & (1 << j)) == (1 << j)) ?
+ PANGO_COVERAGE_EXACT : PANGO_COVERAGE_NONE);
+ }
+
+ CFRelease (bitmap);
+
+ return coverage;
+}
+
+static void
+pango_core_text_family_list_faces (PangoFontFamily *family,
+ PangoFontFace ***faces,
+ int *n_faces)
+{
+ PangoCoreTextFamily *ctfamily = PANGO_CORE_TEXT_FAMILY (family);
+
+ if (ctfamily->n_faces < 0)
+ {
+ GList *l;
+ GList *faces = NULL;
+ const char *real_family = get_real_family (ctfamily->family_name);
+ CTFontCollectionRef collection;
+ CFArrayRef ctfaces;
+ CFArrayRef font_descriptors;
+ CFDictionaryRef attributes;
+ CFIndex i, count;
+
+ CFTypeRef keys[] = {
+ (CFTypeRef) kCTFontFamilyNameAttribute
+ };
+
+ CFStringRef values[] = {
+ CFStringCreateWithCString (kCFAllocatorDefault,
+ real_family,
+ kCFStringEncodingUTF8)
+ };
+
+ CTFontDescriptorRef descriptors[1];
+
+ attributes = CFDictionaryCreate (kCFAllocatorDefault,
+ (const void **)keys,
+ (const void **)values,
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ descriptors[0] = CTFontDescriptorCreateWithAttributes (attributes);
+ font_descriptors = CFArrayCreate (kCFAllocatorDefault,
+ (const void **)descriptors,
+ 1,
+ &kCFTypeArrayCallBacks);
+ collection = CTFontCollectionCreateWithFontDescriptors (font_descriptors,
+ NULL);
+
+ ctfaces = CTFontCollectionCreateMatchingFontDescriptors (collection);
+
+ /* FIXME: do we need the code for the synthetic italic faces? */
+ count = CFArrayGetCount (ctfaces);
+ for (i = 0; i < count; i++)
+ {
+ int font_traits;
+ char *buffer;
+ CFStringRef str;
+ CFNumberRef number;
+ CGFloat value;
+ CFDictionaryRef dict;
+ CFCharacterSetRef charset;
+ CTFontDescriptorRef desc = CFArrayGetValueAtIndex (ctfaces, i);
+ PangoCoreTextFace *face = g_object_new (PANGO_TYPE_CORE_TEXT_FACE,
+ NULL);
+
+ face->family = ctfamily;
+
+ /* Get font name */
+ str = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
+ buffer = gchar_from_cf_string (str);
+
+ /* We strdup again to save space. */
+ face->postscript_name = g_strdup (buffer);
+
+ CFRelease (str);
+ g_free (buffer);
+
+ /* Get style name */
+ str = CTFontDescriptorCopyAttribute (desc, kCTFontStyleNameAttribute);
+ buffer = gchar_from_cf_string (str);
+
+ face->style_name = g_strdup (buffer);
+
+ CFRelease (str);
+ g_free (buffer);
+
+ /* Get font traits, symbolic traits */
+ dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
+ number = (CFNumberRef)CFDictionaryGetValue (dict,
+ kCTFontWeightTrait);
+ if (CFNumberGetValue (number, kCFNumberCGFloatType, &value))
+ /* Map value from range [-1.0, 1.0] to range [1, 14] */
+ face->weight = (value + 1.0f) * 6.5f + 1;
+ else
+ face->weight = PANGO_WEIGHT_NORMAL;
+
+ number = (CFNumberRef)CFDictionaryGetValue (dict,
+ kCTFontSymbolicTrait);
+ if (CFNumberGetValue (number, kCFNumberIntType, &font_traits))
+ {
+ face->traits = font_traits;
+ }
+ CFRelease (dict);
+
+ /* Get font coverage */
+ charset = CTFontDescriptorCopyAttribute (desc,
+ kCTFontCharacterSetAttribute);
+ face->coverage = pango_coverage_from_cf_charset (charset);
+ CFRelease (charset);
+
+ faces = g_list_prepend (faces, face);
+ }
+
+ CFRelease (font_descriptors);
+ CFRelease (attributes);
+ CFRelease (ctfaces);
+
+ ctfamily->n_faces = g_list_length (faces);
+ ctfamily->faces = g_new (PangoFontFace *, ctfamily->n_faces);
+
+ for (l = faces, i = 0; l; l = l->next, i++)
+ ctfamily->faces[i] = l->data;
+
+ g_list_free (faces);
+ }
+
+ if (n_faces)
+ *n_faces = ctfamily->n_faces;
+
+ if (faces)
+ *faces = g_memdup (ctfamily->faces, ctfamily->n_faces * sizeof (PangoFontFace *));
+}
+
+static const char *
+pango_core_text_family_get_name (PangoFontFamily *family)
+{
+ PangoCoreTextFamily *ctfamily = PANGO_CORE_TEXT_FAMILY (family);
+
+ return ctfamily->family_name;
+}
+
+static gboolean
+pango_core_text_family_is_monospace (PangoFontFamily *family)
+{
+ PangoCoreTextFamily *ctfamily = PANGO_CORE_TEXT_FAMILY (family);
+
+ return ctfamily->is_monospace;
+}
+
+static void
+pango_core_text_family_finalize (GObject *object)
+{
+ PangoCoreTextFamily *family = PANGO_CORE_TEXT_FAMILY (object);
+ int i;
+
+ g_free (family->family_name);
+
+ if (family->n_faces != -1)
+ {
+ for (i = 0; i < family->n_faces; i++)
+ g_object_unref (family->faces[i]);
+
+ g_free (family->faces);
+ }
+
+ G_OBJECT_CLASS (pango_core_text_family_parent_class)->finalize (object);
+}
+
+static void
+pango_core_text_family_class_init (PangoFontFamilyClass *class)
+{
+ GObjectClass *object_class = (GObjectClass *)class;
+ int i;
+
+ pango_core_text_family_parent_class = g_type_class_peek_parent (class);
+
+ object_class->finalize = pango_core_text_family_finalize;
+
+ class->list_faces = pango_core_text_family_list_faces;
+ class->get_name = pango_core_text_family_get_name;
+ class->is_monospace = pango_core_text_family_is_monospace;
+
+ for (i = 0; _pango_included_core_text_modules[i].list; i++)
+ pango_module_register (&_pango_included_core_text_modules[i]);
+}
+
+static void
+pango_core_text_family_init (PangoCoreTextFamily *family)
+{
+ family->n_faces = -1;
+}
+
+static GType
+pango_core_text_family_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (G_UNLIKELY (!object_type))
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (PangoFontFamilyClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) pango_core_text_family_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PangoCoreTextFamily),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) pango_core_text_family_init,
+ };
+
+ object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY,
+ I_("PangoCoreTextFamily"),
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+static PangoFontDescription *
+pango_core_text_face_describe (PangoFontFace *face)
+{
+ PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
+ PangoFontDescription *description;
+ PangoWeight pango_weight;
+ PangoStyle pango_style;
+ PangoVariant pango_variant;
+ int weight;
+
+ description = pango_font_description_new ();
+
+ pango_font_description_set_family (description, ctface->family->family_name);
+
+ weight = ctface->weight;
+
+ switch (weight)
+ {
+ case 1:
+ case 2:
+ pango_weight = PANGO_WEIGHT_ULTRALIGHT;
+ break;
+
+ case 3:
+ case 4:
+ pango_weight = PANGO_WEIGHT_LIGHT;
+ break;
+
+ case 5:
+ case 6:
+ pango_weight = PANGO_WEIGHT_NORMAL;
+ break;
+
+ case 7:
+ case 8:
+ pango_weight = PANGO_WEIGHT_SEMIBOLD;
+ break;
+
+ case 9:
+ case 10:
+ pango_weight = PANGO_WEIGHT_BOLD;
+ break;
+
+ case 11:
+ case 12:
+ pango_weight = PANGO_WEIGHT_ULTRABOLD;
+ break;
+
+ case 13:
+ case 14:
+ pango_weight = PANGO_WEIGHT_HEAVY;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ };
+
+ if (ctface->traits & kCTFontItalicTrait)
+ pango_style = PANGO_STYLE_ITALIC;
+ else
+ pango_style = PANGO_STYLE_NORMAL;
+
+ /* FIXME: How can this be figured using CoreText? */
+#if 0
+ if (ctface->traits & NSSmallCapsFontMask)
+ pango_variant = PANGO_VARIANT_SMALL_CAPS;
+ else
+#endif
+ pango_variant = PANGO_VARIANT_NORMAL;
+
+ pango_font_description_set_weight (description, pango_weight);
+ pango_font_description_set_style (description, pango_style);
+ pango_font_description_set_variant (description, pango_variant);
+
+ return description;
+}
+
+static const char *
+pango_core_text_face_get_face_name (PangoFontFace *face)
+{
+ PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
+
+ return ctface->style_name;
+}
+
+static void
+pango_core_text_face_list_sizes (PangoFontFace *face,
+ int **sizes,
+ int *n_sizes)
+{
+ *n_sizes = 0;
+ *sizes = NULL;
+}
+
+static void
+pango_core_text_face_finalize (GObject *object)
+{
+ PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (object);
+
+ if (ctface->coverage)
+ pango_coverage_unref (ctface->coverage);
+
+ g_free (ctface->postscript_name);
+ g_free (ctface->style_name);
+
+ G_OBJECT_CLASS (pango_core_text_face_parent_class)->finalize (object);
+}
+
+static void
+pango_core_text_face_class_init (PangoFontFaceClass *class)
+{
+ GObjectClass *object_class = (GObjectClass *)class;
+
+ pango_core_text_face_parent_class = g_type_class_peek_parent (class);
+
+ object_class->finalize = pango_core_text_face_finalize;
+
+ class->describe = pango_core_text_face_describe;
+ class->get_face_name = pango_core_text_face_get_face_name;
+ class->list_sizes = pango_core_text_face_list_sizes;
+}
+
+GType
+pango_core_text_face_get_type (void)
+{
+ static GType object_type = 0;
+
+ if (G_UNLIKELY (!object_type))
+ {
+ const GTypeInfo object_info =
+ {
+ sizeof (PangoFontFaceClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) pango_core_text_face_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PangoCoreTextFace),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) NULL,
+ };
+
+ object_type = g_type_register_static (PANGO_TYPE_FONT_FACE,
+ I_("PangoCoreTextFace"),
+ &object_info, 0);
+ }
+
+ return object_type;
+}
+
+const char *
+_pango_core_text_face_get_postscript_name (PangoCoreTextFace *face)
+{
+ return face->postscript_name;
+}
+
+PangoCoverage *
+_pango_core_text_face_get_coverage (PangoCoreTextFace *face,
+ PangoLanguage *language)
+{
+ return face->coverage;
+}
+
+static void pango_core_text_font_map_class_init (PangoCoreTextFontMapClass *class);
+static void pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap);
+
+static guint font_hash_key_hash (const FontHashKey *key);
+static gboolean font_hash_key_equal (const FontHashKey *key_a,
+ const FontHashKey *key_b);
+static void font_hash_key_free (FontHashKey *key);
+
+G_DEFINE_TYPE (PangoCoreTextFontMap, pango_core_text_font_map, PANGO_TYPE_FONT_MAP);
+
+static void
+pango_core_text_font_map_finalize (GObject *object)
+{
+ PangoCoreTextFontMap *fontmap = PANGO_CORE_TEXT_FONT_MAP (object);
+
+ g_hash_table_destroy (fontmap->font_hash);
+ g_hash_table_destroy (fontmap->families);
+
+ G_OBJECT_CLASS (pango_core_text_font_map_parent_class)->finalize (object);
+}
+
+struct _FontHashKey {
+ PangoCoreTextFontMap *fontmap;
+ PangoMatrix matrix;
+ PangoFontDescription *desc;
+ char *postscript_name;
+ gpointer context_key;
+};
+
+/* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
+ *
+ * Not necessarily better than a lot of other hashes, but should be OK, and
+ * well tested with binary data.
+ */
+
+#define FNV_32_PRIME ((guint32)0x01000193)
+#define FNV1_32_INIT ((guint32)0x811c9dc5)
+
+static guint32
+hash_bytes_fnv (unsigned char *buffer,
+ int len,
+ guint32 hval)
+{
+ while (len--)
+ {
+ hval *= FNV_32_PRIME;
+ hval ^= *buffer++;
+ }
+
+ return hval;
+}
+
+static gboolean
+font_hash_key_equal (const FontHashKey *key_a,
+ const FontHashKey *key_b)
+{
+ if (key_a->matrix.xx == key_b->matrix.xx &&
+ key_a->matrix.xy == key_b->matrix.xy &&
+ key_a->matrix.yx == key_b->matrix.yx &&
+ key_a->matrix.yy == key_b->matrix.yy &&
+ pango_font_description_equal (key_a->desc, key_b->desc) &&
+ strcmp (key_a->postscript_name, key_b->postscript_name) == 0)
+ {
+ if (key_a->context_key)
+ return PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
+ key_a->context_key,
+ key_b->context_key);
+ else
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static guint
+font_hash_key_hash (const FontHashKey *key)
+{
+ guint32 hash = FNV1_32_INIT;
+
+ /* We do a bytewise hash on the context matrix */
+ hash = hash_bytes_fnv ((unsigned char *)(&key->matrix),
+ sizeof(double) * 4,
+ hash);
+
+ if (key->context_key)
+ hash ^= PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
+ key->context_key);
+
+ hash ^= g_str_hash (key->postscript_name);
+
+ return (hash ^ pango_font_description_hash (key->desc));
+}
+
+static void
+font_hash_key_free (FontHashKey *key)
+{
+ if (key->context_key)
+ PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
+ key->context_key);
+
+ g_slice_free (FontHashKey, key);
+}
+
+static FontHashKey *
+font_hash_key_copy (FontHashKey *old)
+{
+ FontHashKey *key = g_slice_new (FontHashKey);
+
+ key->fontmap = old->fontmap;
+ key->matrix = old->matrix;
+ key->desc = pango_font_description_copy (old->desc);
+ key->postscript_name = g_strdup (old->postscript_name);
+ if (old->context_key)
+ key->context_key = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap, old->context_key);
+ else
+ key->context_key = NULL;
+
+ return key;
+}
+
+
+static void
+get_context_matrix (PangoContext *context,
+ PangoMatrix *matrix)
+{
+ const PangoMatrix *set_matrix;
+ static const PangoMatrix identity = PANGO_MATRIX_INIT;
+
+ if (context)
+ set_matrix = pango_context_get_matrix (context);
+ else
+ set_matrix = NULL;
+
+ if (set_matrix)
+ *matrix = *set_matrix;
+ else
+ *matrix = identity;
+}
+
+static void
+font_hash_key_for_context (PangoCoreTextFontMap *fcfontmap,
+ PangoContext *context,
+ FontHashKey *key)
+{
+ key->fontmap = fcfontmap;
+ get_context_matrix (context, &key->matrix);
+
+ if (PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get)
+ key->context_key = (gpointer)PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get (fcfontmap, context);
+ else
+ key->context_key = NULL;
+}
+
+static void
+pango_core_text_font_map_add (PangoCoreTextFontMap *ctfontmap,
+ PangoContext *context,
+ PangoCoreTextFont *ctfont)
+{
+ FontHashKey key;
+ FontHashKey *key_copy;
+ PangoCoreTextFace *face;
+
+ _pango_core_text_font_set_font_map (ctfont, ctfontmap);
+
+ font_hash_key_for_context (ctfontmap, context, &key);
+ face = _pango_core_text_font_get_face (ctfont);
+ key.postscript_name = (char *)_pango_core_text_face_get_postscript_name (face);
+ key.desc = _pango_core_text_font_get_font_description (ctfont);
+
+ key_copy = font_hash_key_copy (&key);
+ _pango_core_text_font_set_context_key (ctfont, key_copy->context_key);
+ g_hash_table_insert (ctfontmap->font_hash, key_copy, g_object_ref (ctfont));
+}
+
+static PangoCoreTextFont *
+pango_core_text_font_map_lookup (PangoCoreTextFontMap *ctfontmap,
+ PangoContext *context,
+ PangoFontDescription *desc,
+ PangoCoreTextFace *face)
+{
+ FontHashKey key;
+
+ font_hash_key_for_context (ctfontmap, context, &key);
+ key.postscript_name = (char *)_pango_core_text_face_get_postscript_name (face);
+ key.desc = desc;
+
+ return g_hash_table_lookup (ctfontmap->font_hash, &key);
+}
+
+static gboolean
+find_best_match (PangoCoreTextFamily *font_family,
+ const PangoFontDescription *description,
+ PangoFontDescription **best_description,
+ PangoCoreTextFace **best_face)
+{
+ PangoFontDescription *new_desc;
+ int i;
+
+ *best_description = NULL;
+ *best_face = NULL;
+
+ for (i = 0; i < font_family->n_faces; i++)
+ {
+ new_desc = pango_font_face_describe (font_family->faces[i]);
+
+ if (pango_font_description_better_match (description, *best_description, new_desc))
+ {
+ pango_font_description_free (*best_description);
+ *best_description = new_desc;
+ *best_face = (PangoCoreTextFace *)font_family->faces[i];
+ }
+ else
+ pango_font_description_free (new_desc);
+ }
+
+ if (*best_description)
+ return TRUE;
+
+ return FALSE;
+}
+
+static PangoFont *
+pango_core_text_font_map_load_font (PangoFontMap *fontmap,
+ PangoContext *context,
+ const PangoFontDescription *description)
+{
+ PangoCoreTextFontMap *ctfontmap = (PangoCoreTextFontMap *)fontmap;
+ PangoCoreTextFamily *font_family;
+ const gchar *family;
+ gchar *name;
+ gint size;
+
+ size = pango_font_description_get_size (description);
+ if (size < 0)
+ return NULL;
+
+ family = pango_font_description_get_family (description);
+ family = family ? family : "";
+ name = g_utf8_casefold (family, -1);
+ font_family = g_hash_table_lookup (ctfontmap->families, name);
+ g_free (name);
+
+ if (font_family)
+ {
+ PangoFontDescription *best_description;
+ PangoCoreTextFace *best_face;
+ PangoCoreTextFont *best_font;
+
+ /* Force a listing of the available faces */
+ pango_font_family_list_faces ((PangoFontFamily *)font_family, NULL, NULL);
+
+ if (!find_best_match (font_family, description, &best_description, &best_face))
+ return NULL;
+
+ pango_font_description_set_size (best_description, size);
+
+ best_font = pango_core_text_font_map_lookup (ctfontmap,
+ context,
+ best_description,
+ best_face);
+
+ if (best_font)
+ g_object_ref (best_font);
+ else
+ {
+ PangoCoreTextFontMapClass *klass;
+
+ klass = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (ctfontmap);
+ best_font = klass->create_font (ctfontmap, context,
+ best_face, best_description);
+
+ if (best_font)
+ pango_core_text_font_map_add (ctfontmap, context, best_font);
+ /* FIXME: Handle the else case here. */
+ }
+
+ pango_font_description_free (best_description);
+
+ return (PangoFont *)best_font;
+ }
+
+ return NULL;
+}
+
+static void
+list_families_foreach (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GSList **list = user_data;
+
+ *list = g_slist_prepend (*list, value);
+}
+
+static void
+pango_core_text_font_map_list_families (PangoFontMap *fontmap,
+ PangoFontFamily ***families,
+ int *n_families)
+{
+ GSList *family_list = NULL;
+ GSList *tmp_list;
+ PangoCoreTextFontMap *ctfontmap = (PangoCoreTextFontMap *)fontmap;
+
+ if (!n_families)
+ return;
+
+ g_hash_table_foreach (ctfontmap->families,
+ list_families_foreach, &family_list);
+
+ *n_families = g_slist_length (family_list);
+
+ if (families)
+ {
+ int i = 0;
+
+ *families = g_new (PangoFontFamily *, *n_families);
+
+ tmp_list = family_list;
+ while (tmp_list)
+ {
+ (*families)[i] = tmp_list->data;
+ i++;
+ tmp_list = tmp_list->next;
+ }
+ }
+
+ g_slist_free (family_list);
+}
+
+static void
+pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
+{
+ PangoCoreTextFamily *family;
+ CTFontCollectionRef collection;
+ CFArrayRef ctfaces;
+ CFIndex i, count;
+
+ ctfontmap->families = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
+
+
+ ctfontmap->font_hash = g_hash_table_new_full ((GHashFunc)font_hash_key_hash,
+ (GEqualFunc)font_hash_key_equal,
+ (GDestroyNotify)font_hash_key_free,
+ NULL);
+
+ collection = CTFontCollectionCreateFromAvailableFonts (0);
+ ctfaces = CTFontCollectionCreateMatchingFontDescriptors (collection);
+ count = CFArrayGetCount (ctfaces);
+
+ for (i = 0; i < count; i++)
+ {
+ int font_traits;
+ char *buffer;
+ char *family_name;
+ CFStringRef str;
+ CFNumberRef number;
+ CFDictionaryRef dict;
+ CTFontDescriptorRef desc = CFArrayGetValueAtIndex (ctfaces, i);
+
+ str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
+ buffer = gchar_from_cf_string (str);
+
+ family_name = g_utf8_casefold (buffer, -1);
+
+ CFRelease (str);
+ g_free (buffer);
+
+ family = g_hash_table_lookup (ctfontmap->families, family_name);
+ if (!family)
+ {
+ family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
+ g_hash_table_insert (ctfontmap->families, g_strdup (family_name),
+ family);
+
+ family->family_name = family_name;
+ family_name = NULL;
+ }
+
+ if (family_name)
+ g_free (family_name);
+
+ /* We assume that all faces in the family are monospaced or none. */
+ dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
+ number = (CFNumberRef)CFDictionaryGetValue (dict,
+ kCTFontSymbolicTrait);
+
+ if (CFNumberGetValue (number, kCFNumberIntType, &font_traits))
+ {
+ if (font_traits & kCTFontMonoSpaceTrait)
+ family->is_monospace = TRUE;
+ }
+
+ CFRelease (dict);
+ }
+
+ /* Insert aliases */
+ family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
+ family->family_name = g_strdup ("Sans");
+ g_hash_table_insert (ctfontmap->families,
+ g_utf8_casefold (family->family_name, -1), family);
+
+ family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
+ family->family_name = g_strdup ("Serif");
+ g_hash_table_insert (ctfontmap->families,
+ g_utf8_casefold (family->family_name, -1), family);
+
+ family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
+ family->family_name = g_strdup ("Monospace");
+ family->is_monospace = TRUE;
+ g_hash_table_insert (ctfontmap->families,
+ g_utf8_casefold (family->family_name, -1), family);
+}
+
+static void
+pango_core_text_font_map_class_init (PangoCoreTextFontMapClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+ PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (class);
+
+ object_class->finalize = pango_core_text_font_map_finalize;
+
+ fontmap_class->load_font = pango_core_text_font_map_load_font;
+ fontmap_class->list_families = pango_core_text_font_map_list_families;
+ fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_CORE_TEXT;
+}