Upload tizen 2.0 beta source
[external/pango1.0.git] / pango / pangoatsui-fontmap.c
1 /* Pango
2  * pangoatsui-fontmap.c
3  *
4  * Copyright (C) 2000-2003 Red Hat, Inc.
5  * Copyright (C) 2005-2007 Imendio AB
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include "config.h"
24
25 #include "pango-fontmap.h"
26 #include "pangoatsui-private.h"
27 #include "pango-impl-utils.h"
28 #include "modules.h"
29
30 #import <Cocoa/Cocoa.h>
31
32 typedef struct _FontHashKey      FontHashKey;
33
34 struct _PangoATSUIFamily
35 {
36   PangoFontFamily parent_instance;
37
38   char *family_name;
39
40   guint is_monospace : 1;
41
42   PangoFontFace **faces;
43   gint n_faces;
44 };
45
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))
49
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))
53
54 struct _PangoATSUIFace
55 {
56   PangoFontFace parent_instance;
57
58   PangoATSUIFamily *family;
59
60   PangoCoverage *coverage;
61
62   char *postscript_name;
63   char *style_name;
64
65   int weight;
66   int traits;
67   guint synthetic_italic : 1;
68 };
69
70 static GType pango_atsui_family_get_type (void);
71 static GType pango_atsui_face_get_type (void);
72
73 static gpointer pango_atsui_family_parent_class;
74 static gpointer pango_atsui_face_parent_class;
75
76 static const char *
77 get_real_family (const char *family_name)
78 {
79   switch (family_name[0])
80     {
81     case 'm':
82     case 'M':
83       if (g_ascii_strcasecmp (family_name, "monospace") == 0)
84         return "Courier";
85       break;
86     case 's':
87     case 'S':
88       if (g_ascii_strcasecmp (family_name, "sans") == 0)
89         return "Helvetica";
90       else if (g_ascii_strcasecmp (family_name, "serif") == 0)
91         return "Times";
92       break;
93     }
94
95   return family_name;
96 }
97
98 static void
99 pango_atsui_family_list_faces (PangoFontFamily  *family,
100                                PangoFontFace  ***faces,
101                                int              *n_faces)
102 {
103   PangoATSUIFamily *atsuifamily = PANGO_ATSUI_FAMILY (family);
104
105   if (atsuifamily->n_faces < 0)
106     {
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]];
111       int i, count;
112       GHashTable *hash_table;
113       GList *faces = NULL, *l;
114       GList *synthetic_faces = NULL;
115
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.
123        */
124       hash_table = g_hash_table_new (g_direct_hash, g_direct_equal);
125
126       count = [members count];
127       for (i = 0; i < count; i++)
128         {
129           PangoATSUIFace *face = g_object_new (PANGO_TYPE_ATSUI_FACE, NULL);
130           NSArray *font_array = [members objectAtIndex:i];
131
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];
137
138           faces = g_list_prepend (faces, face);
139
140           if (face->traits & NSItalicFontMask)
141             g_hash_table_insert (hash_table, GINT_TO_POINTER (face->weight), face);
142         }
143
144       for (l = faces; l; l = l->next)
145         {
146           PangoATSUIFace *face = l->data;
147
148           if (!g_hash_table_lookup (hash_table, GINT_TO_POINTER (face->weight)))
149             {
150               PangoATSUIFace *italic_face = g_object_new (PANGO_TYPE_ATSUI_FACE, NULL);
151
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;
157
158               /* Try to create a sensible face name. */
159               if (strcasecmp (face->style_name, "regular") == 0)
160                 italic_face->style_name = g_strdup ("Oblique");
161               else 
162                 italic_face->style_name = g_strdup_printf ("%s Oblique", face->style_name);
163
164               synthetic_faces = g_list_prepend (synthetic_faces, italic_face);
165             }
166         }
167
168       faces = g_list_concat (faces, synthetic_faces);
169
170       atsuifamily->n_faces = g_list_length (faces);
171       atsuifamily->faces = g_new (PangoFontFace *, atsuifamily->n_faces);
172
173       for (l = faces, i = 0; l; l = l->next, i++)
174         atsuifamily->faces[i] = l->data;
175
176       g_list_free (faces);
177       g_hash_table_destroy (hash_table);
178
179       [pool release];
180     }
181
182   if (n_faces)
183     *n_faces = atsuifamily->n_faces;
184
185   if (faces)
186     *faces = g_memdup (atsuifamily->faces, atsuifamily->n_faces * sizeof (PangoFontFace *));
187 }
188
189 static const char *
190 pango_atsui_family_get_name (PangoFontFamily *family)
191
192 {
193   PangoATSUIFamily *atsuifamily = PANGO_ATSUI_FAMILY (family);
194
195   return atsuifamily->family_name;
196 }
197
198 static gboolean
199 pango_atsui_family_is_monospace (PangoFontFamily *family)
200 {
201   PangoATSUIFamily *atsuifamily = PANGO_ATSUI_FAMILY (family);
202
203   return atsuifamily->is_monospace;
204 }
205
206 static void
207 pango_atsui_family_finalize (GObject *object)
208 {
209   PangoATSUIFamily *family = PANGO_ATSUI_FAMILY (object);
210   int i;
211
212   g_free (family->family_name);
213
214   if (family->n_faces != -1)
215     {
216       for (i = 0; i < family->n_faces; i++)
217         g_object_unref (family->faces[i]);
218
219       g_free (family->faces);
220     }
221
222   G_OBJECT_CLASS (pango_atsui_family_parent_class)->finalize (object);
223 }
224
225 static void
226 pango_atsui_family_class_init (PangoFontFamilyClass *class)
227 {
228   GObjectClass *object_class = (GObjectClass *)class;
229   int i;
230
231   pango_atsui_family_parent_class = g_type_class_peek_parent (class);
232
233   object_class->finalize = pango_atsui_family_finalize;
234
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;
238
239   for (i = 0; _pango_included_atsui_modules[i].list; i++)
240     pango_module_register (&_pango_included_atsui_modules[i]);
241 }
242
243 static void
244 pango_atsui_family_init (PangoATSUIFamily *family)
245 {
246   family->n_faces = -1;
247 }
248
249 static GType
250 pango_atsui_family_get_type (void)
251 {
252   static GType object_type = 0;
253
254   if (G_UNLIKELY (!object_type))
255     {
256       const GTypeInfo object_info =
257       {
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),
265         0,              /* n_preallocs */
266         (GInstanceInitFunc) pango_atsui_family_init,
267       };
268
269       object_type = g_type_register_static (PANGO_TYPE_FONT_FAMILY,
270                                             I_("PangoATSUIFamily"),
271                                             &object_info, 0);
272     }
273
274   return object_type;
275 }
276
277 static PangoFontDescription *
278 pango_atsui_face_describe (PangoFontFace *face)
279 {
280   PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (face);
281   PangoFontDescription *description;
282   PangoWeight pango_weight;
283   PangoStyle pango_style;
284   PangoVariant pango_variant;
285   int weight;
286
287   description = pango_font_description_new ();
288
289   pango_font_description_set_family (description, atsuiface->family->family_name);
290
291   weight = atsuiface->weight;
292
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;
307   else
308     g_assert_not_reached ();
309
310   if (atsuiface->traits & NSItalicFontMask)
311     pango_style = PANGO_STYLE_ITALIC;
312   else
313     pango_style = PANGO_STYLE_NORMAL;
314
315   if (atsuiface->traits & NSSmallCapsFontMask)
316     pango_variant = PANGO_VARIANT_SMALL_CAPS;
317   else
318     pango_variant = PANGO_VARIANT_NORMAL;
319
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);
323
324   return description;
325 }
326
327 static const char *
328 pango_atsui_face_get_face_name (PangoFontFace *face)
329 {
330   PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (face);
331
332   return atsuiface->style_name;
333 }
334
335 static void
336 pango_atsui_face_list_sizes (PangoFontFace  *face,
337                              int           **sizes,
338                              int            *n_sizes)
339 {
340   *n_sizes = 0;
341   *sizes = NULL;
342 }
343
344 static void
345 pango_atsui_face_finalize (GObject *object)
346 {
347   PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (object);
348
349   if (atsuiface->coverage)
350     pango_coverage_unref (atsuiface->coverage);
351
352   g_free (atsuiface->postscript_name);
353   g_free (atsuiface->style_name);
354
355   G_OBJECT_CLASS (pango_atsui_face_parent_class)->finalize (object);
356 }
357
358 static gboolean
359 pango_atsui_face_is_synthesized (PangoFontFace *face)
360 {
361   PangoATSUIFace *atsuiface = PANGO_ATSUI_FACE (face);
362
363   return atsuiface->synthetic_italic;
364 }
365
366 static void
367 pango_atsui_face_class_init (PangoFontFaceClass *class)
368 {
369   GObjectClass *object_class = (GObjectClass *)class;
370
371   pango_atsui_face_parent_class = g_type_class_peek_parent (class);
372
373   object_class->finalize = pango_atsui_face_finalize;
374
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;
379 }
380
381 GType
382 pango_atsui_face_get_type (void)
383 {
384   static GType object_type = 0;
385
386   if (G_UNLIKELY (!object_type))
387     {
388       const GTypeInfo object_info =
389       {
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),
397         0,              /* n_preallocs */
398         (GInstanceInitFunc) NULL,
399       };
400
401       object_type = g_type_register_static (PANGO_TYPE_FONT_FACE,
402                                             I_("PangoATSUIFace"),
403                                             &object_info, 0);
404     }
405
406   return object_type;
407 }
408
409 const char *
410 _pango_atsui_face_get_postscript_name (PangoATSUIFace *face)
411 {
412   return face->postscript_name;
413 }
414
415 gboolean
416 _pango_atsui_face_get_synthetic_italic (PangoATSUIFace *face)
417 {
418   return face->synthetic_italic;
419 }
420
421 PangoCoverage *
422 _pango_atsui_face_get_coverage (PangoATSUIFace *face,
423                                 PangoLanguage  *language)
424 {
425   int i;
426
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.
430    */
431
432   if (face->coverage)
433     return face->coverage;
434
435   face->coverage = pango_coverage_new ();
436
437   for (i = 0; i < 256; i++)
438     pango_coverage_set (face->coverage, i, PANGO_COVERAGE_EXACT);
439
440   return face->coverage;
441 }
442
443 static void pango_atsui_font_map_class_init (PangoATSUIFontMapClass *class);
444 static void pango_atsui_font_map_init (PangoATSUIFontMap *atsuifontmap);
445
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);
450
451 G_DEFINE_TYPE (PangoATSUIFontMap, pango_atsui_font_map, PANGO_TYPE_FONT_MAP);
452
453 static void
454 pango_atsui_font_map_finalize (GObject *object)
455 {
456   PangoATSUIFontMap *fontmap = PANGO_ATSUI_FONT_MAP (object);
457
458   g_hash_table_destroy (fontmap->font_hash);
459   g_hash_table_destroy (fontmap->families);
460
461   G_OBJECT_CLASS (pango_atsui_font_map_parent_class)->finalize (object);
462 }
463
464 struct _FontHashKey {
465   PangoATSUIFontMap *fontmap;
466   PangoMatrix matrix;
467   PangoFontDescription *desc;
468   char *postscript_name;
469   gpointer context_key;
470 };
471
472 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
473  *
474  * Not necessarily better than a lot of other hashes, but should be OK, and
475  * well tested with binary data.
476  */
477
478 #define FNV_32_PRIME ((guint32)0x01000193)
479 #define FNV1_32_INIT ((guint32)0x811c9dc5)
480
481 static guint32
482 hash_bytes_fnv (unsigned char *buffer,
483                 int            len,
484                 guint32        hval)
485 {
486   while (len--)
487     {
488       hval *= FNV_32_PRIME;
489       hval ^= *buffer++;
490     }
491
492   return hval;
493 }
494
495 static gboolean
496 font_hash_key_equal (const FontHashKey *key_a,
497                      const FontHashKey *key_b)
498 {
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)
505     {
506       if (key_a->context_key)
507         return PANGO_ATSUI_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
508                                                                                 key_a->context_key,
509                                                                                 key_b->context_key);
510       else
511         return TRUE;
512     }
513   else
514     return FALSE;
515 }
516
517 static guint
518 font_hash_key_hash (const FontHashKey *key)
519 {
520     guint32 hash = FNV1_32_INIT;
521
522     /* We do a bytewise hash on the context matrix */
523     hash = hash_bytes_fnv ((unsigned char *)(&key->matrix),
524                            sizeof(double) * 4,
525                            hash);
526
527     if (key->context_key)
528       hash ^= PANGO_ATSUI_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
529                                                                                key->context_key);
530
531     hash ^= g_str_hash (key->postscript_name);
532
533     return (hash ^ pango_font_description_hash (key->desc));
534 }
535
536 static void
537 font_hash_key_free (FontHashKey *key)
538 {
539   if (key->context_key)
540     PANGO_ATSUI_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
541                                                                      key->context_key);
542
543   g_slice_free (FontHashKey, key);
544 }
545
546 static FontHashKey *
547 font_hash_key_copy (FontHashKey *old)
548 {
549   FontHashKey *key = g_slice_new (FontHashKey);
550
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,
557                                                                                         old->context_key);
558   else
559     key->context_key = NULL;
560
561   return key;
562 }
563
564
565 static void
566 get_context_matrix (PangoContext *context,
567                     PangoMatrix *matrix)
568 {
569   const PangoMatrix *set_matrix;
570   static const PangoMatrix identity = PANGO_MATRIX_INIT;
571
572   if (context)
573     set_matrix = pango_context_get_matrix (context);
574   else
575     set_matrix = NULL;
576
577   if (set_matrix)
578     *matrix = *set_matrix;
579   else
580     *matrix = identity;
581 }
582
583 static void
584 font_hash_key_for_context (PangoATSUIFontMap *fcfontmap,
585                            PangoContext   *context,
586                            FontHashKey    *key)
587 {
588   key->fontmap = fcfontmap;
589   get_context_matrix (context, &key->matrix);
590
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);
593   else
594     key->context_key = NULL;
595 }
596
597 static void
598 pango_atsui_font_map_add (PangoATSUIFontMap *atsuifontmap,
599                           PangoContext      *context,
600                           PangoATSUIFont    *atsuifont)
601 {
602   FontHashKey key;
603   FontHashKey *key_copy;
604   PangoATSUIFace *face;
605
606   _pango_atsui_font_set_font_map (atsuifont, atsuifontmap);
607
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);
612
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));
616 }
617
618 static PangoATSUIFont *
619 pango_atsui_font_map_lookup (PangoATSUIFontMap    *atsuifontmap,
620                              PangoContext         *context,
621                              PangoFontDescription *desc,
622                              PangoATSUIFace       *face)
623 {
624   FontHashKey key;
625
626   font_hash_key_for_context (atsuifontmap, context, &key);
627   key.postscript_name = (char *)_pango_atsui_face_get_postscript_name (face);
628   key.desc = desc;
629
630   return g_hash_table_lookup (atsuifontmap->font_hash, &key);
631 }
632
633 static gboolean
634 find_best_match (PangoATSUIFamily            *font_family,
635                  const PangoFontDescription  *description,
636                  PangoFontDescription       **best_description,
637                  PangoATSUIFace             **best_face)
638 {
639   PangoFontDescription *new_desc;
640   int i;
641
642   *best_description = NULL;
643   *best_face = NULL;
644
645   for (i = 0; i < font_family->n_faces; i++)
646     {
647       new_desc = pango_font_face_describe (font_family->faces[i]);
648
649       if (pango_font_description_better_match (description, *best_description, new_desc))
650         {
651           pango_font_description_free (*best_description);
652           *best_description = new_desc;
653           *best_face = (PangoATSUIFace *)font_family->faces[i];
654         }
655       else
656         pango_font_description_free (new_desc);
657     }
658
659   if (*best_description)
660     return TRUE;
661
662   return FALSE;
663 }
664
665 static PangoFont *
666 pango_atsui_font_map_load_font (PangoFontMap               *fontmap,
667                                 PangoContext               *context,
668                                 const PangoFontDescription *description)
669 {
670   PangoATSUIFontMap *atsuifontmap = (PangoATSUIFontMap *)fontmap;
671   PangoATSUIFamily *font_family;
672   const gchar *family;
673   gchar *name;
674   gint size;
675
676   size = pango_font_description_get_size (description);
677   if (size < 0)
678     return NULL;
679
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);
684   g_free (name);
685
686   if (font_family)
687     {
688       PangoFontDescription *best_description;
689       PangoATSUIFace *best_face;
690       PangoATSUIFont *best_font;
691
692       /* Force a listing of the available faces */
693       pango_font_family_list_faces ((PangoFontFamily *)font_family, NULL, NULL);
694
695       if (!find_best_match (font_family, description, &best_description, &best_face))
696         return NULL;
697       
698       pango_font_description_set_size (best_description, size);
699
700       best_font = pango_atsui_font_map_lookup (atsuifontmap, 
701                                                context, 
702                                                best_description, 
703                                                best_face);
704
705       if (best_font)
706         g_object_ref (best_font);
707       else
708         {
709           PangoATSUIFontMapClass *klass;
710
711           klass = PANGO_ATSUI_FONT_MAP_GET_CLASS (atsuifontmap);
712           best_font = klass->create_font (atsuifontmap, context, 
713                                           best_face, best_description);
714           
715           if (best_font)
716             pango_atsui_font_map_add (atsuifontmap, context, best_font);
717             /* TODO: Handle the else case here. */
718         }
719
720       pango_font_description_free (best_description);
721
722       return (PangoFont *)best_font;
723     }
724
725   return NULL;
726 }
727
728 static void
729 list_families_foreach (gpointer key,
730                        gpointer value,
731                        gpointer user_data)
732 {
733   GSList **list = user_data;
734
735   *list = g_slist_prepend (*list, value);
736 }
737
738 static void
739 pango_atsui_font_map_list_families (PangoFontMap      *fontmap,
740                                     PangoFontFamily ***families,
741                                     int               *n_families)
742 {
743   GSList *family_list = NULL;
744   GSList *tmp_list;
745   PangoATSUIFontMap *atsuifontmap = (PangoATSUIFontMap *)fontmap;
746
747   if (!n_families)
748     return;
749
750   g_hash_table_foreach (atsuifontmap->families, list_families_foreach, &family_list);
751
752   *n_families = g_slist_length (family_list);
753
754   if (families)
755     {
756       int i = 0;
757
758       *families = g_new (PangoFontFamily *, *n_families);
759
760       tmp_list = family_list;
761       while (tmp_list)
762         {
763           (*families)[i] = tmp_list->data;
764           i++;
765           tmp_list = tmp_list->next;
766         }
767     }
768
769   g_slist_free (family_list);
770 }
771
772 static void
773 pango_atsui_font_map_init (PangoATSUIFontMap *atsuifontmap)
774 {
775   NSAutoreleasePool *pool;
776   NSFontManager *manager;
777   NSArray *family_array;
778   PangoATSUIFamily *family;
779   int size, i;
780
781   atsuifontmap->families = g_hash_table_new_full (g_str_hash, g_str_equal,
782                                                   g_free, g_object_unref);
783
784
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,
788                                                    NULL);
789
790   pool = [[NSAutoreleasePool alloc] init];
791   manager = [NSFontManager sharedFontManager];
792   family_array = [manager availableFontFamilies];
793   size = [family_array count];
794
795   for (i = 0; i < size; i++)
796     {
797       NSString *family_name = [family_array objectAtIndex:i];
798       NSArray *members;
799
800       family = g_object_new (PANGO_TYPE_ATSUI_FAMILY, NULL);
801       family->family_name = g_strdup ([family_name UTF8String]);
802   
803       members = [manager availableMembersOfFontFamily:family_name];
804       if ([members count] > 0)
805         {
806           NSArray *font_array = [members objectAtIndex:0];
807
808           /* We assume that all faces in the family are monospaced, or
809            * none.
810            */
811           if ([[font_array objectAtIndex:3] intValue] & NSFixedPitchFontMask)
812             family->is_monospace = TRUE;
813         }
814
815       g_hash_table_insert (atsuifontmap->families, g_utf8_casefold (family->family_name, -1), family);
816     }
817
818   /* Insert aliases */
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);
822
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);
826
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);
831
832   [pool release];
833 }
834
835 static void
836 pango_atsui_font_map_class_init (PangoATSUIFontMapClass *class)
837 {
838   GObjectClass *object_class = G_OBJECT_CLASS (class);
839   PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (class);
840
841   object_class->finalize = pango_atsui_font_map_finalize;
842
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;
846 }
847
848