Git init
[external/pango1.0.git] / pango / pangofc-fontmap.c
1 /* Pango
2  * pangofc-fontmap.c: Base fontmap type for fontconfig-based backends
3  *
4  * Copyright (C) 2000-2003 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #define FONTSET_CACHE_SIZE 256
23
24 #include "config.h"
25 #include <math.h>
26
27 #include "pango-context.h"
28 #include "pangofc-fontmap.h"
29 #include "pangofc-private.h"
30 #include "pango-impl-utils.h"
31 #include "modules.h"
32 #include "pango-enum-types.h"
33
34
35 /* Overview:
36  *
37  * All programming is a practice in caching data.  PangoFcFontMap is the
38  * major caching container of a Pango system on a Linux desktop.  Here is
39  * a short overview of how it all works.
40  *
41  * In short, Fontconfig search patterns are constructed and a fontset loaded
42  * using them.  Here is how we achieve that:
43  *
44  * - All FcPattern's referenced by any object in the fontmap are uniquified
45  *   and cached in the fontmap.  This both speeds lookups based on patterns
46  *   faster, and saves memory.  This is handled by fontmap->priv->pattern_hash.
47  *   The patterns are cached indefinitely.
48  *
49  * - The results of a FcFontSort() are used to populate fontsets.  However,
50  *   FcFontSort() relies on the search pattern only, which includes the font
51  *   size but not the full font matrix.  The fontset however depends on the
52  *   matrix.  As a result, multiple fontsets may need results of the
53  *   FcFontSort() on the same input pattern (think rotating text).  As such,
54  *   we cache FcFontSort() results in fontmap->priv->patterns_hash which
55  *   is a refcounted structure.  This level of abstraction also allows for
56  *   optimizations like calling FcFontMatch() instead of FcFontSort(), and
57  *   only calling FcFontSort() if any patterns other than the first match
58  *   are needed.  Another possible optimization would be to call FcFontSort()
59  *   without trimming, and do the trimming lazily as we go.  Only pattern sets
60  *   already referenced by a fontset are cached.
61  *
62  * - A number of most-recently-used fontsets are cached and reused when
63  *   needed.  This is achieved using fontmap->priv->fontset_hash and
64  *   fontmap->priv->fontset_cache.
65  *
66  * - All fonts created by any of our fontsets are also cached and reused.
67  *   This is what fontmap->priv->font_hash does.
68  *
69  * - Data that only depends on the font file and face index is cached and
70  *   reused by multiple fonts.  This includes coverage and cmap cache info.
71  *   This is done using fontmap->priv->font_face_data_hash.
72  *
73  * Upon a cache_clear() request, all caches are emptied.  All objects (fonts,
74  * fontsets, faces, families) having a reference from outside will still live
75  * and may reference the fontmap still, but will not be reused by the fontmap.
76  *
77  *
78  * Todo:
79  *
80  * - Make PangoCoverage a GObject and subclass it as PangoFcCoverage which
81  *   will directly use FcCharset. (#569622)
82  *
83  * - Lazy trimming of FcFontSort() results.  Requires fontconfig with
84  *   FcCharSetMerge().
85  */
86
87
88 typedef struct _PangoFcFontFaceData PangoFcFontFaceData;
89 typedef struct _PangoFcFace         PangoFcFace;
90 typedef struct _PangoFcFamily       PangoFcFamily;
91 typedef struct _PangoFcFindFuncInfo PangoFcFindFuncInfo;
92 typedef struct _PangoFcPatterns     PangoFcPatterns;
93 typedef struct _PangoFcFontset      PangoFcFontset;
94
95 #define PANGO_FC_TYPE_FAMILY            (pango_fc_family_get_type ())
96 #define PANGO_FC_FAMILY(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_FC_TYPE_FAMILY, PangoFcFamily))
97 #define PANGO_FC_IS_FAMILY(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_FC_TYPE_FAMILY))
98
99 #define PANGO_FC_TYPE_FACE              (pango_fc_face_get_type ())
100 #define PANGO_FC_FACE(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_FC_TYPE_FACE, PangoFcFace))
101 #define PANGO_FC_IS_FACE(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_FC_TYPE_FACE))
102
103 #define PANGO_FC_TYPE_FONTSET           (pango_fc_fontset_get_type ())
104 #define PANGO_FC_FONTSET(object)        (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_FC_TYPE_FONTSET, PangoFcFontset))
105 #define PANGO_FC_IS_FONTSET(object)     (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_FC_TYPE_FONTSET))
106
107 struct _PangoFcFontMapPrivate
108 {
109   GHashTable *fontset_hash;     /* Maps PangoFcFontsetKey -> PangoFcFontset  */
110   GQueue *fontset_cache;        /* Recently used fontsets */
111
112   GHashTable *font_hash;        /* Maps PangoFcFontKey -> PangoFcFont */
113
114   GHashTable *patterns_hash;    /* Maps FcPattern -> PangoFcPatterns */
115
116   /* pattern_hash is used to make sure we only store one copy of
117    * each identical pattern. (Speeds up lookup).
118    */
119   GHashTable *pattern_hash;
120
121   GHashTable *font_face_data_hash; /* Maps font file name/id -> data */
122
123   /* List of all families availible */
124   PangoFcFamily **families;
125   int n_families;               /* -1 == uninitialized */
126
127   double dpi;
128
129   /* Decoders */
130   GSList *findfuncs;
131
132   guint closed : 1;
133 };
134
135 struct _PangoFcFontFaceData
136 {
137   /* Key */
138   char *filename;
139   int id;            /* needed to handle TTC files with multiple faces */
140
141   /* Data */
142   FcPattern *pattern;   /* Referenced pattern that owns filename */
143   PangoCoverage *coverage;
144   PangoFcCmapCache *cmap_cache;
145 };
146
147 struct _PangoFcFace
148 {
149   PangoFontFace parent_instance;
150
151   PangoFcFamily *family;
152   char *style;
153
154   guint fake : 1;
155 };
156
157 struct _PangoFcFamily
158 {
159   PangoFontFamily parent_instance;
160
161   PangoFcFontMap *fontmap;
162   char *family_name;
163
164   PangoFcFace **faces;
165   int n_faces;          /* -1 == uninitialized */
166
167   int spacing;  /* FC_SPACING */
168 };
169
170 struct _PangoFcFindFuncInfo
171 {
172   PangoFcDecoderFindFunc findfunc;
173   gpointer               user_data;
174   GDestroyNotify         dnotify;
175   gpointer               ddata;
176 };
177
178 static GType    pango_fc_family_get_type     (void);
179 static GType    pango_fc_face_get_type       (void);
180 static GType    pango_fc_fontset_get_type    (void);
181
182 static void          pango_fc_font_map_finalize      (GObject                      *object);
183 static PangoFont *   pango_fc_font_map_load_font     (PangoFontMap                 *fontmap,
184                                                        PangoContext                 *context,
185                                                        const PangoFontDescription   *description);
186 static PangoFontset *pango_fc_font_map_load_fontset  (PangoFontMap                 *fontmap,
187                                                        PangoContext                 *context,
188                                                        const PangoFontDescription   *desc,
189                                                        PangoLanguage                *language);
190 static void          pango_fc_font_map_list_families (PangoFontMap                 *fontmap,
191                                                        PangoFontFamily            ***families,
192                                                        int                          *n_families);
193
194 static double pango_fc_font_map_get_resolution (PangoFcFontMap *fcfontmap,
195                                                 PangoContext   *context);
196 static PangoFont *pango_fc_font_map_new_font   (PangoFcFontMap    *fontmap,
197                                                 PangoFcFontsetKey *fontset_key,
198                                                 FcPattern         *match);
199
200 static guint    pango_fc_font_face_data_hash  (PangoFcFontFaceData *key);
201 static gboolean pango_fc_font_face_data_equal (PangoFcFontFaceData *key1,
202                                                PangoFcFontFaceData *key2);
203
204 static void               pango_fc_fontset_key_init  (PangoFcFontsetKey          *key,
205                                                       PangoFcFontMap             *fcfontmap,
206                                                       PangoContext               *context,
207                                                       const PangoFontDescription *desc,
208                                                       PangoLanguage              *language);
209 static PangoFcFontsetKey *pango_fc_fontset_key_copy  (const PangoFcFontsetKey *key);
210 static void               pango_fc_fontset_key_free  (PangoFcFontsetKey       *key);
211 static guint              pango_fc_fontset_key_hash  (const PangoFcFontsetKey *key);
212 static gboolean           pango_fc_fontset_key_equal (const PangoFcFontsetKey *key_a,
213                                                       const PangoFcFontsetKey *key_b);
214
215 static void               pango_fc_font_key_init     (PangoFcFontKey       *key,
216                                                       PangoFcFontMap       *fcfontmap,
217                                                       PangoFcFontsetKey    *fontset_key,
218                                                       FcPattern            *pattern);
219 static PangoFcFontKey    *pango_fc_font_key_copy     (const PangoFcFontKey *key);
220 static void               pango_fc_font_key_free     (PangoFcFontKey       *key);
221 static guint              pango_fc_font_key_hash     (const PangoFcFontKey *key);
222 static gboolean           pango_fc_font_key_equal    (const PangoFcFontKey *key_a,
223                                                       const PangoFcFontKey *key_b);
224
225 static PangoFcPatterns *pango_fc_patterns_new   (FcPattern       *pat,
226                                                  PangoFcFontMap  *fontmap);
227 static PangoFcPatterns *pango_fc_patterns_ref   (PangoFcPatterns *pats);
228 static void             pango_fc_patterns_unref (PangoFcPatterns *pats);
229 static FcPattern       *pango_fc_patterns_get_pattern      (PangoFcPatterns *pats);
230 static FcPattern       *pango_fc_patterns_get_font_pattern (PangoFcPatterns *pats, int i);
231
232 static FcPattern *uniquify_pattern (PangoFcFontMap *fcfontmap,
233                                     FcPattern      *pattern);
234
235 static gpointer
236 get_gravity_class (void)
237 {
238   static GEnumClass *class = NULL;
239
240   if (G_UNLIKELY (!class))
241     class = g_type_class_ref (PANGO_TYPE_GRAVITY);
242
243   return class;
244 }
245
246 static guint
247 pango_fc_font_face_data_hash (PangoFcFontFaceData *key)
248 {
249   return g_str_hash (key->filename) ^ key->id;
250 }
251
252 static gboolean
253 pango_fc_font_face_data_equal (PangoFcFontFaceData *key1,
254                                PangoFcFontFaceData *key2)
255 {
256   return key1->id == key2->id &&
257          (key1 == key2 || 0 == strcmp (key1->filename, key2->filename));
258 }
259
260 static void
261 pango_fc_font_face_data_free (PangoFcFontFaceData *data)
262 {
263   FcPatternDestroy (data->pattern);
264
265   if (data->coverage)
266     pango_coverage_unref (data->coverage);
267
268   if (data->cmap_cache)
269     _pango_fc_cmap_cache_unref (data->cmap_cache);
270
271   g_slice_free (PangoFcFontFaceData, data);
272 }
273
274 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
275  *
276  * Not necessarily better than a lot of other hashes, but should be OK, and
277  * well tested with binary data.
278  */
279
280 #define FNV_32_PRIME ((guint32)0x01000193)
281 #define FNV1_32_INIT ((guint32)0x811c9dc5)
282
283 static guint32
284 hash_bytes_fnv (unsigned char *buffer,
285                 int            len,
286                 guint32        hval)
287 {
288   while (len--)
289     {
290       hval *= FNV_32_PRIME;
291       hval ^= *buffer++;
292     }
293
294   return hval;
295 }
296
297 static void
298 get_context_matrix (PangoContext *context,
299                     PangoMatrix *matrix)
300 {
301   const PangoMatrix *set_matrix;
302   static const PangoMatrix identity = PANGO_MATRIX_INIT;
303
304   set_matrix = context ? pango_context_get_matrix (context) : NULL;
305   *matrix = set_matrix ? *set_matrix : identity;
306   matrix->x0 = matrix->y0 = 0.;
307 }
308
309 static int
310 get_scaled_size (PangoFcFontMap             *fcfontmap,
311                  PangoContext               *context,
312                  const PangoFontDescription *desc)
313 {
314   double size = pango_font_description_get_size (desc);
315
316   if (!pango_font_description_get_size_is_absolute (desc))
317     {
318       double dpi = pango_fc_font_map_get_resolution (fcfontmap, context);
319
320       size = size * dpi / 72.;
321     }
322
323   return .5 + pango_matrix_get_font_scale_factor (pango_context_get_matrix (context)) * size;
324 }
325
326
327
328 struct _PangoFcFontsetKey {
329   PangoFcFontMap *fontmap;
330   PangoLanguage *language;
331   PangoFontDescription *desc;
332   PangoMatrix matrix;
333   int pixelsize;
334   double resolution;
335   gpointer context_key;
336 };
337
338 struct _PangoFcFontKey {
339   PangoFcFontMap *fontmap;
340   FcPattern *pattern;
341   PangoMatrix matrix;
342   gpointer context_key;
343 };
344
345 static void
346 pango_fc_fontset_key_init (PangoFcFontsetKey          *key,
347                            PangoFcFontMap             *fcfontmap,
348                            PangoContext               *context,
349                            const PangoFontDescription *desc,
350                            PangoLanguage              *language)
351 {
352   if (!language && context)
353     language = pango_context_get_language (context);
354
355   key->fontmap = fcfontmap;
356   get_context_matrix (context, &key->matrix);
357   key->pixelsize = get_scaled_size (fcfontmap, context, desc);
358   key->resolution = pango_fc_font_map_get_resolution (fcfontmap, context);
359   key->language = language;
360   key->desc = pango_font_description_copy_static (desc);
361   pango_font_description_unset_fields (key->desc, PANGO_FONT_MASK_SIZE);
362
363   if (context && PANGO_FC_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get)
364     key->context_key = (gpointer)PANGO_FC_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get (fcfontmap, context);
365   else
366     key->context_key = NULL;
367 }
368
369 static gboolean
370 pango_fc_fontset_key_equal (const PangoFcFontsetKey *key_a,
371                             const PangoFcFontsetKey *key_b)
372 {
373   if (key_a->language == key_b->language &&
374       key_a->pixelsize == key_b->pixelsize &&
375       key_a->resolution == key_b->resolution &&
376       pango_font_description_equal (key_a->desc, key_b->desc) &&
377       0 == memcmp (&key_a->matrix, &key_b->matrix, 4 * sizeof (double)))
378     {
379       if (key_a->context_key)
380         return PANGO_FC_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
381                                                                                 key_a->context_key,
382                                                                                 key_b->context_key);
383       else
384         return key_a->context_key == key_b->context_key;
385     }
386   else
387     return FALSE;
388 }
389
390 static guint
391 pango_fc_fontset_key_hash (const PangoFcFontsetKey *key)
392 {
393     guint32 hash = FNV1_32_INIT;
394
395     /* We do a bytewise hash on the doubles */
396     hash = hash_bytes_fnv ((unsigned char *)(&key->matrix), sizeof (double) * 4, hash);
397     hash = hash_bytes_fnv ((unsigned char *)(&key->resolution), sizeof (double), hash);
398
399     hash ^= key->pixelsize;
400
401     if (key->context_key)
402       hash ^= PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
403                                                                             key->context_key);
404
405     return (hash ^
406             GPOINTER_TO_UINT (key->language) ^
407             pango_font_description_hash (key->desc));
408 }
409
410 static void
411 pango_fc_fontset_key_free (PangoFcFontsetKey *key)
412 {
413   pango_font_description_free (key->desc);
414
415   if (key->context_key)
416     PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
417                                                                   key->context_key);
418
419   g_slice_free (PangoFcFontsetKey, key);
420 }
421
422 static PangoFcFontsetKey *
423 pango_fc_fontset_key_copy (const PangoFcFontsetKey *old)
424 {
425   PangoFcFontsetKey *key = g_slice_new (PangoFcFontsetKey);
426
427   key->fontmap = old->fontmap;
428   key->language = old->language;
429   key->desc = pango_font_description_copy (old->desc);
430   key->matrix = old->matrix;
431   key->pixelsize = old->pixelsize;
432   key->resolution = old->resolution;
433   if (old->context_key)
434     key->context_key = PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap,
435                                                                                      old->context_key);
436   else
437     key->context_key = NULL;
438
439   return key;
440 }
441
442 /**
443  * pango_fc_fontset_key_get_language:
444  * @key: the fontset key
445  *
446  * Gets the language member of @key.
447  *
448  * Returns: the language
449  *
450  * Since: 1.24
451  **/
452 PangoLanguage *
453 pango_fc_fontset_key_get_language (const PangoFcFontsetKey *key)
454 {
455   return key->language;
456 }
457
458 /**
459  * pango_fc_fontset_key_get_description:
460  * @key: the fontset key
461  *
462  * Gets the font description of @key.
463  *
464  * Returns: the font description, which is owned by @key and should not be modified.
465  *
466  * Since: 1.24
467  **/
468 const PangoFontDescription *
469 pango_fc_fontset_key_get_description (const PangoFcFontsetKey *key)
470 {
471   return key->desc;
472 }
473
474 /**
475  * pango_fc_fontset_key_get_matrix:
476  * @key: the fontset key
477  *
478  * Gets the matrix member of @key.
479  *
480  * Returns: the matrix, which is owned by @key and should not be modified.
481  *
482  * Since: 1.24
483  **/
484 const PangoMatrix *
485 pango_fc_fontset_key_get_matrix      (const PangoFcFontsetKey *key)
486 {
487   return &key->matrix;
488 }
489
490 /**
491  * pango_fc_fontset_key_get_absolute_size:
492  * @key: the fontset key
493  *
494  * Gets the absolute font size of @key in Pango units.  This is adjusted
495  * for both resolution and transformation matrix.
496  *
497  * Returns: the pixel size of @key.
498  *
499  * Since: 1.24
500  **/
501 double
502 pango_fc_fontset_key_get_absolute_size   (const PangoFcFontsetKey *key)
503 {
504   return key->pixelsize;
505 }
506
507 /**
508  * pango_fc_fontset_key_get_resolution:
509  * @key: the fontset key
510  *
511  * Gets the resolution of @key
512  *
513  * Returns: the resolution of @key
514  *
515  * Since: 1.24
516  **/
517 double
518 pango_fc_fontset_key_get_resolution  (const PangoFcFontsetKey *key)
519 {
520   return key->resolution;
521 }
522
523 /**
524  * pango_fc_fontset_key_get_context_key:
525  * @key: the font key
526  *
527  * Gets the context key member of @key.
528  *
529  * Returns: the context key, which is owned by @key and should not be modified.
530  *
531  * Since: 1.24
532  **/
533 gpointer
534 pango_fc_fontset_key_get_context_key (const PangoFcFontsetKey *key)
535 {
536   return key->context_key;
537 }
538
539 /*
540  * PangoFcFontKey
541  */
542
543 static gboolean
544 pango_fc_font_key_equal (const PangoFcFontKey *key_a,
545                          const PangoFcFontKey *key_b)
546 {
547   if (key_a->pattern == key_b->pattern &&
548       0 == memcmp (&key_a->matrix, &key_b->matrix, 4 * sizeof (double)))
549     {
550       if (key_a->context_key && key_b->context_key)
551         return PANGO_FC_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
552                                                                                 key_a->context_key,
553                                                                                 key_b->context_key);
554       else
555         return key_a->context_key == key_b->context_key;
556     }
557   else
558     return FALSE;
559 }
560
561 static guint
562 pango_fc_font_key_hash (const PangoFcFontKey *key)
563 {
564     guint32 hash = FNV1_32_INIT;
565
566     /* We do a bytewise hash on the doubles */
567     hash = hash_bytes_fnv ((unsigned char *)(&key->matrix), sizeof (double) * 4, hash);
568
569     if (key->context_key)
570       hash ^= PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
571                                                                             key->context_key);
572
573     return (hash ^ GPOINTER_TO_UINT (key->pattern));
574 }
575
576 static void
577 pango_fc_font_key_free (PangoFcFontKey *key)
578 {
579   if (key->pattern)
580     FcPatternDestroy (key->pattern);
581
582   if (key->context_key)
583     PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
584                                                                   key->context_key);
585
586   g_slice_free (PangoFcFontKey, key);
587 }
588
589 static PangoFcFontKey *
590 pango_fc_font_key_copy (const PangoFcFontKey *old)
591 {
592   PangoFcFontKey *key = g_slice_new (PangoFcFontKey);
593
594   key->fontmap = old->fontmap;
595   FcPatternReference (old->pattern);
596   key->pattern = old->pattern;
597   key->matrix = old->matrix;
598   if (old->context_key)
599     key->context_key = PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap,
600                                                                                      old->context_key);
601   else
602     key->context_key = NULL;
603
604   return key;
605 }
606
607 static void
608 pango_fc_font_key_init (PangoFcFontKey    *key,
609                         PangoFcFontMap    *fcfontmap,
610                         PangoFcFontsetKey *fontset_key,
611                         FcPattern         *pattern)
612 {
613   key->fontmap = fcfontmap;
614   key->pattern = pattern;
615   key->matrix = *pango_fc_fontset_key_get_matrix (fontset_key);
616   key->context_key = pango_fc_fontset_key_get_context_key (fontset_key);
617 }
618
619 /* Public API */
620
621 /**
622  * pango_fc_font_key_get_pattern:
623  * @key: the font key
624  *
625  * Gets the fontconfig pattern member of @key.
626  *
627  * Returns: the pattern, which is owned by @key and should not be modified.
628  *
629  * Since: 1.24
630  **/
631 const FcPattern *
632 pango_fc_font_key_get_pattern (const PangoFcFontKey *key)
633 {
634   return key->pattern;
635 }
636
637 /**
638  * pango_fc_font_key_get_matrix:
639  * @key: the font key
640  *
641  * Gets the matrix member of @key.
642  *
643  * Returns: the matrix, which is owned by @key and should not be modified.
644  *
645  * Since: 1.24
646  **/
647 const PangoMatrix *
648 pango_fc_font_key_get_matrix (const PangoFcFontKey *key)
649 {
650   return &key->matrix;
651 }
652
653 /**
654  * pango_fc_font_key_get_context_key:
655  * @key: the font key
656  *
657  * Gets the context key member of @key.
658  *
659  * Returns: the context key, which is owned by @key and should not be modified.
660  *
661  * Since: 1.24
662  **/
663 gpointer
664 pango_fc_font_key_get_context_key (const PangoFcFontKey *key)
665 {
666   return key->context_key;
667 }
668
669
670 /*
671  * PangoFcPatterns
672  */
673
674 struct _PangoFcPatterns {
675   guint ref_count;
676
677   PangoFcFontMap *fontmap;
678
679   FcPattern *pattern;
680   FcPattern *match;
681   FcFontSet *fontset;
682 };
683
684 static PangoFcPatterns *
685 pango_fc_patterns_new (FcPattern *pat, PangoFcFontMap *fontmap)
686 {
687   PangoFcPatterns *pats;
688
689   pat = uniquify_pattern (fontmap, pat);
690   pats = g_hash_table_lookup (fontmap->priv->patterns_hash, pat);
691   if (pats)
692     return pango_fc_patterns_ref (pats);
693
694   pats = g_slice_new0 (PangoFcPatterns);
695
696   pats->fontmap = fontmap;
697
698   pats->ref_count = 1;
699   FcPatternReference (pat);
700   pats->pattern = pat;
701
702   g_hash_table_insert (fontmap->priv->patterns_hash,
703                        pats->pattern, pats);
704
705   return pats;
706 }
707
708 static PangoFcPatterns *
709 pango_fc_patterns_ref (PangoFcPatterns *pats)
710 {
711   g_return_val_if_fail (pats->ref_count > 0, NULL);
712
713   pats->ref_count++;
714
715   return pats;
716 }
717
718 static void
719 pango_fc_patterns_unref (PangoFcPatterns *pats)
720 {
721   g_return_if_fail (pats->ref_count > 0);
722
723   pats->ref_count--;
724
725   if (pats->ref_count)
726     return;
727
728   /* Only remove from fontmap hash if we are in it.  This is not necessarily
729    * the case after a cache_clear() call. */
730   if (pats->fontmap->priv->patterns_hash &&
731       pats == g_hash_table_lookup (pats->fontmap->priv->patterns_hash, pats->pattern))
732     g_hash_table_remove (pats->fontmap->priv->patterns_hash,
733                          pats->pattern);
734
735   if (pats->pattern)
736     FcPatternDestroy (pats->pattern);
737
738   if (pats->match)
739     FcPatternDestroy (pats->match);
740
741   if (pats->fontset)
742     FcFontSetDestroy (pats->fontset);
743
744   g_slice_free (PangoFcPatterns, pats);
745 }
746
747 static FcPattern *
748 pango_fc_patterns_get_pattern (PangoFcPatterns *pats)
749 {
750   return pats->pattern;
751 }
752
753 static FcPattern *
754 pango_fc_patterns_get_font_pattern (PangoFcPatterns *pats, int i)
755 {
756   if (i == 0)
757     {
758       FcResult result;
759       if (!pats->match && !pats->fontset)
760         {
761           pats->match = FcFontMatch (NULL, pats->pattern, &result);
762         }
763
764       if (pats->match)
765         return pats->match;
766     }
767   else
768     {
769       if (!pats->fontset)
770         {
771           FcResult result;
772           pats->fontset = FcFontSort (NULL, pats->pattern, FcTrue, NULL, &result);
773           if (pats->match)
774             {
775               FcPatternDestroy (pats->match);
776               pats->match = NULL;
777             }
778         }
779     }
780
781   if (pats->fontset && i < pats->fontset->nfont)
782     return pats->fontset->fonts[i];
783   else
784     return NULL;
785 }
786
787
788 /*
789  * PangoFcFontset
790  */
791
792 static void              pango_fc_fontset_finalize     (GObject                 *object);
793 static void              pango_fc_fontset_init         (PangoFcFontset      *fontset);
794 static PangoLanguage *   pango_fc_fontset_get_language (PangoFontset            *fontset);
795 static  PangoFont *      pango_fc_fontset_get_font     (PangoFontset            *fontset,
796                                                         guint                    wc);
797 static void              pango_fc_fontset_foreach      (PangoFontset            *fontset,
798                                                         PangoFontsetForeachFunc  func,
799                                                         gpointer                 data);
800
801 struct _PangoFcFontset
802 {
803   PangoFontset parent_instance;
804
805   PangoFcFontsetKey *key;
806
807   PangoFcPatterns *patterns;
808   int patterns_i;
809
810   GPtrArray *fonts;
811   GPtrArray *coverages;
812
813   GList *cache_link;
814 };
815
816 typedef PangoFontsetClass PangoFcFontsetClass;
817
818 static PangoFontsetClass *fc_fontset_parent_class;      /* Parent class structure for PangoFcFontset */
819
820 static PangoFcFontset *
821 pango_fc_fontset_new (PangoFcFontsetKey *key,
822                       PangoFcPatterns   *patterns)
823 {
824   PangoFcFontset *fontset;
825
826   fontset = g_object_new (PANGO_FC_TYPE_FONTSET, NULL);
827
828   fontset->key = pango_fc_fontset_key_copy (key);
829   fontset->patterns = pango_fc_patterns_ref (patterns);
830
831   return fontset;
832 }
833
834 static PangoFcFontsetKey *
835 pango_fc_fontset_get_key (PangoFcFontset *fontset)
836 {
837   return fontset->key;
838 }
839
840 static PangoFont *
841 pango_fc_fontset_load_next_font (PangoFcFontset *fontset)
842 {
843   FcPattern *pattern, *font_pattern;
844   PangoFont *font;
845
846   pattern = pango_fc_patterns_get_pattern (fontset->patterns),
847   font_pattern = pango_fc_patterns_get_font_pattern (fontset->patterns,
848                                                      fontset->patterns_i++);
849   if (G_UNLIKELY (!font_pattern))
850     return NULL;
851
852   font_pattern = FcFontRenderPrepare (NULL, pattern, font_pattern);
853
854   if (G_UNLIKELY (!font_pattern))
855     return NULL;
856
857 #ifdef FC_PATTERN
858     /* The FC_PATTERN element, which points back to our the original
859      * pattern defeats our hash tables.
860      */
861     FcPatternDel (font_pattern, FC_PATTERN);
862 #endif /* FC_PATTERN */
863
864   font = pango_fc_font_map_new_font (fontset->key->fontmap,
865                                      fontset->key,
866                                      font_pattern);
867
868   FcPatternDestroy (font_pattern);
869
870   return font;
871 }
872
873 static PangoFont *
874 pango_fc_fontset_get_font_at (PangoFcFontset *fontset,
875                               unsigned int i)
876 {
877   while (i >= fontset->fonts->len)
878     {
879       PangoFont *font = pango_fc_fontset_load_next_font (fontset);
880       g_ptr_array_add (fontset->fonts, font);
881       g_ptr_array_add (fontset->coverages, NULL);
882       if (!font)
883         return NULL;
884     }
885
886   return g_ptr_array_index (fontset->fonts, i);
887 }
888
889 static void
890 pango_fc_fontset_class_init (PangoFcFontsetClass *class)
891 {
892   GObjectClass *object_class = G_OBJECT_CLASS (class);
893   PangoFontsetClass *fontset_class = PANGO_FONTSET_CLASS (class);
894
895   fc_fontset_parent_class = g_type_class_peek_parent (class);
896
897   object_class->finalize = pango_fc_fontset_finalize;
898   fontset_class->get_font = pango_fc_fontset_get_font;
899   fontset_class->get_language = pango_fc_fontset_get_language;
900   fontset_class->foreach = pango_fc_fontset_foreach;
901 }
902
903 static void
904 pango_fc_fontset_init (PangoFcFontset *fontset)
905 {
906   fontset->fonts = g_ptr_array_new ();
907   fontset->coverages = g_ptr_array_new ();
908 }
909
910 static void
911 pango_fc_fontset_finalize (GObject *object)
912 {
913   PangoFcFontset *fontset = PANGO_FC_FONTSET (object);
914   unsigned int i;
915
916   for (i = 0; i < fontset->fonts->len; i++)
917   {
918     PangoFont *font = g_ptr_array_index(fontset->fonts, i);
919     if (font)
920       g_object_unref (font);
921   }
922   g_ptr_array_free (fontset->fonts, TRUE);
923
924   for (i = 0; i < fontset->coverages->len; i++)
925     {
926       PangoCoverage *coverage = g_ptr_array_index (fontset->coverages, i);
927       if (coverage)
928         pango_coverage_unref (coverage);
929     }
930   g_ptr_array_free (fontset->coverages, TRUE);
931
932   if (fontset->key)
933     pango_fc_fontset_key_free (fontset->key);
934
935   if (fontset->patterns)
936     pango_fc_patterns_unref (fontset->patterns);
937
938   G_OBJECT_CLASS (fc_fontset_parent_class)->finalize (object);
939 }
940
941 static PangoLanguage *
942 pango_fc_fontset_get_language (PangoFontset  *fontset)
943 {
944   PangoFcFontset *fcfontset = PANGO_FC_FONTSET (fontset);
945
946   return pango_fc_fontset_key_get_language (pango_fc_fontset_get_key (fcfontset));
947 }
948
949 static PangoFont *
950 pango_fc_fontset_get_font (PangoFontset  *fontset,
951                            guint          wc)
952 {
953   PangoFcFontset *fcfontset = PANGO_FC_FONTSET (fontset);
954   PangoCoverageLevel best_level = PANGO_COVERAGE_NONE;
955   PangoCoverageLevel level;
956   PangoFont *font;
957   PangoCoverage *coverage;
958   int result = -1;
959   unsigned int i;
960
961   for (i = 0;
962        (font = pango_fc_fontset_get_font_at (fcfontset, i));
963        i++)
964     {
965       coverage = g_ptr_array_index (fcfontset->coverages, i);
966
967       if (coverage == NULL)
968         {
969           font = g_ptr_array_index (fcfontset->fonts, i);
970
971           coverage = pango_font_get_coverage (font, fcfontset->key->language);
972           g_ptr_array_index (fcfontset->coverages, i) = coverage;
973         }
974
975       level = pango_coverage_get (coverage, wc);
976
977       if (result == -1 || level > best_level)
978         {
979           result = i;
980           best_level = level;
981           if (level == PANGO_COVERAGE_EXACT)
982             break;
983         }
984     }
985
986   if (G_UNLIKELY (result == -1))
987     return NULL;
988
989   font = g_ptr_array_index(fcfontset->fonts, result);
990   return g_object_ref (font);
991 }
992
993 static void
994 pango_fc_fontset_foreach (PangoFontset           *fontset,
995                           PangoFontsetForeachFunc func,
996                           gpointer                data)
997 {
998   PangoFcFontset *fcfontset = PANGO_FC_FONTSET (fontset);
999   PangoFont *font;
1000   unsigned int i;
1001
1002   for (i = 0;
1003        (font = pango_fc_fontset_get_font_at (fcfontset, i));
1004        i++)
1005     {
1006       if ((*func) (fontset, font, data))
1007         return;
1008     }
1009 }
1010
1011 static PANGO_DEFINE_TYPE (PangoFcFontset, pango_fc_fontset,
1012                           pango_fc_fontset_class_init, pango_fc_fontset_init,
1013                           PANGO_TYPE_FONTSET)
1014
1015 /*
1016  * PangoFcFontMap
1017  */
1018
1019 G_DEFINE_ABSTRACT_TYPE (PangoFcFontMap, pango_fc_font_map, PANGO_TYPE_FONT_MAP)
1020
1021 static void
1022 pango_fc_font_map_init (PangoFcFontMap *fcfontmap)
1023 {
1024   static gboolean registered_modules = FALSE;
1025   PangoFcFontMapPrivate *priv;
1026
1027   priv = fcfontmap->priv = G_TYPE_INSTANCE_GET_PRIVATE (fcfontmap,
1028                                                         PANGO_TYPE_FC_FONT_MAP,
1029                                                         PangoFcFontMapPrivate);
1030
1031   if (!registered_modules)
1032     {
1033       int i;
1034
1035       registered_modules = TRUE;
1036
1037       for (i = 0; _pango_included_fc_modules[i].list; i++)
1038         pango_module_register (&_pango_included_fc_modules[i]);
1039     }
1040
1041   priv->n_families = -1;
1042
1043   priv->font_hash = g_hash_table_new ((GHashFunc)pango_fc_font_key_hash,
1044                                       (GEqualFunc)pango_fc_font_key_equal);
1045
1046   priv->fontset_hash = g_hash_table_new_full ((GHashFunc)pango_fc_fontset_key_hash,
1047                                               (GEqualFunc)pango_fc_fontset_key_equal,
1048                                               NULL,
1049                                               (GDestroyNotify)g_object_unref);
1050   priv->fontset_cache = g_queue_new ();
1051
1052   priv->patterns_hash = g_hash_table_new (NULL, NULL);
1053
1054   priv->pattern_hash = g_hash_table_new_full ((GHashFunc) FcPatternHash,
1055                                               (GEqualFunc) FcPatternEqual,
1056                                               (GDestroyNotify) FcPatternDestroy,
1057                                               NULL);
1058
1059   priv->font_face_data_hash = g_hash_table_new_full ((GHashFunc)pango_fc_font_face_data_hash,
1060                                                      (GEqualFunc)pango_fc_font_face_data_equal,
1061                                                      (GDestroyNotify)pango_fc_font_face_data_free,
1062                                                      NULL);
1063   priv->dpi = -1;
1064 }
1065
1066 static void
1067 pango_fc_font_map_fini (PangoFcFontMap *fcfontmap)
1068 {
1069   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1070   int i;
1071
1072   g_queue_free (priv->fontset_cache);
1073   priv->fontset_cache = NULL;
1074
1075   g_hash_table_destroy (priv->fontset_hash);
1076   priv->fontset_hash = NULL;
1077
1078   g_hash_table_destroy (priv->patterns_hash);
1079   priv->patterns_hash = NULL;
1080
1081   g_hash_table_destroy (priv->font_hash);
1082   priv->font_hash = NULL;
1083
1084   g_hash_table_destroy (priv->font_face_data_hash);
1085   priv->font_face_data_hash = NULL;
1086
1087   g_hash_table_destroy (priv->pattern_hash);
1088   priv->pattern_hash = NULL;
1089
1090   for (i = 0; i < priv->n_families; i++)
1091     g_object_unref (priv->families[i]);
1092   g_free (priv->families);
1093   priv->n_families = -1;
1094   priv->families = NULL;
1095 }
1096
1097 static void
1098 pango_fc_font_map_class_init (PangoFcFontMapClass *class)
1099 {
1100   GObjectClass *object_class = G_OBJECT_CLASS (class);
1101   PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (class);
1102
1103   object_class->finalize = pango_fc_font_map_finalize;
1104   fontmap_class->load_font = pango_fc_font_map_load_font;
1105   fontmap_class->load_fontset = pango_fc_font_map_load_fontset;
1106   fontmap_class->list_families = pango_fc_font_map_list_families;
1107   fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_FC;
1108
1109   g_type_class_add_private (object_class, sizeof (PangoFcFontMapPrivate));
1110 }
1111
1112
1113 /**
1114  * pango_fc_font_map_add_decoder_find_func:
1115  * @fcfontmap: The #PangoFcFontMap to add this method to.
1116  * @findfunc: The #PangoFcDecoderFindFunc callback function
1117  * @user_data: User data.
1118  * @dnotify: A #GDestroyNotify callback that will be called when the
1119  *  fontmap is finalized and the decoder is released.
1120  *
1121  * This function saves a callback method in the #PangoFcFontMap that
1122  * will be called whenever new fonts are created.  If the
1123  * function returns a #PangoFcDecoder, that decoder will be used to
1124  * determine both coverage via a #FcCharSet and a one-to-one mapping of
1125  * characters to glyphs.  This will allow applications to have
1126  * application-specific encodings for various fonts.
1127  *
1128  * Since: 1.6.
1129  **/
1130 void
1131 pango_fc_font_map_add_decoder_find_func (PangoFcFontMap        *fcfontmap,
1132                                          PangoFcDecoderFindFunc findfunc,
1133                                          gpointer               user_data,
1134                                          GDestroyNotify         dnotify)
1135 {
1136   PangoFcFontMapPrivate *priv;
1137   PangoFcFindFuncInfo *info;
1138
1139   g_return_if_fail (PANGO_IS_FC_FONT_MAP (fcfontmap));
1140
1141   priv = fcfontmap->priv;
1142
1143   info = g_slice_new (PangoFcFindFuncInfo);
1144
1145   info->findfunc = findfunc;
1146   info->user_data = user_data;
1147   info->dnotify = dnotify;
1148
1149   priv->findfuncs = g_slist_append (priv->findfuncs, info);
1150 }
1151
1152 /**
1153  * pango_fc_font_map_find_decoder:
1154  * @fcfontmap: The #PangoFcFontMap to use.
1155  * @pattern: The #FcPattern to find the decoder for.
1156  *
1157  * Finds the decoder to use for @pattern.  Decoders can be added to
1158  * a font map using pango_fc_font_map_add_decoder_find_func().
1159  *
1160  * Returns: a newly created #PangoFcDecoder object or %NULL if
1161  *          no decoder is set for @pattern.
1162  *
1163  * Since: 1.26.
1164  **/
1165 PangoFcDecoder *
1166 pango_fc_font_map_find_decoder  (PangoFcFontMap *fcfontmap,
1167                                  FcPattern      *pattern)
1168 {
1169   GSList *l;
1170
1171   g_return_val_if_fail (PANGO_IS_FC_FONT_MAP (fcfontmap), NULL);
1172   g_return_val_if_fail (pattern != NULL, NULL);
1173
1174   for (l = fcfontmap->priv->findfuncs; l && l->data; l = l->next)
1175     {
1176       PangoFcFindFuncInfo *info = l->data;
1177       PangoFcDecoder *decoder;
1178
1179       decoder = info->findfunc (pattern, info->user_data);
1180       if (decoder)
1181         return decoder;
1182     }
1183
1184   return NULL;
1185 }
1186
1187 static void
1188 pango_fc_font_map_finalize (GObject *object)
1189 {
1190   PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (object);
1191
1192   pango_fc_font_map_shutdown (fcfontmap);
1193
1194   G_OBJECT_CLASS (pango_fc_font_map_parent_class)->finalize (object);
1195 }
1196
1197 /* Add a mapping from key to fcfont */
1198 static void
1199 pango_fc_font_map_add (PangoFcFontMap *fcfontmap,
1200                        PangoFcFontKey *key,
1201                        PangoFcFont    *fcfont)
1202 {
1203   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1204   PangoFcFontKey *key_copy;
1205
1206   key_copy = pango_fc_font_key_copy (key);
1207   _pango_fc_font_set_font_key (fcfont, key_copy);
1208   g_hash_table_insert (priv->font_hash, key_copy, fcfont);
1209 }
1210
1211 /* Remove mapping from fcfont->key to fcfont */
1212 /* Closely related to shutdown_font() */
1213 void
1214 _pango_fc_font_map_remove (PangoFcFontMap *fcfontmap,
1215                            PangoFcFont    *fcfont)
1216 {
1217   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1218   PangoFcFontKey *key;
1219
1220   key = _pango_fc_font_get_font_key (fcfont);
1221   if (key)
1222     {
1223       /* Only remove from fontmap hash if we are in it.  This is not necessarily
1224        * the case after a cache_clear() call. */
1225       if (priv->font_hash &&
1226           fcfont == g_hash_table_lookup (priv->font_hash, key))
1227         {
1228           g_hash_table_remove (priv->font_hash, key);
1229         }
1230       _pango_fc_font_set_font_key (fcfont, NULL);
1231       pango_fc_font_key_free (key);
1232     }
1233 }
1234
1235 static PangoFcFamily *
1236 create_family (PangoFcFontMap *fcfontmap,
1237                const char     *family_name,
1238                int             spacing)
1239 {
1240   PangoFcFamily *family = g_object_new (PANGO_FC_TYPE_FAMILY, NULL);
1241   family->fontmap = fcfontmap;
1242   family->family_name = g_strdup (family_name);
1243   family->spacing = spacing;
1244
1245   return family;
1246 }
1247
1248 static gboolean
1249 is_alias_family (const char *family_name)
1250 {
1251   switch (family_name[0])
1252     {
1253     case 'm':
1254     case 'M':
1255       return (g_ascii_strcasecmp (family_name, "monospace") == 0);
1256     case 's':
1257     case 'S':
1258       return (g_ascii_strcasecmp (family_name, "sans") == 0 ||
1259               g_ascii_strcasecmp (family_name, "serif") == 0);
1260     }
1261
1262   return FALSE;
1263 }
1264
1265 static void
1266 pango_fc_font_map_list_families (PangoFontMap      *fontmap,
1267                                  PangoFontFamily ***families,
1268                                  int               *n_families)
1269 {
1270   PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (fontmap);
1271   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1272   FcFontSet *fontset;
1273   int i;
1274   int count;
1275
1276   if (priv->closed)
1277     {
1278       if (families)
1279         *families = NULL;
1280       if (n_families)
1281         *n_families = 0;
1282
1283       return;
1284     }
1285
1286   if (priv->n_families < 0)
1287     {
1288       FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_SPACING, NULL);
1289       FcPattern *pat = FcPatternCreate ();
1290       /* use hash table to avoid duplicate listings if different faces in
1291        * the same family have different spacing values */
1292       GHashTable *temp_family_hash;
1293
1294       fontset = FcFontList (NULL, pat, os);
1295
1296       FcPatternDestroy (pat);
1297       FcObjectSetDestroy (os);
1298
1299       priv->families = g_new (PangoFcFamily *, fontset->nfont + 3); /* 3 standard aliases */
1300       temp_family_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1301
1302       count = 0;
1303       for (i = 0; i < fontset->nfont; i++)
1304         {
1305           char *s;
1306           FcResult res;
1307           int spacing;
1308
1309           res = FcPatternGetString (fontset->fonts[i], FC_FAMILY, 0, (FcChar8 **)(void*)&s);
1310           g_assert (res == FcResultMatch);
1311
1312           res = FcPatternGetInteger (fontset->fonts[i], FC_SPACING, 0, &spacing);
1313           g_assert (res == FcResultMatch || res == FcResultNoMatch);
1314           if (res == FcResultNoMatch)
1315             spacing = FC_PROPORTIONAL;
1316
1317           if (!is_alias_family (s) && !g_hash_table_lookup (temp_family_hash, s))
1318             {
1319               PangoFcFamily *temp_family = create_family (fcfontmap, s, spacing);
1320               g_hash_table_insert (temp_family_hash, g_strdup (s), s);
1321               priv->families[count++] = temp_family;
1322             }
1323         }
1324
1325       FcFontSetDestroy (fontset);
1326       g_hash_table_destroy (temp_family_hash);
1327
1328       priv->families[count++] = create_family (fcfontmap, "Sans", FC_PROPORTIONAL);
1329       priv->families[count++] = create_family (fcfontmap, "Serif", FC_PROPORTIONAL);
1330       priv->families[count++] = create_family (fcfontmap, "Monospace", FC_MONO);
1331
1332       priv->n_families = count;
1333     }
1334
1335   if (n_families)
1336     *n_families = priv->n_families;
1337
1338   if (families)
1339     *families = g_memdup (priv->families, priv->n_families * sizeof (PangoFontFamily *));
1340 }
1341
1342 static int
1343 pango_fc_convert_weight_to_fc (PangoWeight pango_weight)
1344 {
1345   if (pango_weight <= (PANGO_WEIGHT_THIN + PANGO_WEIGHT_ULTRALIGHT) / 2)
1346     return FC_WEIGHT_THIN;
1347   else if (pango_weight <= (PANGO_WEIGHT_ULTRALIGHT + PANGO_WEIGHT_LIGHT) / 2)
1348     return FC_WEIGHT_ULTRALIGHT;
1349   else if (pango_weight <= (PANGO_WEIGHT_LIGHT + PANGO_WEIGHT_BOOK) / 2)
1350     return FC_WEIGHT_LIGHT;
1351   else if (pango_weight <= (PANGO_WEIGHT_BOOK + PANGO_WEIGHT_NORMAL) / 2)
1352     return FC_WEIGHT_BOOK;
1353   else if (pango_weight <= (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_MEDIUM) / 2)
1354     return FC_WEIGHT_NORMAL;
1355   else if (pango_weight <= (PANGO_WEIGHT_MEDIUM + PANGO_WEIGHT_SEMIBOLD) / 2)
1356     return FC_WEIGHT_MEDIUM;
1357   else if (pango_weight <= (PANGO_WEIGHT_SEMIBOLD + PANGO_WEIGHT_BOLD) / 2)
1358     return FC_WEIGHT_DEMIBOLD;
1359   else if (pango_weight <= (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD) / 2)
1360     return FC_WEIGHT_BOLD;
1361   else if (pango_weight <= (PANGO_WEIGHT_ULTRABOLD + PANGO_WEIGHT_HEAVY) / 2)
1362     return FC_WEIGHT_ULTRABOLD;
1363   else if (pango_weight <= (PANGO_WEIGHT_HEAVY + PANGO_WEIGHT_ULTRAHEAVY) / 2)
1364     return FC_WEIGHT_BLACK;
1365   else
1366     return FC_WEIGHT_EXTRABLACK;
1367 }
1368
1369 static int
1370 pango_fc_convert_slant_to_fc (PangoStyle pango_style)
1371 {
1372   switch (pango_style)
1373     {
1374     case PANGO_STYLE_NORMAL:
1375       return FC_SLANT_ROMAN;
1376     case PANGO_STYLE_ITALIC:
1377       return FC_SLANT_ITALIC;
1378     case PANGO_STYLE_OBLIQUE:
1379       return FC_SLANT_OBLIQUE;
1380     default:
1381       return FC_SLANT_ROMAN;
1382     }
1383 }
1384
1385 #ifdef FC_WIDTH
1386 static int
1387 pango_fc_convert_width_to_fc (PangoStretch pango_stretch)
1388 {
1389   switch (pango_stretch)
1390     {
1391     case PANGO_STRETCH_NORMAL:
1392       return FC_WIDTH_NORMAL;
1393     case PANGO_STRETCH_ULTRA_CONDENSED:
1394       return FC_WIDTH_ULTRACONDENSED;
1395     case PANGO_STRETCH_EXTRA_CONDENSED:
1396       return FC_WIDTH_EXTRACONDENSED;
1397     case PANGO_STRETCH_CONDENSED:
1398       return FC_WIDTH_CONDENSED;
1399     case PANGO_STRETCH_SEMI_CONDENSED:
1400       return FC_WIDTH_SEMICONDENSED;
1401     case PANGO_STRETCH_SEMI_EXPANDED:
1402       return FC_WIDTH_SEMIEXPANDED;
1403     case PANGO_STRETCH_EXPANDED:
1404       return FC_WIDTH_EXPANDED;
1405     case PANGO_STRETCH_EXTRA_EXPANDED:
1406       return FC_WIDTH_EXTRAEXPANDED;
1407     case PANGO_STRETCH_ULTRA_EXPANDED:
1408       return FC_WIDTH_ULTRAEXPANDED;
1409     default:
1410       return FC_WIDTH_NORMAL;
1411     }
1412 }
1413 #endif
1414
1415 static FcPattern *
1416 pango_fc_make_pattern (const  PangoFontDescription *description,
1417                        PangoLanguage               *language,
1418                        int                          pixel_size,
1419                        double                       dpi)
1420 {
1421   FcPattern *pattern;
1422   const char *prgname;
1423   int slant;
1424   int weight;
1425   PangoGravity gravity;
1426   FcBool vertical;
1427   char **families;
1428   int i;
1429 #ifdef FC_WIDTH
1430   int width;
1431 #endif
1432
1433   prgname = g_get_prgname ();
1434   slant = pango_fc_convert_slant_to_fc (pango_font_description_get_style (description));
1435   weight = pango_fc_convert_weight_to_fc (pango_font_description_get_weight (description));
1436 #ifdef FC_WIDTH
1437   width = pango_fc_convert_width_to_fc (pango_font_description_get_stretch (description));
1438 #endif
1439
1440   gravity = pango_font_description_get_gravity (description);
1441   vertical = PANGO_GRAVITY_IS_VERTICAL (gravity) ? FcTrue : FcFalse;
1442
1443   /* The reason for passing in FC_SIZE as well as FC_PIXEL_SIZE is
1444    * to work around a bug in libgnomeprint where it doesn't look
1445    * for FC_PIXEL_SIZE. See http://bugzilla.gnome.org/show_bug.cgi?id=169020
1446    *
1447    * Putting FC_SIZE in here slightly reduces the efficiency
1448    * of caching of patterns and fonts when working with multiple different
1449    * dpi values.
1450    */
1451   pattern = FcPatternBuild (NULL,
1452                             PANGO_FC_VERSION, FcTypeInteger, pango_version(),
1453                             FC_WEIGHT, FcTypeInteger, weight,
1454                             FC_SLANT,  FcTypeInteger, slant,
1455 #ifdef FC_WIDTH
1456                             FC_WIDTH,  FcTypeInteger, width,
1457 #endif
1458 #ifdef FC_VERTICAL_LAYOUT
1459                             FC_VERTICAL_LAYOUT,  FcTypeBool, vertical,
1460 #endif
1461                             FC_DPI, FcTypeDouble, dpi,
1462                             FC_SIZE,  FcTypeDouble,  pixel_size * (72. / 1024. / dpi),
1463                             FC_PIXEL_SIZE,  FcTypeDouble,  pixel_size / 1024.,
1464                             NULL);
1465
1466   if (pango_font_description_get_family (description))
1467     {
1468       families = g_strsplit (pango_font_description_get_family (description), ",", -1);
1469
1470       for (i = 0; families[i]; i++)
1471         FcPatternAddString (pattern, FC_FAMILY, (FcChar8*) families[i]);
1472
1473       g_strfreev (families);
1474     }
1475
1476   if (language)
1477     FcPatternAddString (pattern, FC_LANG, (FcChar8 *) pango_language_to_string (language));
1478
1479   if (gravity != PANGO_GRAVITY_SOUTH)
1480     {
1481       GEnumValue *value = g_enum_get_value (get_gravity_class (), gravity);
1482       FcPatternAddString (pattern, PANGO_FC_GRAVITY, (FcChar8*) value->value_nick);
1483     }
1484
1485   if (prgname)
1486     FcPatternAddString (pattern, PANGO_FC_PRGNAME, (FcChar8*) prgname);
1487
1488   return pattern;
1489 }
1490
1491 static FcPattern *
1492 uniquify_pattern (PangoFcFontMap *fcfontmap,
1493                   FcPattern      *pattern)
1494 {
1495   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1496   FcPattern *old_pattern;
1497
1498   old_pattern = g_hash_table_lookup (priv->pattern_hash, pattern);
1499   if (old_pattern)
1500     {
1501       return old_pattern;
1502     }
1503   else
1504     {
1505       FcPatternReference (pattern);
1506       g_hash_table_insert (priv->pattern_hash, pattern, pattern);
1507       return pattern;
1508     }
1509 }
1510
1511 static PangoFont *
1512 pango_fc_font_map_new_font (PangoFcFontMap    *fcfontmap,
1513                             PangoFcFontsetKey *fontset_key,
1514                             FcPattern         *match)
1515 {
1516   PangoFcFontMapClass *class;
1517   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1518   FcPattern *pattern;
1519   PangoFcFont *fcfont;
1520   PangoFcFontKey key;
1521
1522   if (priv->closed)
1523     return NULL;
1524
1525   match = uniquify_pattern (fcfontmap, match);
1526
1527   pango_fc_font_key_init (&key, fcfontmap, fontset_key, match);
1528
1529   fcfont = g_hash_table_lookup (priv->font_hash, &key);
1530   if (fcfont)
1531     return g_object_ref (fcfont);
1532
1533   class = PANGO_FC_FONT_MAP_GET_CLASS (fcfontmap);
1534
1535   if (class->create_font)
1536     {
1537       fcfont = class->create_font (fcfontmap, &key);
1538     }
1539   else
1540     {
1541       const PangoMatrix *pango_matrix = pango_fc_fontset_key_get_matrix (fontset_key);
1542       FcMatrix fc_matrix, *fc_matrix_val;
1543       int i;
1544
1545       /* Fontconfig has the Y axis pointing up, Pango, down.
1546        */
1547       fc_matrix.xx = pango_matrix->xx;
1548       fc_matrix.xy = - pango_matrix->xy;
1549       fc_matrix.yx = - pango_matrix->yx;
1550       fc_matrix.yy = pango_matrix->yy;
1551
1552       pattern = FcPatternDuplicate (match);
1553
1554       for (i = 0; FcPatternGetMatrix (pattern, FC_MATRIX, i, &fc_matrix_val) == FcResultMatch; i++)
1555         FcMatrixMultiply (&fc_matrix, &fc_matrix, fc_matrix_val);
1556
1557       FcPatternDel (pattern, FC_MATRIX);
1558       FcPatternAddMatrix (pattern, FC_MATRIX, &fc_matrix);
1559
1560       fcfont = class->new_font (fcfontmap, uniquify_pattern (fcfontmap, pattern));
1561
1562       FcPatternDestroy (pattern);
1563     }
1564
1565   if (!fcfont)
1566     return NULL;
1567
1568   fcfont->matrix = key.matrix;
1569   /* In case the backend didn't set the fontmap */
1570   if (!fcfont->fontmap)
1571     g_object_set (fcfont,
1572                   "fontmap", fcfontmap,
1573                   NULL);
1574
1575   /* cache it on fontmap */
1576   pango_fc_font_map_add (fcfontmap, &key, fcfont);
1577
1578   return (PangoFont *)fcfont;
1579 }
1580
1581 static void
1582 pango_fc_default_substitute (PangoFcFontMap    *fontmap,
1583                              PangoFcFontsetKey *fontsetkey,
1584                              FcPattern         *pattern)
1585 {
1586   if (PANGO_FC_FONT_MAP_GET_CLASS (fontmap)->fontset_key_substitute)
1587     PANGO_FC_FONT_MAP_GET_CLASS (fontmap)->fontset_key_substitute (fontmap, fontsetkey, pattern);
1588   else if (PANGO_FC_FONT_MAP_GET_CLASS (fontmap)->default_substitute)
1589     PANGO_FC_FONT_MAP_GET_CLASS (fontmap)->default_substitute (fontmap, pattern);
1590 }
1591
1592 static double
1593 pango_fc_font_map_get_resolution (PangoFcFontMap *fcfontmap,
1594                                   PangoContext   *context)
1595 {
1596   if (PANGO_FC_FONT_MAP_GET_CLASS (fcfontmap)->get_resolution)
1597     return PANGO_FC_FONT_MAP_GET_CLASS (fcfontmap)->get_resolution (fcfontmap, context);
1598
1599   if (fcfontmap->priv->dpi < 0)
1600     {
1601       FcResult result = FcResultNoMatch;
1602       FcPattern *tmp = FcPatternBuild (NULL,
1603                                        FC_FAMILY, FcTypeString, "Sans",
1604                                        FC_SIZE,   FcTypeDouble, 10.,
1605                                        NULL);
1606       if (tmp)
1607         {
1608           pango_fc_default_substitute (fcfontmap, NULL, tmp);
1609           result = FcPatternGetDouble (tmp, FC_DPI, 0, &fcfontmap->priv->dpi);
1610           FcPatternDestroy (tmp);
1611         }
1612
1613       if (result != FcResultMatch)
1614         {
1615           g_warning ("Error getting DPI from fontconfig, using 72.0");
1616           fcfontmap->priv->dpi = 72.0;
1617         }
1618     }
1619
1620   return fcfontmap->priv->dpi;
1621 }
1622
1623 static FcPattern *
1624 pango_fc_fontset_key_make_pattern (PangoFcFontsetKey *key)
1625 {
1626   return pango_fc_make_pattern (key->desc,
1627                                 key->language,
1628                                 key->pixelsize,
1629                                 key->resolution);
1630 }
1631
1632 static PangoFcPatterns *
1633 pango_fc_font_map_get_patterns (PangoFontMap      *fontmap,
1634                                 PangoFcFontsetKey *key)
1635 {
1636   PangoFcFontMap *fcfontmap = (PangoFcFontMap *)fontmap;
1637   PangoFcPatterns *patterns;
1638   FcPattern *pattern;
1639
1640   pattern = pango_fc_fontset_key_make_pattern (key);
1641   pango_fc_default_substitute (fcfontmap, key, pattern);
1642
1643   patterns = pango_fc_patterns_new (pattern, fcfontmap);
1644
1645   FcPatternDestroy (pattern);
1646
1647   return patterns;
1648 }
1649
1650 static gboolean
1651 get_first_font (PangoFontset  *fontset G_GNUC_UNUSED,
1652                 PangoFont     *font,
1653                 gpointer       data)
1654 {
1655   *(PangoFont **)data = font;
1656
1657   return TRUE;
1658 }
1659
1660 static PangoFont *
1661 pango_fc_font_map_load_font (PangoFontMap               *fontmap,
1662                              PangoContext               *context,
1663                              const PangoFontDescription *description)
1664 {
1665   PangoLanguage *language;
1666   PangoFontset *fontset;
1667   PangoFont *font = NULL;
1668
1669   if (context)
1670     language = pango_context_get_language (context);
1671   else
1672     language = NULL;
1673
1674   fontset = pango_font_map_load_fontset (fontmap, context, description, language);
1675
1676   if (fontset)
1677     {
1678       pango_fontset_foreach (fontset, get_first_font, &font);
1679
1680       if (font)
1681         g_object_ref (font);
1682
1683       g_object_unref (fontset);
1684     }
1685
1686   return font;
1687 }
1688
1689 static void
1690 pango_fc_fontset_cache (PangoFcFontset *fontset,
1691                         PangoFcFontMap *fcfontmap)
1692 {
1693   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1694   GQueue *cache = priv->fontset_cache;
1695
1696   if (fontset->cache_link)
1697     {
1698       if (fontset->cache_link == cache->head)
1699         return;
1700
1701       /* Already in cache, move to head
1702        */
1703       if (fontset->cache_link == cache->tail)
1704         cache->tail = fontset->cache_link->prev;
1705
1706       cache->head = g_list_remove_link (cache->head, fontset->cache_link);
1707       cache->length--;
1708     }
1709   else
1710     {
1711       /* Add to cache initially
1712        */
1713       if (cache->length == FONTSET_CACHE_SIZE)
1714         {
1715           PangoFcFontset *tmp_fontset = g_queue_pop_tail (cache);
1716           tmp_fontset->cache_link = NULL;
1717           g_hash_table_remove (priv->fontset_hash, tmp_fontset->key);
1718         }
1719
1720       fontset->cache_link = g_list_prepend (NULL, fontset);
1721     }
1722
1723   g_queue_push_head_link (cache, fontset->cache_link);
1724 }
1725
1726 static PangoFontset *
1727 pango_fc_font_map_load_fontset (PangoFontMap                 *fontmap,
1728                                 PangoContext                 *context,
1729                                 const PangoFontDescription   *desc,
1730                                 PangoLanguage                *language)
1731 {
1732   PangoFcFontMap *fcfontmap = (PangoFcFontMap *)fontmap;
1733   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1734   PangoFcFontset *fontset;
1735   PangoFcFontsetKey key;
1736
1737   pango_fc_fontset_key_init (&key, fcfontmap, context, desc, language);
1738
1739   fontset = g_hash_table_lookup (priv->fontset_hash, &key);
1740
1741   if (G_UNLIKELY (!fontset))
1742     {
1743       PangoFcPatterns *patterns = pango_fc_font_map_get_patterns (fontmap, &key);
1744
1745       if (!patterns)
1746         return NULL;
1747
1748       fontset = pango_fc_fontset_new (&key, patterns);
1749       g_hash_table_insert (priv->fontset_hash, pango_fc_fontset_get_key (fontset), fontset);
1750
1751       pango_fc_patterns_unref (patterns);
1752     }
1753
1754   pango_fc_fontset_cache (fontset, fcfontmap);
1755
1756   pango_font_description_free (key.desc);
1757
1758   return g_object_ref (fontset);
1759 }
1760
1761 /**
1762  * pango_fc_font_map_cache_clear:
1763  * @fcfontmap: a #PangoFcFontmap
1764  *
1765  * Clear all cached information and fontsets for this font map;
1766  * this should be called whenever there is a change in the
1767  * output of the default_substitute() virtual function of the
1768  * font map, or if fontconfig has been reinitialized to new
1769  * configuration.
1770  *
1771  * Since: 1.4
1772  **/
1773 void
1774 pango_fc_font_map_cache_clear (PangoFcFontMap *fcfontmap)
1775 {
1776   if (G_UNLIKELY (fcfontmap->priv->closed))
1777     return;
1778
1779   pango_fc_font_map_fini (fcfontmap);
1780   pango_fc_font_map_init (fcfontmap);
1781 }
1782
1783 static PangoFcFontFaceData *
1784 pango_fc_font_map_get_font_face_data (PangoFcFontMap *fcfontmap,
1785                                       FcPattern      *font_pattern)
1786 {
1787   PangoFcFontMapPrivate *priv = fcfontmap->priv;
1788   PangoFcFontFaceData key;
1789   PangoFcFontFaceData *data;
1790
1791   if (FcPatternGetString (font_pattern, FC_FILE, 0, (FcChar8 **)(void*)&key.filename) != FcResultMatch)
1792     return NULL;
1793
1794   if (FcPatternGetInteger (font_pattern, FC_INDEX, 0, &key.id) != FcResultMatch)
1795     return NULL;
1796
1797   data = g_hash_table_lookup (priv->font_face_data_hash, &key);
1798   if (G_LIKELY (data))
1799     return data;
1800
1801   data = g_slice_new0 (PangoFcFontFaceData);
1802   data->filename = key.filename;
1803   data->id = key.id;
1804
1805   data->pattern = font_pattern;
1806   FcPatternReference (data->pattern);
1807
1808   g_hash_table_insert (priv->font_face_data_hash, data, data);
1809
1810   return data;
1811 }
1812
1813 static PangoFcCmapCache *
1814 _pango_fc_cmap_cache_ref (PangoFcCmapCache *cmap_cache)
1815 {
1816   g_atomic_int_inc ((int *) &cmap_cache->ref_count);
1817
1818   return cmap_cache;
1819 }
1820
1821 void
1822 _pango_fc_cmap_cache_unref (PangoFcCmapCache *cmap_cache)
1823 {
1824   g_return_if_fail (cmap_cache->ref_count > 0);
1825
1826   if (g_atomic_int_dec_and_test ((int *) &cmap_cache->ref_count))
1827     {
1828       g_free (cmap_cache);
1829     }
1830 }
1831
1832 PangoFcCmapCache *
1833 _pango_fc_font_map_get_cmap_cache (PangoFcFontMap *fcfontmap,
1834                                    PangoFcFont    *fcfont)
1835 {
1836   PangoFcFontMapPrivate *priv;
1837   PangoFcFontFaceData *data;
1838
1839   if (G_UNLIKELY (fcfontmap == NULL))
1840         return NULL;
1841
1842   if (G_UNLIKELY (!fcfont->font_pattern))
1843     return NULL;
1844
1845   priv = fcfontmap->priv;
1846
1847   data = pango_fc_font_map_get_font_face_data (fcfontmap, fcfont->font_pattern);
1848   if (G_UNLIKELY (!data))
1849     return NULL;
1850
1851   if (G_UNLIKELY (data->cmap_cache == NULL))
1852     {
1853       data->cmap_cache = g_new0 (PangoFcCmapCache, 1);
1854       data->cmap_cache->ref_count = 1;
1855
1856       /* Make sure all cache entries are invalid initially */
1857       data->cmap_cache->entries[0].ch = 1; /* char 1 cannot happen in bucket 0 */
1858     }
1859
1860   return _pango_fc_cmap_cache_ref (data->cmap_cache);
1861 }
1862
1863 PangoCoverage *
1864 _pango_fc_font_map_get_coverage (PangoFcFontMap *fcfontmap,
1865                                  PangoFcFont    *fcfont)
1866 {
1867   PangoFcFontFaceData *data;
1868   FcCharSet *charset;
1869
1870   if (G_UNLIKELY (!fcfont->font_pattern))
1871     return NULL;
1872
1873   data = pango_fc_font_map_get_font_face_data (fcfontmap, fcfont->font_pattern);
1874   if (G_UNLIKELY (!data))
1875     return NULL;
1876
1877   if (G_UNLIKELY (data->coverage == NULL))
1878     {
1879       /*
1880        * Pull the coverage out of the pattern, this
1881        * doesn't require loading the font
1882        */
1883       if (FcPatternGetCharSet (fcfont->font_pattern, FC_CHARSET, 0, &charset) != FcResultMatch)
1884         return NULL;
1885
1886       data->coverage = _pango_fc_font_map_fc_to_coverage (charset);
1887     }
1888
1889   return pango_coverage_ref (data->coverage);
1890 }
1891
1892 /**
1893  * _pango_fc_font_map_fc_to_coverage:
1894  * @charset: #FcCharSet to convert to a #PangoCoverage object.
1895  *
1896  * Convert the given #FcCharSet into a new #PangoCoverage object.  The
1897  * caller is responsible for freeing the newly created object.
1898  *
1899  * Since: 1.6
1900  **/
1901 PangoCoverage  *
1902 _pango_fc_font_map_fc_to_coverage (FcCharSet *charset)
1903 {
1904   PangoCoverage *coverage;
1905   FcChar32  ucs4, pos;
1906   FcChar32  map[FC_CHARSET_MAP_SIZE];
1907   int i;
1908
1909   /*
1910    * Convert an Fc CharSet into a pango coverage structure.  Sure
1911    * would be nice to just use the Fc structure in place...
1912    */
1913   coverage = pango_coverage_new ();
1914   for (ucs4 = FcCharSetFirstPage (charset, map, &pos);
1915        ucs4 != FC_CHARSET_DONE;
1916        ucs4 = FcCharSetNextPage (charset, map, &pos))
1917     {
1918       for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
1919         {
1920           FcChar32  bits = map[i];
1921           FcChar32  base = ucs4 + i * 32;
1922           int b = 0;
1923
1924           while (bits)
1925             {
1926               if (bits & 1)
1927                 pango_coverage_set (coverage, base + b, PANGO_COVERAGE_EXACT);
1928
1929               bits >>= 1;
1930               b++;
1931             }
1932         }
1933     }
1934
1935   /* Awful hack so Hangul Tone marks get rendered with the same
1936    * font and in the same run as other Hangul characters. If a font
1937    * covers the first composed Hangul glyph, then it is declared to cover
1938    * the Hangul tone marks. This hack probably needs to be formalized
1939    * by choosing fonts for scripts rather than individual code points.
1940    */
1941   if (pango_coverage_get (coverage, 0xac00) == PANGO_COVERAGE_EXACT)
1942     {
1943       pango_coverage_set (coverage, 0x302e, PANGO_COVERAGE_EXACT);
1944       pango_coverage_set (coverage, 0x302f, PANGO_COVERAGE_EXACT);
1945     }
1946
1947   return coverage;
1948 }
1949
1950 /**
1951  * pango_fc_font_map_create_context:
1952  * @fcfontmap: a #PangoFcFontMap
1953  *
1954  * Creates a new context for this fontmap. This function is intended
1955  * only for backend implementations deriving from #PangoFcFontmap;
1956  * it is possible that a backend will store additional information
1957  * needed for correct operation on the #PangoContext after calling
1958  * this function.
1959  *
1960  * Return value: a new #PangoContext
1961  *
1962  * Since: 1.4
1963  *
1964  * Deprecated: 1.22: Use pango_font_map_create_context() instead.
1965  **/
1966 PangoContext *
1967 pango_fc_font_map_create_context (PangoFcFontMap *fcfontmap)
1968 {
1969   g_return_val_if_fail (PANGO_IS_FC_FONT_MAP (fcfontmap), NULL);
1970
1971   return pango_font_map_create_context (PANGO_FONT_MAP (fcfontmap));
1972 }
1973
1974 static void
1975 shutdown_font (gpointer        key,
1976                PangoFcFont    *fcfont,
1977                PangoFcFontMap *fcfontmap)
1978 {
1979   _pango_fc_font_shutdown (fcfont);
1980
1981   _pango_fc_font_set_font_key (fcfont, NULL);
1982   pango_fc_font_key_free (key);
1983 }
1984
1985 /**
1986  * pango_fc_font_map_shutdown:
1987  * @fcfontmap: a #PangoFcFontmap
1988  *
1989  * Clears all cached information for the fontmap and marks
1990  * all fonts open for the fontmap as dead. (See the shutdown()
1991  * virtual function of #PangoFcFont.) This function might be used
1992  * by a backend when the underlying windowing system for the font
1993  * map exits. This function is only intended to be called
1994  * only for backend implementations deriving from #PangoFcFontmap.
1995  *
1996  * Since: 1.4
1997  **/
1998 void
1999 pango_fc_font_map_shutdown (PangoFcFontMap *fcfontmap)
2000 {
2001   PangoFcFontMapPrivate *priv = fcfontmap->priv;
2002   int i;
2003
2004   if (priv->closed)
2005     return;
2006
2007   g_hash_table_foreach (priv->font_hash, (GHFunc) shutdown_font, fcfontmap);
2008   for (i = 0; i < priv->n_families; i++)
2009     priv->families[i]->fontmap = NULL;
2010
2011   pango_fc_font_map_fini (fcfontmap);
2012
2013   while (priv->findfuncs)
2014     {
2015       PangoFcFindFuncInfo *info;
2016       info = priv->findfuncs->data;
2017       if (info->dnotify)
2018         info->dnotify (info->user_data);
2019
2020       g_slice_free (PangoFcFindFuncInfo, info);
2021       priv->findfuncs = g_slist_delete_link (priv->findfuncs, priv->findfuncs);
2022     }
2023
2024   priv->closed = TRUE;
2025 }
2026
2027 static PangoWeight
2028 pango_fc_convert_weight_to_pango (int fc_weight)
2029 {
2030   if (fc_weight <= (FC_WEIGHT_THIN + FC_WEIGHT_EXTRALIGHT) / 2)
2031     return PANGO_WEIGHT_THIN;
2032   else if (fc_weight <= (FC_WEIGHT_EXTRALIGHT + FC_WEIGHT_LIGHT) / 2)
2033     return PANGO_WEIGHT_ULTRALIGHT;
2034   else if (fc_weight <= (FC_WEIGHT_LIGHT + FC_WEIGHT_BOOK) / 2)
2035     return PANGO_WEIGHT_LIGHT;
2036   else if (fc_weight <= (FC_WEIGHT_BOOK + FC_WEIGHT_REGULAR) / 2)
2037     return PANGO_WEIGHT_BOOK;
2038   else if (fc_weight <= (FC_WEIGHT_REGULAR + FC_WEIGHT_MEDIUM) / 2)
2039     return PANGO_WEIGHT_NORMAL;
2040    else if (fc_weight <= (FC_WEIGHT_MEDIUM + FC_WEIGHT_DEMIBOLD) / 2)
2041     return PANGO_WEIGHT_MEDIUM;
2042   else if (fc_weight <= (FC_WEIGHT_DEMIBOLD + FC_WEIGHT_BOLD) / 2)
2043     return PANGO_WEIGHT_SEMIBOLD;
2044   else if (fc_weight <= (FC_WEIGHT_BOLD + FC_WEIGHT_EXTRABOLD) / 2)
2045     return PANGO_WEIGHT_BOLD;
2046   else if (fc_weight <= (FC_WEIGHT_EXTRABOLD + FC_WEIGHT_BLACK) / 2)
2047     return PANGO_WEIGHT_ULTRABOLD;
2048   else if (fc_weight <= (FC_WEIGHT_BLACK + FC_WEIGHT_EXTRABLACK) / 2)
2049     return PANGO_WEIGHT_HEAVY;
2050   else
2051     return PANGO_WEIGHT_ULTRAHEAVY;
2052 }
2053
2054 static PangoStyle
2055 pango_fc_convert_slant_to_pango (int fc_style)
2056 {
2057   switch (fc_style)
2058     {
2059     case FC_SLANT_ROMAN:
2060       return PANGO_STYLE_NORMAL;
2061     case FC_SLANT_ITALIC:
2062       return PANGO_STYLE_ITALIC;
2063     case FC_SLANT_OBLIQUE:
2064       return PANGO_STYLE_OBLIQUE;
2065     default:
2066       return PANGO_STYLE_NORMAL;
2067     }
2068 }
2069
2070 #ifdef FC_WIDTH
2071 static PangoStretch
2072 pango_fc_convert_width_to_pango (int fc_stretch)
2073 {
2074   switch (fc_stretch)
2075     {
2076     case FC_WIDTH_NORMAL:
2077       return PANGO_STRETCH_NORMAL;
2078     case FC_WIDTH_ULTRACONDENSED:
2079       return PANGO_STRETCH_ULTRA_CONDENSED;
2080     case FC_WIDTH_EXTRACONDENSED:
2081       return PANGO_STRETCH_EXTRA_CONDENSED;
2082     case FC_WIDTH_CONDENSED:
2083       return PANGO_STRETCH_CONDENSED;
2084     case FC_WIDTH_SEMICONDENSED:
2085       return PANGO_STRETCH_SEMI_CONDENSED;
2086     case FC_WIDTH_SEMIEXPANDED:
2087       return PANGO_STRETCH_SEMI_EXPANDED;
2088     case FC_WIDTH_EXPANDED:
2089       return PANGO_STRETCH_EXPANDED;
2090     case FC_WIDTH_EXTRAEXPANDED:
2091       return PANGO_STRETCH_EXTRA_EXPANDED;
2092     case FC_WIDTH_ULTRAEXPANDED:
2093       return PANGO_STRETCH_ULTRA_EXPANDED;
2094     default:
2095       return PANGO_STRETCH_NORMAL;
2096     }
2097 }
2098 #endif
2099
2100 /**
2101  * pango_fc_font_description_from_pattern:
2102  * @pattern: a #FcPattern
2103  * @include_size: if %TRUE, the pattern will include the size from
2104  *   the @pattern; otherwise the resulting pattern will be unsized.
2105  *   (only %FC_SIZE is examined, not %FC_PIXEL_SIZE)
2106  *
2107  * Creates a #PangoFontDescription that matches the specified
2108  * Fontconfig pattern as closely as possible. Many possible Fontconfig
2109  * pattern values, such as %FC_RASTERIZER or %FC_DPI, don't make sense in
2110  * the context of #PangoFontDescription, so will be ignored.
2111  *
2112  * Return value: a new #PangoFontDescription. Free with
2113  *  pango_font_description_free().
2114  *
2115  * Since: 1.4
2116  **/
2117 PangoFontDescription *
2118 pango_fc_font_description_from_pattern (FcPattern *pattern, gboolean include_size)
2119 {
2120   PangoFontDescription *desc;
2121   PangoStyle style;
2122   PangoWeight weight;
2123   PangoStretch stretch;
2124   double size;
2125   PangoGravity gravity;
2126
2127   FcChar8 *s;
2128   int i;
2129   FcResult res;
2130
2131   desc = pango_font_description_new ();
2132
2133   res = FcPatternGetString (pattern, FC_FAMILY, 0, (FcChar8 **) &s);
2134   g_assert (res == FcResultMatch);
2135
2136   pango_font_description_set_family (desc, (gchar *)s);
2137
2138   if (FcPatternGetInteger (pattern, FC_SLANT, 0, &i) == FcResultMatch)
2139     style = pango_fc_convert_slant_to_pango (i);
2140   else
2141     style = PANGO_STYLE_NORMAL;
2142
2143   pango_font_description_set_style (desc, style);
2144
2145   if (FcPatternGetInteger (pattern, FC_WEIGHT, 0, &i) == FcResultMatch)
2146     weight = pango_fc_convert_weight_to_pango (i);
2147   else
2148     weight = PANGO_WEIGHT_NORMAL;
2149
2150   pango_font_description_set_weight (desc, weight);
2151
2152 #ifdef FC_WIDTH
2153   if (FcPatternGetInteger (pattern, FC_WIDTH, 0, &i) == FcResultMatch)
2154     stretch = pango_fc_convert_width_to_pango (i);
2155   else
2156 #endif
2157     stretch = PANGO_STRETCH_NORMAL;
2158
2159   pango_font_description_set_stretch (desc, stretch);
2160
2161   pango_font_description_set_variant (desc, PANGO_VARIANT_NORMAL);
2162
2163   if (include_size && FcPatternGetDouble (pattern, FC_SIZE, 0, &size) == FcResultMatch)
2164     pango_font_description_set_size (desc, size * PANGO_SCALE);
2165
2166   /* gravity is a bit different.  we don't want to set it if it was not set on
2167    * the pattern */
2168   if (FcPatternGetString (pattern, PANGO_FC_GRAVITY, 0, (FcChar8 **)&s) == FcResultMatch)
2169     {
2170       GEnumValue *value = g_enum_get_value_by_nick (get_gravity_class (), (char *)s);
2171       gravity = value->value;
2172
2173       pango_font_description_set_gravity (desc, gravity);
2174     }
2175
2176   return desc;
2177 }
2178
2179 /*
2180  * PangoFcFace
2181  */
2182
2183 static GObjectClass *pango_fc_face_parent_class = NULL;
2184
2185 static PangoFontDescription *
2186 make_alias_description (PangoFcFamily *fcfamily,
2187                         gboolean        bold,
2188                         gboolean        italic)
2189 {
2190   PangoFontDescription *desc = pango_font_description_new ();
2191
2192   pango_font_description_set_family (desc, fcfamily->family_name);
2193   pango_font_description_set_style (desc, italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL);
2194   pango_font_description_set_weight (desc, bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL);
2195
2196   return desc;
2197 }
2198
2199 static PangoFontDescription *
2200 pango_fc_face_describe (PangoFontFace *face)
2201 {
2202   PangoFcFace *fcface = PANGO_FC_FACE (face);
2203   PangoFcFamily *fcfamily = fcface->family;
2204   PangoFontDescription *desc = NULL;
2205   FcResult res;
2206   FcPattern *match_pattern;
2207   FcPattern *result_pattern;
2208
2209   if (G_UNLIKELY (!fcfamily))
2210     return pango_font_description_new ();
2211
2212   if (fcface->fake)
2213     {
2214       if (strcmp (fcface->style, "Regular") == 0)
2215         return make_alias_description (fcfamily, FALSE, FALSE);
2216       else if (strcmp (fcface->style, "Bold") == 0)
2217         return make_alias_description (fcfamily, TRUE, FALSE);
2218       else if (strcmp (fcface->style, "Italic") == 0)
2219         return make_alias_description (fcfamily, FALSE, TRUE);
2220       else                      /* Bold Italic */
2221         return make_alias_description (fcfamily, TRUE, TRUE);
2222     }
2223
2224   match_pattern = FcPatternBuild (NULL,
2225                                   FC_FAMILY, FcTypeString, fcfamily->family_name,
2226                                   FC_STYLE, FcTypeString, fcface->style,
2227                                   NULL);
2228
2229   g_assert (match_pattern);
2230
2231   FcConfigSubstitute (NULL, match_pattern, FcMatchPattern);
2232   FcDefaultSubstitute (match_pattern);
2233
2234   result_pattern = FcFontMatch (NULL, match_pattern, &res);
2235   if (result_pattern)
2236     {
2237       desc = pango_fc_font_description_from_pattern (result_pattern, FALSE);
2238       FcPatternDestroy (result_pattern);
2239     }
2240
2241   FcPatternDestroy (match_pattern);
2242
2243   return desc;
2244 }
2245
2246 static const char *
2247 pango_fc_face_get_face_name (PangoFontFace *face)
2248 {
2249   PangoFcFace *fcface = PANGO_FC_FACE (face);
2250
2251   return fcface->style;
2252 }
2253
2254 static int
2255 compare_ints (gconstpointer ap,
2256               gconstpointer bp)
2257 {
2258   int a = *(int *)ap;
2259   int b = *(int *)bp;
2260
2261   if (a == b)
2262     return 0;
2263   else if (a > b)
2264     return 1;
2265   else
2266     return -1;
2267 }
2268
2269 static void
2270 pango_fc_face_list_sizes (PangoFontFace  *face,
2271                           int           **sizes,
2272                           int            *n_sizes)
2273 {
2274   PangoFcFace *fcface = PANGO_FC_FACE (face);
2275   FcPattern *pattern;
2276   FcFontSet *fontset;
2277   FcObjectSet *objectset;
2278
2279   *sizes = NULL;
2280   *n_sizes = 0;
2281   if (G_UNLIKELY (!fcface->family || !fcface->family->fontmap))
2282     return;
2283
2284   pattern = FcPatternCreate ();
2285   FcPatternAddString (pattern, FC_FAMILY, (FcChar8*)(void*)fcface->family->family_name);
2286   FcPatternAddString (pattern, FC_STYLE, (FcChar8*)(void*)fcface->style);
2287
2288   objectset = FcObjectSetCreate ();
2289   FcObjectSetAdd (objectset, FC_PIXEL_SIZE);
2290
2291   fontset = FcFontList (NULL, pattern, objectset);
2292
2293   if (fontset)
2294     {
2295       GArray *size_array;
2296       double size, dpi = -1.0;
2297       int i, size_i;
2298
2299       size_array = g_array_new (FALSE, FALSE, sizeof (int));
2300
2301       for (i = 0; i < fontset->nfont; i++)
2302         {
2303           if (FcPatternGetDouble (fontset->fonts[i], FC_PIXEL_SIZE, 0, &size) == FcResultMatch)
2304             {
2305               if (dpi < 0)
2306                 dpi = pango_fc_font_map_get_resolution (fcface->family->fontmap, NULL);
2307
2308               size_i = (int) (PANGO_SCALE * size * 72.0 / dpi);
2309               g_array_append_val (size_array, size_i);
2310             }
2311         }
2312
2313       g_array_sort (size_array, compare_ints);
2314
2315       if (size_array->len == 0)
2316         {
2317           *n_sizes = 0;
2318           if (sizes)
2319             *sizes = NULL;
2320           g_array_free (size_array, TRUE);
2321         }
2322       else
2323         {
2324           *n_sizes = size_array->len;
2325           if (sizes)
2326             {
2327               *sizes = (int *) size_array->data;
2328               g_array_free (size_array, FALSE);
2329             }
2330           else
2331             g_array_free (size_array, TRUE);
2332         }
2333
2334       FcFontSetDestroy (fontset);
2335     }
2336   else
2337     {
2338       *n_sizes = 0;
2339       if (sizes)
2340         *sizes = NULL;
2341     }
2342
2343   FcPatternDestroy (pattern);
2344   FcObjectSetDestroy (objectset);
2345 }
2346
2347 static gboolean
2348 pango_fc_face_is_synthesized (PangoFontFace *face)
2349 {
2350   PangoFcFace *fcface = PANGO_FC_FACE (face);
2351
2352   return fcface->fake;
2353 }
2354
2355 static void
2356 pango_fc_face_finalize (GObject *object)
2357 {
2358   PangoFcFace *fcface = PANGO_FC_FACE (object);
2359
2360   g_free (fcface->style);
2361
2362   pango_fc_face_parent_class->finalize (object);
2363 }
2364
2365 typedef PangoFontFaceClass PangoFcFaceClass;
2366
2367 static void
2368 pango_fc_face_class_init (PangoFcFaceClass *class)
2369 {
2370   GObjectClass *object_class = G_OBJECT_CLASS (class);
2371
2372   pango_fc_face_parent_class = g_type_class_peek_parent (class);
2373   object_class->finalize = pango_fc_face_finalize;
2374
2375   class->describe = pango_fc_face_describe;
2376   class->get_face_name = pango_fc_face_get_face_name;
2377   class->list_sizes = pango_fc_face_list_sizes;
2378   class->is_synthesized = pango_fc_face_is_synthesized;
2379 }
2380
2381 static PANGO_DEFINE_TYPE (PangoFcFace, pango_fc_face,
2382                           pango_fc_face_class_init, NULL,
2383                           PANGO_TYPE_FONT_FACE)
2384
2385 /*
2386  * PangoFcFamily
2387  */
2388
2389 static GObjectClass *pango_fc_family_parent_class = NULL;
2390
2391 static PangoFcFace *
2392 create_face (PangoFcFamily *fcfamily,
2393              const char     *style,
2394              gboolean       fake)
2395 {
2396   PangoFcFace *face = g_object_new (PANGO_FC_TYPE_FACE, NULL);
2397   face->style = g_strdup (style);
2398   face->family = fcfamily;
2399   face->fake = fake;
2400
2401   return face;
2402 }
2403
2404 static void
2405 pango_fc_family_list_faces (PangoFontFamily  *family,
2406                             PangoFontFace  ***faces,
2407                             int              *n_faces)
2408 {
2409   PangoFcFamily *fcfamily = PANGO_FC_FAMILY (family);
2410   PangoFcFontMap *fcfontmap = fcfamily->fontmap;
2411   PangoFcFontMapPrivate *priv;
2412
2413   *faces = NULL;
2414   *n_faces = 0;
2415   if (G_UNLIKELY (!fcfontmap))
2416     return;
2417
2418   priv = fcfontmap->priv;
2419
2420   if (fcfamily->n_faces < 0)
2421     {
2422       FcFontSet *fontset;
2423       int i;
2424
2425       if (is_alias_family (fcfamily->family_name) || priv->closed)
2426         {
2427           fcfamily->n_faces = 4;
2428           fcfamily->faces = g_new (PangoFcFace *, fcfamily->n_faces);
2429
2430           i = 0;
2431           fcfamily->faces[i++] = create_face (fcfamily, "Regular", TRUE);
2432           fcfamily->faces[i++] = create_face (fcfamily, "Bold", TRUE);
2433           fcfamily->faces[i++] = create_face (fcfamily, "Italic", TRUE);
2434           fcfamily->faces[i++] = create_face (fcfamily, "Bold Italic", TRUE);
2435         }
2436       else
2437         {
2438           FcObjectSet *os = FcObjectSetBuild (FC_STYLE, FC_WEIGHT, FC_SLANT, NULL);
2439           FcPattern *pat = FcPatternBuild (NULL,
2440                                            FC_FAMILY, FcTypeString, fcfamily->family_name,
2441                                            NULL);
2442
2443           enum {
2444             REGULAR,
2445             ITALIC,
2446             BOLD,
2447             BOLD_ITALIC
2448           };
2449           /* Regular, Italic, Bold, Bold Italic */
2450           gboolean has_face [4] = { FALSE, FALSE, FALSE, FALSE };
2451           PangoFcFace **faces;
2452           gint num = 0;
2453
2454           fontset = FcFontList (NULL, pat, os);
2455
2456           FcPatternDestroy (pat);
2457           FcObjectSetDestroy (os);
2458
2459           /* at most we have 3 additional artifical faces */
2460           faces = g_new (PangoFcFace *, fontset->nfont + 3);
2461
2462           for (i = 0; i < fontset->nfont; i++)
2463             {
2464               const char *style, *font_style = NULL;
2465               int weight, slant;
2466
2467               if (FcPatternGetInteger(fontset->fonts[i], FC_WEIGHT, 0, &weight) != FcResultMatch)
2468                 weight = FC_WEIGHT_MEDIUM;
2469
2470               if (FcPatternGetInteger(fontset->fonts[i], FC_SLANT, 0, &slant) != FcResultMatch)
2471                 slant = FC_SLANT_ROMAN;
2472
2473               if (FcPatternGetString (fontset->fonts[i], FC_STYLE, 0, (FcChar8 **)(void*)&font_style) != FcResultMatch)
2474                 font_style = NULL;
2475
2476               if (weight <= FC_WEIGHT_MEDIUM)
2477                 {
2478                   if (slant == FC_SLANT_ROMAN)
2479                     {
2480                       has_face[REGULAR] = TRUE;
2481                       style = "Regular";
2482                     }
2483                   else
2484                     {
2485                       has_face[ITALIC] = TRUE;
2486                       style = "Italic";
2487                     }
2488                 }
2489               else
2490                 {
2491                   if (slant == FC_SLANT_ROMAN)
2492                     {
2493                       has_face[BOLD] = TRUE;
2494                       style = "Bold";
2495                     }
2496                   else
2497                     {
2498                       has_face[BOLD_ITALIC] = TRUE;
2499                       style = "Bold Italic";
2500                     }
2501                 }
2502
2503               if (!font_style)
2504                 font_style = style;
2505               faces[num++] = create_face (fcfamily, font_style, FALSE);
2506             }
2507
2508           if (has_face[REGULAR])
2509             {
2510               if (!has_face[ITALIC])
2511                 faces[num++] = create_face (fcfamily, "Italic", TRUE);
2512               if (!has_face[BOLD])
2513                 faces[num++] = create_face (fcfamily, "Bold", TRUE);
2514
2515             }
2516           if ((has_face[REGULAR] || has_face[ITALIC] || has_face[BOLD]) && !has_face[BOLD_ITALIC])
2517             faces[num++] = create_face (fcfamily, "Bold Italic", TRUE);
2518
2519           faces = g_renew (PangoFcFace *, faces, num);
2520
2521           fcfamily->n_faces = num;
2522           fcfamily->faces = faces;
2523
2524           FcFontSetDestroy (fontset);
2525         }
2526     }
2527
2528   if (n_faces)
2529     *n_faces = fcfamily->n_faces;
2530
2531   if (faces)
2532     *faces = g_memdup (fcfamily->faces, fcfamily->n_faces * sizeof (PangoFontFace *));
2533 }
2534
2535 static const char *
2536 pango_fc_family_get_name (PangoFontFamily  *family)
2537 {
2538   PangoFcFamily *fcfamily = PANGO_FC_FAMILY (family);
2539
2540   return fcfamily->family_name;
2541 }
2542
2543 static gboolean
2544 pango_fc_family_is_monospace (PangoFontFamily *family)
2545 {
2546   PangoFcFamily *fcfamily = PANGO_FC_FAMILY (family);
2547
2548   return fcfamily->spacing == FC_MONO ||
2549 #ifdef FC_DUAL
2550          fcfamily->spacing == FC_DUAL ||
2551 #endif
2552          fcfamily->spacing == FC_CHARCELL;
2553 }
2554
2555 static void
2556 pango_fc_family_finalize (GObject *object)
2557 {
2558   int i;
2559   PangoFcFamily *fcfamily = PANGO_FC_FAMILY (object);
2560
2561   g_free (fcfamily->family_name);
2562
2563   for (i = 0; i < fcfamily->n_faces; i++)
2564     {
2565       fcfamily->faces[i]->family = NULL;
2566       g_object_unref (fcfamily->faces[i]);
2567     }
2568   g_free (fcfamily->faces);
2569
2570   pango_fc_family_parent_class->finalize (object);
2571 }
2572
2573 typedef PangoFontFamilyClass PangoFcFamilyClass;
2574
2575 static void
2576 pango_fc_family_class_init (PangoFcFamilyClass *class)
2577 {
2578   GObjectClass *object_class = G_OBJECT_CLASS (class);
2579
2580   pango_fc_family_parent_class = g_type_class_peek_parent (class);
2581   object_class->finalize = pango_fc_family_finalize;
2582
2583   class->list_faces = pango_fc_family_list_faces;
2584   class->get_name = pango_fc_family_get_name;
2585   class->is_monospace = pango_fc_family_is_monospace;
2586 }
2587
2588 static void
2589 pango_fc_family_init (PangoFcFamily *fcfamily)
2590 {
2591   fcfamily->n_faces = -1;
2592 }
2593
2594 static PANGO_DEFINE_TYPE (PangoFcFamily, pango_fc_family,
2595                           pango_fc_family_class_init, pango_fc_family_init,
2596                           PANGO_TYPE_FONT_FAMILY)