4 * Copyright (C) 2000-2003 Red Hat, Inc.
5 * Copyright (C) 2005-2007 Imendio AB
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
25 #include "pango-fontmap.h"
26 #include "pangoatsui-private.h"
27 #include "pango-impl-utils.h"
30 #import <Cocoa/Cocoa.h>
32 typedef struct _FontHashKey FontHashKey;
34 struct _PangoATSUIFamily
36 PangoFontFamily parent_instance;
40 guint is_monospace : 1;
42 PangoFontFace **faces;
46 #define PANGO_TYPE_ATSUI_FAMILY (pango_atsui_family_get_type ())
47 #define PANGO_ATSUI_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_ATSUI_FAMILY, PangoATSUIFamily))
48 #define PANGO_IS_ATSUI_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_ATSUI_FAMILY))
50 #define PANGO_TYPE_ATSUI_FACE (pango_atsui_face_get_type ())
51 #define PANGO_ATSUI_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_ATSUI_FACE, PangoATSUIFace))
52 #define PANGO_IS_ATSUI_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_ATSUI_FACE))
54 struct _PangoATSUIFace
56 PangoFontFace parent_instance;
58 PangoATSUIFamily *family;
60 PangoCoverage *coverage;
62 char *postscript_name;
67 guint synthetic_italic : 1;
70 static GType pango_atsui_family_get_type (void);
71 static GType pango_atsui_face_get_type (void);
73 static gpointer pango_atsui_family_parent_class;
74 static gpointer pango_atsui_face_parent_class;
77 get_real_family (const char *family_name)
79 switch (family_name[0])
83 if (g_ascii_strcasecmp (family_name, "monospace") == 0)
88 if (g_ascii_strcasecmp (family_name, "sans") == 0)
90 else if (g_ascii_strcasecmp (family_name, "serif") == 0)
99 pango_atsui_family_list_faces (PangoFontFamily *family,
100 PangoFontFace ***faces,
103 PangoATSUIFamily *atsuifamily = PANGO_ATSUI_FAMILY (family);
105 if (atsuifamily->n_faces < 0)
107 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
108 const char *real_family = get_real_family (atsuifamily->family_name);
109 NSFontManager *manager = [NSFontManager sharedFontManager];
110 NSArray *members = [manager availableMembersOfFontFamily:[NSString stringWithUTF8String:real_family]];
112 GHashTable *hash_table;
113 GList *faces = NULL, *l;
114 GList *synthetic_faces = NULL;
116 /* The NSFontManager API returns italic faces for some families
117 * even if they don't exist. When using Cocoa to create
118 * instances of those fonts, Cocoa synthesizes italic versions
119 * by applying a shear transformation. We do that manually for
120 * those fonts in pangocairo-atsuifont.c. For many other fonts,
121 * there is no italic face at all, so we create synthesized
122 * versions of those like in the win32 and fontconfig backends.
124 hash_table = g_hash_table_new (g_direct_hash, g_direct_equal);
126 count = [members count];
127 for (i = 0; i < count; i++)
129 PangoATSUIFace *face = g_object_new (PANGO_TYPE_ATSUI_FACE, NULL);
130 NSArray *font_array = [members objectAtIndex:i];
132 face->family = atsuifamily;
133 face->postscript_name = g_strdup ([[font_array objectAtIndex:0] UTF8String]);
134 face->style_name = g_strdup ([[font_array objectAtIndex:1] UTF8String]);
135 face->weight = [[font_array objectAtIndex:2] intValue];
136 face->traits = [[font_array objectAtIndex:3] intValue];
138 faces = g_list_prepend (faces, face);
140 if (face->traits & NSItalicFontMask)
141 g_hash_table_insert (hash_table, GINT_TO_POINTER (face->weight), face);
144 for (l = faces; l; l = l->next)
146 PangoATSUIFace *face = l->data;
148 if (!g_hash_table_lookup (hash_table, GINT_TO_POINTER (face->weight)))
150 PangoATSUIFace *italic_face = g_object_new (PANGO_TYPE_ATSUI_FACE, NULL);
152 italic_face->family = atsuifamily;
153 italic_face->postscript_name = g_strdup (face->postscript_name);
154 italic_face->weight = face->weight;
155 italic_face->traits = face->traits | NSItalicFontMask;
156 italic_face->synthetic_italic = TRUE;
158 /* Try to create a sensible face name. */
159 if (strcasecmp (face->style_name, "regular") == 0)
160 italic_face->style_name = g_strdup ("Oblique");
162 italic_face->style_name = g_strdup_printf ("%s Oblique", face->style_name);
164 synthetic_faces = g_list_prepend (synthetic_faces, italic_face);
168 faces = g_list_concat (faces, synthetic_faces);
170 atsuifamily->n_faces = g_list_length (faces);
171 atsuifamily->faces = g_new (PangoFontFace *, atsuifamily->n_faces);
173 for (l = faces, i = 0; l; l = l->next, i++)
174 atsuifamily->faces[i] = l->data;
177 g_hash_table_destroy (hash_table);
183 *n_faces = atsuifamily->n_faces;
186 *faces = g_memdup (atsuifamily->faces, atsuifamily->n_faces * sizeof (PangoFontFace *));
190 pango_atsui_family_get_name (PangoFontFamily *family)
193 PangoATSUIFamily *atsuifamily = PANGO_ATSUI_FAMILY (family);
195 return atsuifamily->family_name;
199 pango_atsui_family_is_monospace (PangoFontFamily *family)
201 PangoATSUIFamily *atsuifamily = PANGO_ATSUI_FAMILY (family);
203 return atsuifamily->is_monospace;
207 pango_atsui_family_finalize (GObject *object)
209 PangoATSUIFamily *family = PANGO_ATSUI_FAMILY (object);
212 g_free (family->family_name);
214 if (family->n_faces != -1)
216 for (i = 0; i < family->n_faces; i++)
217 g_object_unref (family->faces[i]);
219 g_free (family->faces);
222 G_OBJECT_CLASS (pango_atsui_family_parent_class)->finalize (object);
226 pango_atsui_family_class_init (PangoFontFamilyClass *class)
228 GObjectClass *object_class = (GObjectClass *)class;
231 pango_atsui_family_parent_class = g_type_class_peek_parent (class);
233 object_class->finalize = pango_atsui_family_finalize;
235 class->list_faces = pango_atsui_family_list_faces;
236 class->get_name = pango_atsui_family_get_name;
237 class->is_monospace = pango_atsui_family_is_monospace;
239 for (i = 0; _pango_included_atsui_modules[i].list; i++)
240 pango_module_register (&_pango_included_atsui_modules[i]);
244 pango_atsui_family_init (PangoATSUIFamily *family)
246 family->n_faces = -1;
250 pango_atsui_family_get_type (void)
252 static GType object_type = 0;
254 if (G_UNLIKELY (!object_type))
256 const GTypeInfo object_info =
258 sizeof (PangoFontFamilyClass),
259 (GBaseInitFunc) NULL,
260 (GBaseFinalizeFunc) NULL,
261 (GClassInitFunc) pango_atsui_family_class_init,
262 NULL, /* class_finalize */
263 NULL, /* class_data */
264 sizeof (PangoATSUIFamily),
266 (GInstanceInitFunc) pango_atsui_family_init,
269 object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY,
270 I_("PangoATSUIFamily"),
277 static PangoFontDescription *
278 pango_atsui_face_describe (PangoFontFace *face)
280 PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (face);
281 PangoFontDescription *description;
282 PangoWeight pango_weight;
283 PangoStyle pango_style;
284 PangoVariant pango_variant;
287 description = pango_font_description_new ();
289 pango_font_description_set_family (description, atsuiface->family->family_name);
291 weight = atsuiface->weight;
293 if (weight == 1 || weight == 2)
294 pango_weight = PANGO_WEIGHT_ULTRALIGHT;
295 else if (weight == 3 || weight == 4)
296 pango_weight = PANGO_WEIGHT_LIGHT;
297 else if (weight == 5 || weight == 6)
298 pango_weight = PANGO_WEIGHT_NORMAL;
299 else if (weight == 7 || weight == 8)
300 pango_weight = PANGO_WEIGHT_SEMIBOLD;
301 else if (weight == 9 || weight == 10)
302 pango_weight = PANGO_WEIGHT_BOLD;
303 else if (weight == 11 || weight == 12)
304 pango_weight = PANGO_WEIGHT_ULTRABOLD;
305 else if (weight == 13 || weight == 14)
306 pango_weight = PANGO_WEIGHT_HEAVY;
308 g_assert_not_reached ();
310 if (atsuiface->traits & NSItalicFontMask)
311 pango_style = PANGO_STYLE_ITALIC;
313 pango_style = PANGO_STYLE_NORMAL;
315 if (atsuiface->traits & NSSmallCapsFontMask)
316 pango_variant = PANGO_VARIANT_SMALL_CAPS;
318 pango_variant = PANGO_VARIANT_NORMAL;
320 pango_font_description_set_weight (description, pango_weight);
321 pango_font_description_set_style (description, pango_style);
322 pango_font_description_set_variant (description, pango_variant);
328 pango_atsui_face_get_face_name (PangoFontFace *face)
330 PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (face);
332 return atsuiface->style_name;
336 pango_atsui_face_list_sizes (PangoFontFace *face,
345 pango_atsui_face_finalize (GObject *object)
347 PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (object);
349 if (atsuiface->coverage)
350 pango_coverage_unref (atsuiface->coverage);
352 g_free (atsuiface->postscript_name);
353 g_free (atsuiface->style_name);
355 G_OBJECT_CLASS (pango_atsui_face_parent_class)->finalize (object);
359 pango_atsui_face_is_synthesized (PangoFontFace *face)
361 PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (face);
363 return atsuiface->synthetic_italic;
367 pango_atsui_face_class_init (PangoFontFaceClass *class)
369 GObjectClass *object_class = (GObjectClass *)class;
371 pango_atsui_face_parent_class = g_type_class_peek_parent (class);
373 object_class->finalize = pango_atsui_face_finalize;
375 class->describe = pango_atsui_face_describe;
376 class->get_face_name = pango_atsui_face_get_face_name;
377 class->list_sizes = pango_atsui_face_list_sizes;
378 class->is_synthesized = pango_atsui_face_is_synthesized;
382 pango_atsui_face_get_type (void)
384 static GType object_type = 0;
386 if (G_UNLIKELY (!object_type))
388 const GTypeInfo object_info =
390 sizeof (PangoFontFaceClass),
391 (GBaseInitFunc) NULL,
392 (GBaseFinalizeFunc) NULL,
393 (GClassInitFunc) pango_atsui_face_class_init,
394 NULL, /* class_finalize */
395 NULL, /* class_data */
396 sizeof (PangoATSUIFace),
398 (GInstanceInitFunc) NULL,
401 object_type = g_type_register_static (PANGO_TYPE_FONT_FACE,
402 I_("PangoATSUIFace"),
410 _pango_atsui_face_get_postscript_name (PangoATSUIFace *face)
412 return face->postscript_name;
416 _pango_atsui_face_get_synthetic_italic (PangoATSUIFace *face)
418 return face->synthetic_italic;
422 _pango_atsui_face_get_coverage (PangoATSUIFace *face,
423 PangoLanguage *language)
427 /* Note: We currently fake the coverage by reporting that the 255 first
428 * glyphs exist in all fonts, which is not true. It's unclear how to get
429 * this done correctly.
433 return face->coverage;
435 face->coverage = pango_coverage_new ();
437 for (i = 0; i < 256; i++)
438 pango_coverage_set (face->coverage, i, PANGO_COVERAGE_EXACT);
440 return face->coverage;
443 static void pango_atsui_font_map_class_init (PangoATSUIFontMapClass *class);
444 static void pango_atsui_font_map_init (PangoATSUIFontMap *atsuifontmap);
446 static guint font_hash_key_hash (const FontHashKey *key);
447 static gboolean font_hash_key_equal (const FontHashKey *key_a,
448 const FontHashKey *key_b);
449 static void font_hash_key_free (FontHashKey *key);
451 G_DEFINE_TYPE (PangoATSUIFontMap, pango_atsui_font_map, PANGO_TYPE_FONT_MAP);
454 pango_atsui_font_map_finalize (GObject *object)
456 PangoATSUIFontMap *fontmap = PANGO_ATSUI_FONT_MAP (object);
458 g_hash_table_destroy (fontmap->font_hash);
459 g_hash_table_destroy (fontmap->families);
461 G_OBJECT_CLASS (pango_atsui_font_map_parent_class)->finalize (object);
464 struct _FontHashKey {
465 PangoATSUIFontMap *fontmap;
467 PangoFontDescription *desc;
468 char *postscript_name;
469 gpointer context_key;
472 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
474 * Not necessarily better than a lot of other hashes, but should be OK, and
475 * well tested with binary data.
478 #define FNV_32_PRIME ((guint32)0x01000193)
479 #define FNV1_32_INIT ((guint32)0x811c9dc5)
482 hash_bytes_fnv (unsigned char *buffer,
488 hval *= FNV_32_PRIME;
496 font_hash_key_equal (const FontHashKey *key_a,
497 const FontHashKey *key_b)
499 if (key_a->matrix.xx == key_b->matrix.xx &&
500 key_a->matrix.xy == key_b->matrix.xy &&
501 key_a->matrix.yx == key_b->matrix.yx &&
502 key_a->matrix.yy == key_b->matrix.yy &&
503 pango_font_description_equal (key_a->desc, key_b->desc) &&
504 strcmp (key_a->postscript_name, key_b->postscript_name) == 0)
506 if (key_a->context_key)
507 return PANGO_ATSUI_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
518 font_hash_key_hash (const FontHashKey *key)
520 guint32 hash = FNV1_32_INIT;
522 /* We do a bytewise hash on the context matrix */
523 hash = hash_bytes_fnv ((unsigned char *)(&key->matrix),
527 if (key->context_key)
528 hash ^= PANGO_ATSUI_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
531 hash ^= g_str_hash (key->postscript_name);
533 return (hash ^ pango_font_description_hash (key->desc));
537 font_hash_key_free (FontHashKey *key)
539 if (key->context_key)
540 PANGO_ATSUI_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
543 g_slice_free (FontHashKey, key);
547 font_hash_key_copy (FontHashKey *old)
549 FontHashKey *key = g_slice_new (FontHashKey);
551 key->fontmap = old->fontmap;
552 key->matrix = old->matrix;
553 key->desc = pango_font_description_copy (old->desc);
554 key->postscript_name = g_strdup (old->postscript_name);
555 if (old->context_key)
556 key->context_key = PANGO_ATSUI_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap,
559 key->context_key = NULL;
566 get_context_matrix (PangoContext *context,
569 const PangoMatrix *set_matrix;
570 static const PangoMatrix identity = PANGO_MATRIX_INIT;
573 set_matrix = pango_context_get_matrix (context);
578 *matrix = *set_matrix;
584 font_hash_key_for_context (PangoATSUIFontMap *fcfontmap,
585 PangoContext *context,
588 key->fontmap = fcfontmap;
589 get_context_matrix (context, &key->matrix);
591 if (PANGO_ATSUI_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get)
592 key->context_key = (gpointer)PANGO_ATSUI_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get (fcfontmap, context);
594 key->context_key = NULL;
598 pango_atsui_font_map_add (PangoATSUIFontMap *atsuifontmap,
599 PangoContext *context,
600 PangoATSUIFont *atsuifont)
603 FontHashKey *key_copy;
604 PangoATSUIFace *face;
606 _pango_atsui_font_set_font_map (atsuifont, atsuifontmap);
608 font_hash_key_for_context (atsuifontmap, context, &key);
609 face = _pango_atsui_font_get_face (atsuifont);
610 key.postscript_name = (char *)_pango_atsui_face_get_postscript_name (face);
611 key.desc = _pango_atsui_font_get_font_description (atsuifont);
613 key_copy = font_hash_key_copy (&key);
614 _pango_atsui_font_set_context_key (atsuifont, key_copy->context_key);
615 g_hash_table_insert (atsuifontmap->font_hash, key_copy, g_object_ref (atsuifont));
618 static PangoATSUIFont *
619 pango_atsui_font_map_lookup (PangoATSUIFontMap *atsuifontmap,
620 PangoContext *context,
621 PangoFontDescription *desc,
622 PangoATSUIFace *face)
626 font_hash_key_for_context (atsuifontmap, context, &key);
627 key.postscript_name = (char *)_pango_atsui_face_get_postscript_name (face);
630 return g_hash_table_lookup (atsuifontmap->font_hash, &key);
634 find_best_match (PangoATSUIFamily *font_family,
635 const PangoFontDescription *description,
636 PangoFontDescription **best_description,
637 PangoATSUIFace **best_face)
639 PangoFontDescription *new_desc;
642 *best_description = NULL;
645 for (i = 0; i < font_family->n_faces; i++)
647 new_desc = pango_font_face_describe (font_family->faces[i]);
649 if (pango_font_description_better_match (description, *best_description, new_desc))
651 pango_font_description_free (*best_description);
652 *best_description = new_desc;
653 *best_face = (PangoATSUIFace *)font_family->faces[i];
656 pango_font_description_free (new_desc);
659 if (*best_description)
666 pango_atsui_font_map_load_font (PangoFontMap *fontmap,
667 PangoContext *context,
668 const PangoFontDescription *description)
670 PangoATSUIFontMap *atsuifontmap = (PangoATSUIFontMap *)fontmap;
671 PangoATSUIFamily *font_family;
676 size = pango_font_description_get_size (description);
680 family = pango_font_description_get_family (description);
681 family = family ? family : "";
682 name = g_utf8_casefold (family, -1);
683 font_family = g_hash_table_lookup (atsuifontmap->families, name);
688 PangoFontDescription *best_description;
689 PangoATSUIFace *best_face;
690 PangoATSUIFont *best_font;
692 /* Force a listing of the available faces */
693 pango_font_family_list_faces ((PangoFontFamily *)font_family, NULL, NULL);
695 if (!find_best_match (font_family, description, &best_description, &best_face))
698 pango_font_description_set_size (best_description, size);
700 best_font = pango_atsui_font_map_lookup (atsuifontmap,
706 g_object_ref (best_font);
709 PangoATSUIFontMapClass *klass;
711 klass = PANGO_ATSUI_FONT_MAP_GET_CLASS (atsuifontmap);
712 best_font = klass->create_font (atsuifontmap, context,
713 best_face, best_description);
716 pango_atsui_font_map_add (atsuifontmap, context, best_font);
717 /* TODO: Handle the else case here. */
720 pango_font_description_free (best_description);
722 return (PangoFont *)best_font;
729 list_families_foreach (gpointer key,
733 GSList **list = user_data;
735 *list = g_slist_prepend (*list, value);
739 pango_atsui_font_map_list_families (PangoFontMap *fontmap,
740 PangoFontFamily ***families,
743 GSList *family_list = NULL;
745 PangoATSUIFontMap *atsuifontmap = (PangoATSUIFontMap *)fontmap;
750 g_hash_table_foreach (atsuifontmap->families, list_families_foreach, &family_list);
752 *n_families = g_slist_length (family_list);
758 *families = g_new (PangoFontFamily *, *n_families);
760 tmp_list = family_list;
763 (*families)[i] = tmp_list->data;
765 tmp_list = tmp_list->next;
769 g_slist_free (family_list);
773 pango_atsui_font_map_init (PangoATSUIFontMap *atsuifontmap)
775 NSAutoreleasePool *pool;
776 NSFontManager *manager;
777 NSArray *family_array;
778 PangoATSUIFamily *family;
781 atsuifontmap->families = g_hash_table_new_full (g_str_hash, g_str_equal,
782 g_free, g_object_unref);
785 atsuifontmap->font_hash = g_hash_table_new_full ((GHashFunc)font_hash_key_hash,
786 (GEqualFunc)font_hash_key_equal,
787 (GDestroyNotify)font_hash_key_free,
790 pool = [[NSAutoreleasePool alloc] init];
791 manager = [NSFontManager sharedFontManager];
792 family_array = [manager availableFontFamilies];
793 size = [family_array count];
795 for (i = 0; i < size; i++)
797 NSString *family_name = [family_array objectAtIndex:i];
800 family = g_object_new (PANGO_TYPE_ATSUI_FAMILY, NULL);
801 family->family_name = g_strdup ([family_name UTF8String]);
803 members = [manager availableMembersOfFontFamily:family_name];
804 if ([members count] > 0)
806 NSArray *font_array = [members objectAtIndex:0];
808 /* We assume that all faces in the family are monospaced, or
811 if ([[font_array objectAtIndex:3] intValue] & NSFixedPitchFontMask)
812 family->is_monospace = TRUE;
815 g_hash_table_insert (atsuifontmap->families, g_utf8_casefold (family->family_name, -1), family);
819 family = g_object_new (PANGO_TYPE_ATSUI_FAMILY, NULL);
820 family->family_name = g_strdup ("Sans");
821 g_hash_table_insert (atsuifontmap->families, g_utf8_casefold (family->family_name, -1), family);
823 family = g_object_new (PANGO_TYPE_ATSUI_FAMILY, NULL);
824 family->family_name = g_strdup ("Serif");
825 g_hash_table_insert (atsuifontmap->families, g_utf8_casefold (family->family_name, -1), family);
827 family = g_object_new (PANGO_TYPE_ATSUI_FAMILY, NULL);
828 family->family_name = g_strdup ("Monospace");
829 family->is_monospace = TRUE;
830 g_hash_table_insert (atsuifontmap->families, g_utf8_casefold (family->family_name, -1), family);
836 pango_atsui_font_map_class_init (PangoATSUIFontMapClass *class)
838 GObjectClass *object_class = G_OBJECT_CLASS (class);
839 PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (class);
841 object_class->finalize = pango_atsui_font_map_finalize;
843 fontmap_class->load_font = pango_atsui_font_map_load_font;
844 fontmap_class->list_families = pango_atsui_font_map_list_families;
845 fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_ATSUI;