1 /* Pango
2 * pangocoretext-fontmap.c
3 *
4 * Copyright (C) 2000-2003 Red Hat, Inc.
5 * Copyright (C) 2005-2007 Imendio AB
6 * Copyright (C) 2010 Kristian Rietveld <kris@gtk.org>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24 #include "config.h"
25
26 #include "pango-fontmap.h"
27 #include "pangocoretext-private.h"
28 #include "pango-impl-utils.h"
29
30 #include <Carbon/Carbon.h>
31
32 typedef struct _FontHashKey FontHashKey;
33
34 typedef struct _PangoCoreTextFontset PangoCoreTextFontset;
35
36 #define PANGO_TYPE_CORE_TEXT_FAMILY (pango_core_text_family_get_type ())
37 #define PANGO_CORE_TEXT_FAMILY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CORE_TEXT_FAMILY, PangoCoreTextFamily))
38 #define PANGO_IS_CORE_TEXT_FAMILY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CORE_TEXT_FAMILY))
39 #define PANGO_CORE_TEXT_FAMILY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_CORE_TEXT_FAMILY, PangoCoreTextFamilyClass))
40 #define PANGO_IS_CORE_TEXT_FAMILY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_CORE_TEXT_FAMILY))
41 #define PANGO_CORE_TEXT_FAMILY_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), PANGO_CORE_TEXT_FAMILY, PangoCoreTextFamilyClass))
42
43 #define PANGO_TYPE_CORE_TEXT_FONTSET (pango_core_text_fontset_get_type ())
44 #define PANGO_CORE_TEXT_FONTSET(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CORE_TEXT_FONTSET, PangoCoreTextFontset))
45 #define PANGO_IS_CORE_TEXT_FONTSET(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CORE_TEXT_FONTSET))
46
47
48 struct _PangoCoreTextFamily
49 {
50 PangoFontFamily parent_instance;
51
52 char *family_name;
53
54 guint is_monospace : 1;
55
56 PangoFontFace **faces;
57 gint n_faces;
58 };
59
60 struct _PangoCoreTextFamilyClass
61 {
62 PangoFontFamilyClass parent_class;
63 };
64
65 typedef struct _PangoCoreTextFamilyClass PangoCoreTextFamilyClass;
66
67 #define PANGO_TYPE_CORE_TEXT_FACE (pango_core_text_face_get_type ())
68 #define PANGO_CORE_TEXT_FACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CORE_TEXT_FACE, PangoCoreTextFace))
69 #define PANGO_IS_CORE_TEXT_FACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), PANGO_TYPE_CORE_TEXT_FACE))
70 #define PANGO_CORE_TEXT_FACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_CORE_TEXT_FACE, PangoCoreTextFaceClass))
71 #define PANGO_IS_CORE_TEXT_FACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_CORE_TEXT_FACE))
72 #define PANGO_CORE_TEXT_FACE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), PANGO_CORE_TEXT_FACE, PangoCoreTextFaceClass))
73
74 struct _PangoCoreTextFace
75 {
76 PangoFontFace parent_instance;
77
78 PangoCoreTextFamily *family;
79
80 CTFontDescriptorRef ctfontdescriptor;
81
82 char *style_name;
83 PangoWeight weight;
84 CTFontSymbolicTraits traits;
85 guint synthetic_italic : 1;
86 };
87
88 struct _PangoCoreTextFaceClass
89 {
90 PangoFontFaceClass parent_class;
91 };
92
93 typedef struct _PangoCoreTextFaceClass PangoCoreTextFaceClass;
94
95 static GType pango_core_text_family_get_type (void);
96 static GType pango_core_text_face_get_type (void);
97 static GType pango_core_text_fontset_get_type (void);
98
99 static PangoCoreTextFontset *pango_core_text_fontset_new (PangoCoreTextFontsetKey *key,
100 const PangoFontDescription *description);
101 static PangoCoreTextFontsetKey *pango_core_text_fontset_get_key (PangoCoreTextFontset *fontset);
102
103 /*
104 * Helper functions to translate CoreText data to Pango
105 */
106
107 typedef struct
108 {
109 float ct_weight;
110 PangoWeight pango_weight;
111 } PangoCTWeight;
112
113 #define ct_weight_min -0.7f
114 #define ct_weight_max 0.8f
115
116 /* This map is based on empirical data from analyzing a large collection of
117 * fonts and comparing the opentype value with the value that OSX returns.
118 * see: https://bugzilla.gnome.org/show_bug.cgi?id=766148
119 */
120
121 static const PangoCTWeight ct_weight_map[] = {
122 { ct_weight_min, PANGO_WEIGHT_THIN },
123 { -0.5, PANGO_WEIGHT_ULTRALIGHT },
124 { -0.23, PANGO_WEIGHT_LIGHT },
125 { -0.115, PANGO_WEIGHT_SEMILIGHT },
126 { 0.00, PANGO_WEIGHT_NORMAL },
127 { 0.2, PANGO_WEIGHT_MEDIUM },
128 { 0.3, PANGO_WEIGHT_SEMIBOLD },
129 { 0.4, PANGO_WEIGHT_BOLD },
130 { 0.6, PANGO_WEIGHT_ULTRABOLD },
131 { ct_weight_max, PANGO_WEIGHT_HEAVY }
132 };
133
134 static const char *
get_real_family(const char * family_name)135 get_real_family (const char *family_name)
136 {
137 switch (family_name[0])
138 {
139 case 'c':
140 case 'C':
141 if (g_ascii_strcasecmp (family_name, "cursive") == 0)
142 return "Apple Chancery";
143 break;
144 case 'f':
145 case 'F':
146 if (g_ascii_strcasecmp (family_name, "fantasy") == 0)
147 return "Papyrus";
148 break;
149 case 'm':
150 case 'M':
151 if (g_ascii_strcasecmp (family_name, "monospace") == 0)
152 return "Courier";
153 break;
154 case 's':
155 case 'S':
156 if (g_ascii_strcasecmp (family_name, "sans") == 0)
157 return "Helvetica";
158 else if (g_ascii_strcasecmp (family_name, "serif") == 0)
159 return "Times";
160 else if (g_ascii_strcasecmp (family_name, "system-ui") == 0)
161 return ".AppleSystemUIFont";
162 break;
163 }
164
165 return family_name;
166 }
167
168 static gchar *
gchar_from_cf_string(CFStringRef str)169 gchar_from_cf_string (CFStringRef str)
170 {
171 CFIndex len;
172 gchar *buffer;
173
174 /* GetLength returns the number of UTF-16 pairs, so this number
175 * times 2 should definitely gives us enough space for UTF8.
176 * We add one for the terminating zero.
177 */
178 len = CFStringGetLength (str) * 2 + 1;
179 buffer = g_new0 (char, len);
180 CFStringGetCString (str, buffer, len, kCFStringEncodingUTF8);
181
182 return buffer;
183 }
184
185 static char *
ct_font_descriptor_get_family_name(CTFontDescriptorRef desc,gboolean may_fail)186 ct_font_descriptor_get_family_name (CTFontDescriptorRef desc,
187 gboolean may_fail)
188 {
189 CFStringRef cf_str;
190 char *buffer;
191
192 cf_str = CTFontDescriptorCopyAttribute (desc, kCTFontFamilyNameAttribute);
193 if (!cf_str)
194 {
195 int i;
196
197 /* No font family name is set, try to retrieve font name and deduce
198 * the family name from that instead.
199 */
200 cf_str = CTFontDescriptorCopyAttribute (desc, kCTFontNameAttribute);
201 if (!cf_str)
202 {
203 if (may_fail)
204 return NULL;
205
206 /* This font is likely broken, return a default family name ... */
207 return g_strdup ("Sans");
208 }
209
210 buffer = gchar_from_cf_string (cf_str);
211 CFRelease (cf_str);
212
213 for (i = 0; i < strlen (buffer); i++)
214 if (buffer[i] == '-')
215 break;
216
217 if (i < strlen (buffer))
218 {
219 char *ret;
220
221 ret = g_strndup (buffer, i);
222 g_free (buffer);
223
224 return ret;
225 }
226 else
227 return buffer;
228 }
229 /* else */
230
231 buffer = gchar_from_cf_string (cf_str);
232 CFRelease (cf_str);
233
234 return buffer;
235 }
236
237 static char *
ct_font_descriptor_get_style_name(CTFontDescriptorRef desc)238 ct_font_descriptor_get_style_name (CTFontDescriptorRef desc)
239 {
240 CFStringRef cf_str;
241 char *buffer;
242
243 cf_str = CTFontDescriptorCopyAttribute (desc, kCTFontStyleNameAttribute);
244 if (!cf_str)
245 return NULL;
246
247 buffer = gchar_from_cf_string (cf_str);
248 CFRelease (cf_str);
249
250 return buffer;
251 }
252
253 static CTFontSymbolicTraits
ct_font_descriptor_get_traits(CTFontDescriptorRef desc)254 ct_font_descriptor_get_traits (CTFontDescriptorRef desc)
255 {
256 CFDictionaryRef dict;
257 CFNumberRef cf_number;
258 SInt64 traits;
259
260 /* This is interesting, the value stored is a CTFontSymbolicTraits which
261 * is defined as uint32_t. CFNumber does not have an obvious type which
262 * deals with unsigned values. Upon inspection with CFNumberGetType,
263 * it turns out this value is stored as SInt64, so we use that to
264 * obtain the value from the CFNumber.
265 */
266 dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
267 cf_number = (CFNumberRef)CFDictionaryGetValue (dict, kCTFontSymbolicTrait);
268 if (!CFNumberGetValue (cf_number, kCFNumberSInt64Type, &traits))
269 traits = 0;
270 CFRelease (dict);
271
272 return (CTFontSymbolicTraits)traits;
273 }
274
275 static CTFontDescriptorRef
cf_font_descriptor_copy_with_traits(CTFontDescriptorRef desc,const CTFontSymbolicTraits traits)276 cf_font_descriptor_copy_with_traits (CTFontDescriptorRef desc,
277 const CTFontSymbolicTraits traits)
278 {
279 CFMutableDictionaryRef dict, traits_dict;
280 CFDictionaryRef tmp;
281 CTFontDescriptorRef new_desc;
282 SInt64 tmp_traits;
283
284 tmp = CTFontDescriptorCopyAttributes (desc);
285 dict = CFDictionaryCreateMutableCopy (kCFAllocatorDefault, 0, tmp);
286 CFRelease (tmp);
287
288 tmp = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
289 traits_dict = CFDictionaryCreateMutableCopy (kCFAllocatorDefault, 0, tmp);
290 CFRelease (tmp);
291
292 tmp_traits = traits;
293 CFDictionarySetValue (traits_dict, (CFTypeRef) kCTFontSymbolicTrait,
294 CFNumberCreate (kCFAllocatorDefault, kCFNumberSInt64Type, &tmp_traits));
295
296 CFDictionarySetValue (dict, (CFTypeRef)kCTFontTraitsAttribute, traits_dict);
297
298 new_desc = CTFontDescriptorCreateCopyWithAttributes (desc, dict);
299 CFRelease (dict);
300
301 return new_desc;
302 }
303
304 static int
lerp(float x,float x1,float x2,int y1,int y2)305 lerp(float x, float x1, float x2, int y1, int y2) {
306 float dx = x2 - x1;
307 int dy = y2 - y1;
308 return y1 + (dy*(x-x1) + dx/2) / dx;
309 }
310
311 static PangoWeight
ct_font_descriptor_get_weight(CTFontDescriptorRef desc)312 ct_font_descriptor_get_weight (CTFontDescriptorRef desc)
313 {
314 CFDictionaryRef dict;
315 CFNumberRef cf_number;
316 CGFloat value;
317 PangoWeight weight = PANGO_WEIGHT_NORMAL;
318
319 dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
320 cf_number = (CFNumberRef)CFDictionaryGetValue (dict,
321 kCTFontWeightTrait);
322
323 if (cf_number != NULL && CFNumberGetValue (cf_number, kCFNumberCGFloatType, &value))
324 {
325 if (value < ct_weight_min || value > ct_weight_max)
326 {
327 /* This is really an error */
328 weight = PANGO_WEIGHT_NORMAL;
329 }
330 else
331 {
332 guint i;
333 for (i = 1; value > ct_weight_map[i].ct_weight; ++i)
334 ;
335
336 weight = lerp(value, ct_weight_map[i-1].ct_weight, ct_weight_map[i].ct_weight,
337 ct_weight_map[i-1].pango_weight, ct_weight_map[i].pango_weight);
338
339 }
340 }
341 else
342 weight = PANGO_WEIGHT_NORMAL;
343
344 CFRelease (dict);
345
346 return weight;
347 }
348
349 static gboolean
ct_font_descriptor_is_small_caps(CTFontDescriptorRef desc)350 ct_font_descriptor_is_small_caps (CTFontDescriptorRef desc)
351 {
352 CFIndex i, count;
353 CFArrayRef array;
354 CFStringRef str;
355 gboolean retval = FALSE;
356
357 /* See http://stackoverflow.com/a/4811371 for why this works and an
358 * explanation of the magic number "3" used below.
359 */
360 array = CTFontDescriptorCopyAttribute (desc, kCTFontFeaturesAttribute);
361 if (!array)
362 return FALSE;
363
364 str = CFStringCreateWithCString (NULL, "CTFeatureTypeIdentifier",
365 kCFStringEncodingASCII);
366
367 count = CFArrayGetCount (array);
368 for (i = 0; i < count; i++)
369 {
370 CFDictionaryRef dict = CFArrayGetValueAtIndex (array, i);
371 CFNumberRef num;
372
373 num = (CFNumberRef)CFDictionaryGetValue (dict, str);
374 if (num)
375 {
376 int value = 0;
377
378 if (CFNumberGetValue (num, kCFNumberSInt32Type, &value) &&
379 value == 3)
380 {
381 /* This font supports small caps. */
382 retval = TRUE;
383 break;
384 }
385 }
386 }
387
388 CFRelease (str);
389 CFRelease (array);
390
391 return retval;
392 }
393
394 static inline gboolean
pango_core_text_style_name_is_oblique(const char * style_name)395 pango_core_text_style_name_is_oblique (const char *style_name)
396 {
397 if (!style_name)
398 return FALSE;
399
400 return g_strrstr (style_name, "Oblique") != NULL;
401 }
402
403 PangoFontDescription *
_pango_core_text_font_description_from_ct_font_descriptor(CTFontDescriptorRef desc)404 _pango_core_text_font_description_from_ct_font_descriptor (CTFontDescriptorRef desc)
405 {
406 SInt64 font_traits;
407 char *family_name;
408 char *style_name;
409 PangoFontDescription *font_desc;
410
411 font_desc = pango_font_description_new ();
412
413 /* Family name */
414
415 /* FIXME: Should we actually retrieve the family name from the list of
416 * families in a font map?
417 */
418 family_name = ct_font_descriptor_get_family_name (desc, FALSE);
419 pango_font_description_set_family (font_desc, family_name);
420 g_free (family_name);
421
422 /* Weight */
423 pango_font_description_set_weight (font_desc,
424 ct_font_descriptor_get_weight (desc));
425
426 /* Font traits, style name; from this we deduce style and variant */
427 font_traits = ct_font_descriptor_get_traits (desc);
428 style_name = ct_font_descriptor_get_style_name (desc);
429
430 if ((font_traits & kCTFontItalicTrait) == kCTFontItalicTrait)
431 pango_font_description_set_style (font_desc, PANGO_STYLE_ITALIC);
432 else if (pango_core_text_style_name_is_oblique (style_name))
433 pango_font_description_set_style (font_desc, PANGO_STYLE_OBLIQUE);
434 else
435 pango_font_description_set_style (font_desc, PANGO_STYLE_NORMAL);
436
437 if ((font_traits & kCTFontCondensedTrait) == kCTFontCondensedTrait)
438 pango_font_description_set_stretch (font_desc, PANGO_STRETCH_CONDENSED);
439
440 if (ct_font_descriptor_is_small_caps (desc))
441 pango_font_description_set_variant (font_desc, PANGO_VARIANT_SMALL_CAPS);
442 else
443 pango_font_description_set_variant (font_desc, PANGO_VARIANT_NORMAL);
444
445 g_free (style_name);
446
447 return font_desc;
448 }
449
450 /*
451 * PangoCoreTextFace
452 */
453
454 static inline gboolean
pango_core_text_face_is_oblique(PangoCoreTextFace * face)455 pango_core_text_face_is_oblique (PangoCoreTextFace *face)
456 {
457 return pango_core_text_style_name_is_oblique (face->style_name);
458 }
459
460 static void
pango_core_text_face_make_italic(PangoCoreTextFace * ctface,gboolean synthetic_italic)461 pango_core_text_face_make_italic (PangoCoreTextFace *ctface,
462 gboolean synthetic_italic)
463 {
464 CTFontDescriptorRef new_desc;
465
466 ctface->traits |= kCTFontItalicTrait;
467 if (synthetic_italic)
468 ctface->synthetic_italic = TRUE;
469
470 /* Update the font descriptor */
471 new_desc = cf_font_descriptor_copy_with_traits (ctface->ctfontdescriptor,
472 ctface->traits);
473 CFRelease (ctface->ctfontdescriptor);
474 ctface->ctfontdescriptor = new_desc;
475 }
476
477 static inline PangoCoreTextFace *
pango_core_text_face_copy(const PangoCoreTextFace * old)478 pango_core_text_face_copy (const PangoCoreTextFace *old)
479 {
480 PangoCoreTextFace *face;
481
482 face = g_object_new (PANGO_TYPE_CORE_TEXT_FACE, NULL);
483 face->family = old->family;
484 face->ctfontdescriptor = CFRetain (old->ctfontdescriptor);
485 face->style_name = g_strdup (old->style_name);
486 face->weight = old->weight;
487 face->traits = old->traits;
488 face->synthetic_italic = old->synthetic_italic;
489
490 return face;
491 }
492
493 static inline PangoCoreTextFace *
pango_core_text_face_from_ct_font_descriptor(CTFontDescriptorRef desc)494 pango_core_text_face_from_ct_font_descriptor (CTFontDescriptorRef desc)
495 {
496 PangoCoreTextFace *face = g_object_new (PANGO_TYPE_CORE_TEXT_FACE,
497 NULL);
498
499 face->synthetic_italic = FALSE;
500
501 face->ctfontdescriptor = CFRetain (desc);
502
503 face->style_name = ct_font_descriptor_get_style_name (desc);
504 face->traits = ct_font_descriptor_get_traits (desc);
505 face->weight = ct_font_descriptor_get_weight (desc);
506
507 return face;
508 }
509
510 static PangoFontDescription *
pango_core_text_face_describe(PangoFontFace * face)511 pango_core_text_face_describe (PangoFontFace *face)
512 {
513 PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
514
515 return _pango_core_text_font_description_from_ct_font_descriptor (ctface->ctfontdescriptor);
516 }
517
518 static const char *
pango_core_text_face_get_face_name(PangoFontFace * face)519 pango_core_text_face_get_face_name (PangoFontFace *face)
520 {
521 PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (face);
522
523 return ctface->style_name;
524 }
525
526 static void
pango_core_text_face_list_sizes(PangoFontFace * face,int ** sizes,int * n_sizes)527 pango_core_text_face_list_sizes (PangoFontFace *face,
528 int **sizes,
529 int *n_sizes)
530 {
531 *n_sizes = 0;
532 if (sizes)
533 *sizes = NULL;
534 }
535
536 G_DEFINE_TYPE (PangoCoreTextFace, pango_core_text_face, PANGO_TYPE_FONT_FACE);
537
538 static void
pango_core_text_face_init(PangoCoreTextFace * face)539 pango_core_text_face_init (PangoCoreTextFace *face)
540 {
541 face->family = NULL;
542 }
543
544 static void
pango_core_text_face_finalize(GObject * object)545 pango_core_text_face_finalize (GObject *object)
546 {
547 PangoCoreTextFace *ctface = PANGO_CORE_TEXT_FACE (object);
548
549 g_free (ctface->style_name);
550 CFRelease (ctface->ctfontdescriptor);
551
552 G_OBJECT_CLASS (pango_core_text_face_parent_class)->finalize (object);
553 }
554
555 static gboolean
pango_core_text_face_is_synthesized(PangoFontFace * face)556 pango_core_text_face_is_synthesized (PangoFontFace *face)
557 {
558 PangoCoreTextFace *cface = PANGO_CORE_TEXT_FACE (face);
559
560 return cface->synthetic_italic;
561 }
562
563 static PangoFontFamily *
pango_core_text_face_get_family(PangoFontFace * face)564 pango_core_text_face_get_family (PangoFontFace *face)
565 {
566 PangoCoreTextFace *cface = PANGO_CORE_TEXT_FACE (face);
567
568 return PANGO_FONT_FAMILY (cface->family);
569 }
570
571 static void
pango_core_text_face_class_init(PangoCoreTextFaceClass * klass)572 pango_core_text_face_class_init (PangoCoreTextFaceClass *klass)
573 {
574 GObjectClass *object_class = (GObjectClass *)klass;
575 PangoFontFaceClass *pfclass = PANGO_FONT_FACE_CLASS(klass);
576
577 object_class->finalize = pango_core_text_face_finalize;
578
579 pfclass->describe = pango_core_text_face_describe;
580 pfclass->get_face_name = pango_core_text_face_get_face_name;
581 pfclass->list_sizes = pango_core_text_face_list_sizes;
582 pfclass->is_synthesized = pango_core_text_face_is_synthesized;
583 pfclass->get_family = pango_core_text_face_get_family;
584 }
585
586 /*
587 * PangoCoreTextFamily
588 */
589
590 static void
pango_core_text_family_list_faces(PangoFontFamily * family,PangoFontFace *** faces,int * n_faces)591 pango_core_text_family_list_faces (PangoFontFamily *family,
592 PangoFontFace ***faces,
593 int *n_faces)
594 {
595 PangoCoreTextFamily *ctfamily = PANGO_CORE_TEXT_FAMILY (family);
596
597 if (ctfamily->n_faces < 0)
598 {
599 GList *l;
600 GList *faces = NULL;
601 GList *synthetic_faces = NULL;
602 GHashTable *italic_faces;
603 const char *real_family = get_real_family (ctfamily->family_name);
604 CTFontCollectionRef collection;
605 CFArrayRef ctfaces;
606 CFArrayRef font_descriptors;
607 CFDictionaryRef attributes;
608 CFIndex i, count;
609
610 CFTypeRef keys[] = {
611 (CFTypeRef) kCTFontFamilyNameAttribute
612 };
613
614 CFStringRef values[] = {
615 CFStringCreateWithCString (kCFAllocatorDefault,
616 real_family,
617 kCFStringEncodingUTF8)
618 };
619
620 CTFontDescriptorRef descriptors[1];
621
622 attributes = CFDictionaryCreate (kCFAllocatorDefault,
623 (const void **)keys,
624 (const void **)values,
625 1,
626 &kCFTypeDictionaryKeyCallBacks,
627 &kCFTypeDictionaryValueCallBacks);
628 descriptors[0] = CTFontDescriptorCreateWithAttributes (attributes);
629 font_descriptors = CFArrayCreate (kCFAllocatorDefault,
630 (const void **)descriptors,
631 1,
632 &kCFTypeArrayCallBacks);
633 collection = CTFontCollectionCreateWithFontDescriptors (font_descriptors,
634 NULL);
635
636 ctfaces = CTFontCollectionCreateMatchingFontDescriptors (collection);
637
638 italic_faces = g_hash_table_new (g_direct_hash, g_direct_equal);
639
640 count = CFArrayGetCount (ctfaces);
641 for (i = 0; i < count; i++)
642 {
643 PangoCoreTextFace *face;
644 CTFontDescriptorRef desc = CFArrayGetValueAtIndex (ctfaces, i);
645
646 face = pango_core_text_face_from_ct_font_descriptor (desc);
647 face->family = ctfamily;
648
649 faces = g_list_prepend (faces, face);
650
651 if ((face->traits & kCTFontItalicTrait) == kCTFontItalicTrait ||
652 pango_core_text_face_is_oblique (face))
653 g_hash_table_insert (italic_faces,
654 GINT_TO_POINTER ((gint)face->weight),
655 face);
656 }
657
658 CFRelease (font_descriptors);
659 CFRelease (attributes);
660 CFRelease (ctfaces);
661
662 /* For all fonts for which a non-synthetic italic variant does
663 * not exist on the system, we create synthesized versions here.
664 */
665 for (l = faces; l; l = l->next)
666 {
667 PangoCoreTextFace *face = l->data;
668
669 if (!g_hash_table_lookup (italic_faces,
670 GINT_TO_POINTER ((gint)face->weight)))
671 {
672 PangoCoreTextFace *italic_face;
673
674 italic_face = pango_core_text_face_copy (face);
675
676 italic_face->family = ctfamily;
677 pango_core_text_face_make_italic (italic_face, TRUE);
678
679 /* Try to create a sensible face name. */
680 g_free (italic_face->style_name);
681 if (strcasecmp (face->style_name, "regular") == 0)
682 italic_face->style_name = g_strdup ("Oblique");
683 else
684 italic_face->style_name = g_strdup_printf ("%s Oblique",
685 face->style_name);
686
687 synthetic_faces = g_list_prepend (synthetic_faces, italic_face);
688 }
689 }
690
691 faces = g_list_concat (faces, synthetic_faces);
692
693 ctfamily->n_faces = g_list_length (faces);
694 ctfamily->faces = g_new (PangoFontFace *, ctfamily->n_faces);
695
696 for (l = faces, i = 0; l; l = l->next, i++)
697 ctfamily->faces[i] = l->data;
698
699 g_list_free (faces);
700 g_hash_table_destroy (italic_faces);
701 }
702
703 if (n_faces)
704 *n_faces = ctfamily->n_faces;
705
706 if (faces)
707 *faces = g_memdup2 (ctfamily->faces, ctfamily->n_faces * sizeof (PangoFontFace *));
708 }
709
710 static const char *
pango_core_text_family_get_name(PangoFontFamily * family)711 pango_core_text_family_get_name (PangoFontFamily *family)
712 {
713 PangoCoreTextFamily *ctfamily = PANGO_CORE_TEXT_FAMILY (family);
714
715 return ctfamily->family_name;
716 }
717
718 static gboolean
pango_core_text_family_is_monospace(PangoFontFamily * family)719 pango_core_text_family_is_monospace (PangoFontFamily *family)
720 {
721 PangoCoreTextFamily *ctfamily = PANGO_CORE_TEXT_FAMILY (family);
722
723 return ctfamily->is_monospace;
724 }
725
726 G_DEFINE_TYPE (PangoCoreTextFamily, pango_core_text_family, PANGO_TYPE_FONT_FAMILY);
727
728 static void
pango_core_text_family_finalize(GObject * object)729 pango_core_text_family_finalize (GObject *object)
730 {
731 PangoCoreTextFamily *family = PANGO_CORE_TEXT_FAMILY (object);
732 int i;
733
734 g_free (family->family_name);
735
736 if (family->n_faces != -1)
737 {
738 for (i = 0; i < family->n_faces; i++)
739 g_object_unref (family->faces[i]);
740
741 g_free (family->faces);
742 }
743
744 G_OBJECT_CLASS (pango_core_text_family_parent_class)->finalize (object);
745 }
746
747
748 static void
pango_core_text_family_class_init(PangoCoreTextFamilyClass * klass)749 pango_core_text_family_class_init (PangoCoreTextFamilyClass *klass)
750 {
751 GObjectClass *object_class = (GObjectClass *)klass;
752 PangoFontFamilyClass *pfclass = PANGO_FONT_FAMILY_CLASS(klass);
753
754 object_class->finalize = pango_core_text_family_finalize;
755
756 pfclass->list_faces = pango_core_text_family_list_faces;
757 pfclass->get_name = pango_core_text_family_get_name;
758 pfclass->is_monospace = pango_core_text_family_is_monospace;
759 }
760
761 static void
pango_core_text_family_init(PangoCoreTextFamily * family)762 pango_core_text_family_init (PangoCoreTextFamily *family)
763 {
764 family->n_faces = -1;
765 }
766
767
768
769 static void pango_core_text_font_map_class_init (PangoCoreTextFontMapClass *class);
770 static void pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap);
771
772
773 G_DEFINE_TYPE (PangoCoreTextFontMap, pango_core_text_font_map, PANGO_TYPE_FONT_MAP);
774
775 static void
pango_core_text_font_map_finalize(GObject * object)776 pango_core_text_font_map_finalize (GObject *object)
777 {
778 PangoCoreTextFontMap *fontmap = PANGO_CORE_TEXT_FONT_MAP (object);
779
780 g_hash_table_destroy (fontmap->fontset_hash);
781 g_hash_table_destroy (fontmap->font_hash);
782 g_hash_table_destroy (fontmap->families);
783
784 G_OBJECT_CLASS (pango_core_text_font_map_parent_class)->finalize (object);
785 }
786
787 /* Fowler / Noll / Vo (FNV) Hash (http://www.isthe.com/chongo/tech/comp/fnv/)
788 *
789 * Not necessarily better than a lot of other hashes, but should be OK, and
790 * well tested with binary data.
791 */
792
793 #define FNV_32_PRIME ((guint32)0x01000193)
794 #define FNV1_32_INIT ((guint32)0x811c9dc5)
795
796 static guint32
hash_bytes_fnv(unsigned char * buffer,int len,guint32 hval)797 hash_bytes_fnv (unsigned char *buffer,
798 int len,
799 guint32 hval)
800 {
801 while (len--)
802 {
803 hval *= FNV_32_PRIME;
804 hval ^= *buffer++;
805 }
806
807 return hval;
808 }
809
810 static void
get_context_matrix(PangoContext * context,PangoMatrix * matrix)811 get_context_matrix (PangoContext *context,
812 PangoMatrix *matrix)
813 {
814 const PangoMatrix *set_matrix;
815 const PangoMatrix identity = PANGO_MATRIX_INIT;
816
817 if (context)
818 set_matrix = pango_context_get_matrix (context);
819 else
820 set_matrix = NULL;
821
822 if (set_matrix)
823 *matrix = *set_matrix;
824 else
825 *matrix = identity;
826 }
827
828 /*
829 * Helper functions for PangoCoreTextFontsetKey
830 */
831 static const double ppi = 72.0; /* typographic points per inch */
832
833 static double
pango_core_text_font_map_get_resolution(PangoCoreTextFontMap * fontmap,PangoContext * context)834 pango_core_text_font_map_get_resolution (PangoCoreTextFontMap *fontmap,
835 PangoContext *context)
836 {
837 if (PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->get_resolution)
838 return PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->get_resolution (fontmap, context);
839
840 /* FIXME: acquire DPI from CoreText using some deafault font */
841 g_warning ("FIXME: returning default DPI");
842
843 return ppi;
844 }
845
846 static int
get_scaled_size(PangoCoreTextFontMap * fontmap,PangoContext * context,const PangoFontDescription * desc)847 get_scaled_size (PangoCoreTextFontMap *fontmap,
848 PangoContext *context,
849 const PangoFontDescription *desc)
850 {
851 double size = pango_font_description_get_size (desc);
852 PangoMatrix *matrix = pango_context_get_matrix (context);
853 double scale_factor = pango_matrix_get_font_scale_factor (matrix);
854
855 if (!pango_font_description_get_size_is_absolute(desc))
856 {
857 double dpi = pango_core_text_font_map_get_resolution (fontmap, context);
858 size *= (dpi/ppi);
859 }
860
861 return .5 + scale_factor * size;
862 }
863
864
865 /*
866 * PangoCoreTextFontsetKey
867 */
868 struct _PangoCoreTextFontsetKey
869 {
870 PangoCoreTextFontMap *fontmap;
871 PangoLanguage *language;
872 PangoFontDescription *desc;
873 PangoMatrix matrix;
874 int pointsize;
875 double resolution;
876 PangoGravity gravity;
877 gpointer context_key;
878 };
879
880 static void
pango_core_text_fontset_key_init(PangoCoreTextFontsetKey * key,PangoCoreTextFontMap * fontmap,PangoContext * context,const PangoFontDescription * desc,PangoLanguage * language)881 pango_core_text_fontset_key_init (PangoCoreTextFontsetKey *key,
882 PangoCoreTextFontMap *fontmap,
883 PangoContext *context,
884 const PangoFontDescription *desc,
885 PangoLanguage *language)
886 {
887 if (!language && context)
888 language = pango_context_get_language (context);
889
890 key->fontmap = fontmap;
891 get_context_matrix (context, &key->matrix);
892 key->language = language;
893 key->pointsize = get_scaled_size (fontmap, context, desc);
894 key->resolution = pango_core_text_font_map_get_resolution (fontmap, context);
895 key->gravity = pango_context_get_gravity (context);
896 key->desc = pango_font_description_copy_static (desc);
897 pango_font_description_unset_fields (key->desc, PANGO_FONT_MASK_SIZE);
898
899 if (context && PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->context_key_get)
900 key->context_key = (gpointer)PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap)->context_key_get (fontmap, context);
901 else
902 key->context_key = NULL;
903 }
904
905 static PangoCoreTextFontsetKey *
pango_core_text_fontset_key_copy(const PangoCoreTextFontsetKey * old)906 pango_core_text_fontset_key_copy (const PangoCoreTextFontsetKey *old)
907 {
908 PangoCoreTextFontsetKey *key = g_slice_new (PangoCoreTextFontsetKey);
909
910 key->fontmap = old->fontmap;
911 key->matrix = old->matrix;
912 key->language = old->language;
913 key->pointsize = old->pointsize;
914 key->resolution = old->resolution;
915 key->gravity = old->gravity;
916 key->desc = pango_font_description_copy (old->desc);
917 if (old->context_key)
918 key->context_key = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap, old->context_key);
919 else
920 key->context_key = NULL;
921
922 return key;
923 }
924
925 static void
pango_core_text_fontset_key_free(PangoCoreTextFontsetKey * key)926 pango_core_text_fontset_key_free (PangoCoreTextFontsetKey *key)
927 {
928 pango_font_description_free (key->desc);
929
930 if (key->context_key)
931 PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap, key->context_key);
932
933 g_slice_free (PangoCoreTextFontsetKey, key);
934 }
935
936 static guint
pango_core_text_fontset_key_hash(const PangoCoreTextFontsetKey * key)937 pango_core_text_fontset_key_hash (const PangoCoreTextFontsetKey *key)
938 {
939 guint32 hash = FNV1_32_INIT;
940
941 hash = hash_bytes_fnv ((unsigned char *)(&key->matrix), sizeof (double) * 4, hash);
942 hash ^= hash_bytes_fnv ((unsigned char *)(&key->resolution), sizeof (double), hash);
943
944 if (key->context_key)
945 hash ^= PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap, key->context_key);
946
947 return (hash ^
948 GPOINTER_TO_UINT (key->language) ^
949 pango_font_description_hash (key->desc));
950 }
951
952 static gboolean
pango_core_text_fontset_key_equal(const PangoCoreTextFontsetKey * key_a,const PangoCoreTextFontsetKey * key_b)953 pango_core_text_fontset_key_equal (const PangoCoreTextFontsetKey *key_a,
954 const PangoCoreTextFontsetKey *key_b)
955 {
956 if (key_a->language == key_b->language &&
957 key_a->pointsize == key_b->pointsize &&
958 key_a->resolution == key_b->resolution &&
959 key_a->gravity == key_b->gravity &&
960 pango_font_description_equal (key_a->desc, key_b->desc) &&
961 memcmp ((void *)&key_a->matrix, (void *)&key_b->matrix, 4 * sizeof (double)) == 0)
962 {
963 if (key_a->context_key)
964 return PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
965 key_a->context_key,
966 key_b->context_key);
967 else
968 return key_a->context_key == key_b->context_key;
969 }
970 /* else */
971 return FALSE;
972 }
973
974 static PangoLanguage *
pango_core_text_fontset_key_get_language(const PangoCoreTextFontsetKey * key)975 pango_core_text_fontset_key_get_language (const PangoCoreTextFontsetKey *key)
976 {
977 return key->language;
978 }
979
980 static const PangoMatrix *
pango_core_text_fontset_key_get_matrix(const PangoCoreTextFontsetKey * key)981 pango_core_text_fontset_key_get_matrix (const PangoCoreTextFontsetKey *key)
982 {
983 return &key->matrix;
984 }
985
986 static PangoGravity
pango_core_text_fontset_key_get_gravity(const PangoCoreTextFontsetKey * key)987 pango_core_text_fontset_key_get_gravity (const PangoCoreTextFontsetKey *key)
988 {
989 return key->gravity;
990 }
991
992 static gpointer
pango_core_text_fontset_key_get_context_key(const PangoCoreTextFontsetKey * key)993 pango_core_text_fontset_key_get_context_key (const PangoCoreTextFontsetKey *key)
994 {
995 return key->context_key;
996 }
997
998 /*
999 * PangoCoreTextFontKey
1000 */
1001 struct _PangoCoreTextFontKey
1002 {
1003 PangoCoreTextFontMap *fontmap;
1004 CTFontDescriptorRef ctfontdescriptor;
1005 PangoMatrix matrix;
1006 PangoGravity gravity;
1007 int pointsize;
1008 double resolution;
1009 gboolean synthetic_italic;
1010 gpointer context_key;
1011 };
1012
1013 static void
pango_core_text_font_key_init(PangoCoreTextFontKey * key,PangoCoreTextFontMap * ctfontmap,PangoCoreTextFontsetKey * fontset_key,CTFontDescriptorRef ctdescriptor,gboolean synthetic_italic)1014 pango_core_text_font_key_init (PangoCoreTextFontKey *key,
1015 PangoCoreTextFontMap *ctfontmap,
1016 PangoCoreTextFontsetKey *fontset_key,
1017 CTFontDescriptorRef ctdescriptor,
1018 gboolean synthetic_italic)
1019 {
1020 key->fontmap = ctfontmap;
1021 key->ctfontdescriptor = ctdescriptor;
1022 key->matrix = *pango_core_text_fontset_key_get_matrix (fontset_key);
1023 key->pointsize = fontset_key->pointsize;
1024 key->resolution = fontset_key->resolution;
1025 key->synthetic_italic = synthetic_italic;
1026 key->gravity = pango_core_text_fontset_key_get_gravity (fontset_key);
1027 key->context_key = pango_core_text_fontset_key_get_context_key (fontset_key);
1028 }
1029
1030 static PangoCoreTextFontKey *
pango_core_text_font_key_copy(const PangoCoreTextFontKey * old)1031 pango_core_text_font_key_copy (const PangoCoreTextFontKey *old)
1032 {
1033 PangoCoreTextFontKey *key = g_slice_new (PangoCoreTextFontKey);
1034
1035 key->fontmap = old->fontmap;
1036 key->ctfontdescriptor = old->ctfontdescriptor;
1037 CFRetain (key->ctfontdescriptor);
1038 key->matrix = old->matrix;
1039 key->pointsize = old->pointsize;
1040 key->resolution = old->resolution;
1041 key->synthetic_italic = old->synthetic_italic;
1042 key->gravity = old->gravity;
1043 if (old->context_key)
1044 key->context_key = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap, old->context_key);
1045 else
1046 key->context_key = NULL;
1047
1048 return key;
1049 }
1050
1051 static void
pango_core_text_font_key_free(PangoCoreTextFontKey * key)1052 pango_core_text_font_key_free (PangoCoreTextFontKey *key)
1053 {
1054 if (key->ctfontdescriptor)
1055 CFRelease (key->ctfontdescriptor);
1056
1057 if (key->context_key)
1058 PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap, key->context_key);
1059
1060 g_slice_free (PangoCoreTextFontKey, key);
1061 }
1062
1063 static guint
pango_core_text_font_key_hash(const PangoCoreTextFontKey * key)1064 pango_core_text_font_key_hash (const PangoCoreTextFontKey *key)
1065 {
1066 guint32 hash = FNV1_32_INIT;
1067
1068 /* Not everything is included here, probably good enough for a hash */
1069
1070 hash = hash_bytes_fnv ((unsigned char *)(&key->matrix), sizeof (double) * 4, hash);
1071
1072 if (key->context_key)
1073 hash ^= PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap, key->context_key);
1074
1075 return (hash ^ CFHash (key->ctfontdescriptor));
1076 }
1077
1078 static gboolean
pango_core_text_font_key_equal(const PangoCoreTextFontKey * key_a,const PangoCoreTextFontKey * key_b)1079 pango_core_text_font_key_equal (const PangoCoreTextFontKey *key_a,
1080 const PangoCoreTextFontKey *key_b)
1081 {
1082 if (CFEqual (key_a->ctfontdescriptor, key_b->ctfontdescriptor) &&
1083 memcmp (&key_a->matrix, &key_b->matrix, 4 * sizeof (double)) == 0 &&
1084 key_a->gravity == key_b->gravity &&
1085 key_a->pointsize == key_b->pointsize &&
1086 key_a->resolution == key_b->resolution &&
1087 key_a->synthetic_italic == key_b->synthetic_italic)
1088 {
1089 if (key_a->context_key && key_b->context_key)
1090 return PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (key_a->fontmap)->context_key_equal (key_a->fontmap,
1091 key_a->context_key,
1092 key_b->context_key);
1093 else
1094 return key_a->context_key == key_b->context_key;
1095 }
1096 else
1097 return FALSE;
1098 }
1099
1100 int
pango_core_text_font_key_get_size(const PangoCoreTextFontKey * key)1101 pango_core_text_font_key_get_size (const PangoCoreTextFontKey *key)
1102 {
1103 return key->pointsize;
1104 }
1105
1106 double
pango_core_text_font_key_get_resolution(const PangoCoreTextFontKey * key)1107 pango_core_text_font_key_get_resolution (const PangoCoreTextFontKey *key)
1108 {
1109 return key->resolution;
1110 }
1111
1112 gboolean
pango_core_text_font_key_get_synthetic_italic(const PangoCoreTextFontKey * key)1113 pango_core_text_font_key_get_synthetic_italic (const PangoCoreTextFontKey *key)
1114 {
1115 return key->synthetic_italic;
1116 }
1117
1118 gpointer
pango_core_text_font_key_get_context_key(const PangoCoreTextFontKey * key)1119 pango_core_text_font_key_get_context_key (const PangoCoreTextFontKey *key)
1120 {
1121 return key->context_key;
1122 }
1123
1124 const PangoMatrix *
pango_core_text_font_key_get_matrix(const PangoCoreTextFontKey * key)1125 pango_core_text_font_key_get_matrix (const PangoCoreTextFontKey *key)
1126 {
1127 return &key->matrix;
1128 }
1129
1130 PangoGravity
pango_core_text_font_key_get_gravity(const PangoCoreTextFontKey * key)1131 pango_core_text_font_key_get_gravity (const PangoCoreTextFontKey *key)
1132 {
1133 return key->gravity;
1134 }
1135
1136 CTFontDescriptorRef
pango_core_text_font_key_get_ctfontdescriptor(const PangoCoreTextFontKey * key)1137 pango_core_text_font_key_get_ctfontdescriptor (const PangoCoreTextFontKey *key)
1138 {
1139 return key->ctfontdescriptor;
1140 }
1141
1142
1143
1144 static void
pango_core_text_font_map_add(PangoCoreTextFontMap * ctfontmap,PangoCoreTextFontKey * key,PangoCoreTextFont * ctfont)1145 pango_core_text_font_map_add (PangoCoreTextFontMap *ctfontmap,
1146 PangoCoreTextFontKey *key,
1147 PangoCoreTextFont *ctfont)
1148 {
1149 PangoCoreTextFontKey *key_copy;
1150
1151 _pango_core_text_font_set_font_map (ctfont, ctfontmap);
1152
1153 key_copy = pango_core_text_font_key_copy (key);
1154 _pango_core_text_font_set_font_key (ctfont, key_copy);
1155 g_hash_table_insert (ctfontmap->font_hash, key_copy, ctfont);
1156 }
1157
1158 static PangoCoreTextFont *
pango_core_text_font_map_new_font(PangoCoreTextFontMap * fontmap,PangoCoreTextFontsetKey * fontset_key,CTFontDescriptorRef ctfontdescriptor,gboolean synthetic_italic)1159 pango_core_text_font_map_new_font (PangoCoreTextFontMap *fontmap,
1160 PangoCoreTextFontsetKey *fontset_key,
1161 CTFontDescriptorRef ctfontdescriptor,
1162 gboolean synthetic_italic)
1163 {
1164 PangoCoreTextFontMapClass *klass;
1165 PangoCoreTextFont *font;
1166 PangoCoreTextFontKey key;
1167
1168 pango_core_text_font_key_init (&key, fontmap, fontset_key, ctfontdescriptor,
1169 synthetic_italic);
1170
1171 font = g_hash_table_lookup (fontmap->font_hash, &key);
1172 if (font)
1173 return g_object_ref (font);
1174
1175 /* Call create_font */
1176 klass = PANGO_CORE_TEXT_FONT_MAP_GET_CLASS (fontmap);
1177 font = klass->create_font (fontmap, &key);
1178
1179 if (!font)
1180 return NULL;
1181
1182 pango_core_text_font_map_add (fontmap, &key, font);
1183
1184 return font;
1185 }
1186
1187 static gboolean
find_best_match(PangoCoreTextFamily * font_family,const PangoFontDescription * description,PangoCoreTextFace ** best_face)1188 find_best_match (PangoCoreTextFamily *font_family,
1189 const PangoFontDescription *description,
1190 PangoCoreTextFace **best_face)
1191 {
1192 PangoFontDescription *new_desc;
1193 PangoFontDescription *best_description = NULL;
1194 int i;
1195
1196 *best_face = NULL;
1197
1198 for (i = 0; i < font_family->n_faces; i++)
1199 {
1200 new_desc = pango_font_face_describe (font_family->faces[i]);
1201 pango_font_description_set_gravity (new_desc, pango_font_description_get_gravity (description));
1202
1203 if (pango_font_description_better_match (description, best_description,
1204 new_desc))
1205 {
1206 pango_font_description_free (best_description);
1207 best_description = new_desc;
1208 *best_face = (PangoCoreTextFace *)font_family->faces[i];
1209 }
1210 else
1211 pango_font_description_free (new_desc);
1212 }
1213
1214 if (best_description)
1215 {
1216 pango_font_description_free (best_description);
1217 return TRUE;
1218 }
1219 return FALSE;
1220 }
1221
1222 static gboolean
get_first_font(PangoFontset * fontset G_GNUC_UNUSED,PangoFont * font,gpointer data)1223 get_first_font (PangoFontset *fontset G_GNUC_UNUSED,
1224 PangoFont *font,
1225 gpointer data)
1226 {
1227 *(PangoFont **)data = font;
1228
1229 return TRUE;
1230 }
1231
1232 static guint
pango_core_text_font_map_get_serial(PangoFontMap * fontmap)1233 pango_core_text_font_map_get_serial (PangoFontMap *fontmap)
1234 {
1235 PangoCoreTextFontMap *ctfontmap = PANGO_CORE_TEXT_FONT_MAP (fontmap);
1236
1237 return ctfontmap->serial;
1238 }
1239
1240 static void
pango_core_text_font_map_changed(PangoFontMap * fontmap)1241 pango_core_text_font_map_changed (PangoFontMap *fontmap)
1242 {
1243 PangoCoreTextFontMap *ctfontmap = PANGO_CORE_TEXT_FONT_MAP (fontmap);
1244
1245 ctfontmap->serial++;
1246 if (ctfontmap->serial == 0)
1247 ctfontmap->serial++;
1248 }
1249
1250 static PangoFont *
pango_core_text_font_map_load_font(PangoFontMap * fontmap,PangoContext * context,const PangoFontDescription * description)1251 pango_core_text_font_map_load_font (PangoFontMap *fontmap,
1252 PangoContext *context,
1253 const PangoFontDescription *description)
1254 {
1255 PangoLanguage *language;
1256 PangoFontset *fontset;
1257 PangoFont *font = NULL;
1258
1259 if (context)
1260 language = pango_context_get_language (context);
1261 else
1262 language = NULL;
1263
1264 fontset = pango_font_map_load_fontset (fontmap, context,
1265 description, language);
1266
1267 if (fontset)
1268 {
1269 pango_fontset_foreach (fontset, get_first_font, &font);
1270
1271 if (font)
1272 g_object_ref (font);
1273
1274 g_object_unref (fontset);
1275 }
1276
1277 return font;
1278 }
1279
1280 static void
list_families_foreach(gpointer key,gpointer value,gpointer user_data)1281 list_families_foreach (gpointer key,
1282 gpointer value,
1283 gpointer user_data)
1284 {
1285 GSList **list = user_data;
1286
1287 *list = g_slist_prepend (*list, value);
1288 }
1289
1290 static void
pango_core_text_font_map_list_families(PangoFontMap * fontmap,PangoFontFamily *** families,int * n_families)1291 pango_core_text_font_map_list_families (PangoFontMap *fontmap,
1292 PangoFontFamily ***families,
1293 int *n_families)
1294 {
1295 GSList *family_list = NULL;
1296 GSList *tmp_list;
1297 PangoCoreTextFontMap *ctfontmap = (PangoCoreTextFontMap *)fontmap;
1298
1299 if (!n_families)
1300 return;
1301
1302 g_hash_table_foreach (ctfontmap->families,
1303 list_families_foreach, &family_list);
1304
1305 *n_families = g_slist_length (family_list);
1306
1307 if (families)
1308 {
1309 int i = 0;
1310
1311 *families = g_new (PangoFontFamily *, *n_families);
1312
1313 tmp_list = family_list;
1314 while (tmp_list)
1315 {
1316 (*families)[i] = tmp_list->data;
1317 i++;
1318 tmp_list = tmp_list->next;
1319 }
1320 }
1321
1322 g_slist_free (family_list);
1323 }
1324
1325 static PangoFontset *
pango_core_text_font_map_load_fontset(PangoFontMap * fontmap,PangoContext * context,const PangoFontDescription * desc,PangoLanguage * language)1326 pango_core_text_font_map_load_fontset (PangoFontMap *fontmap,
1327 PangoContext *context,
1328 const PangoFontDescription *desc,
1329 PangoLanguage *language)
1330 {
1331 PangoCoreTextFontset *fontset;
1332 PangoCoreTextFontsetKey key;
1333 PangoCoreTextFontMap *ctfontmap = PANGO_CORE_TEXT_FONT_MAP (fontmap);
1334 static gboolean warned_full_fallback = FALSE; /* MT-safe */
1335
1336 pango_core_text_fontset_key_init (&key, ctfontmap,
1337 context, desc, language);
1338
1339 fontset = g_hash_table_lookup (ctfontmap->fontset_hash, &key);
1340
1341 if (G_UNLIKELY (!fontset))
1342 {
1343 gboolean insert_in_hash = TRUE;
1344
1345 fontset = pango_core_text_fontset_new (&key, desc);
1346
1347 if (G_UNLIKELY (!fontset))
1348 {
1349 /* If no font(set) could be loaded, we fallback to "Apple Color
1350 * Emoji" for emoji font, fallback to "Sans" for other fonts,
1351 * which should always work on Mac. We try to adhere to the
1352 * requested style at first.
1353 */
1354 PangoFontDescription *tmp_desc;
1355
1356 /* Cannot use pango_core_text_fontset_key_free() here */
1357 pango_font_description_free (key.desc);
1358
1359 tmp_desc = pango_font_description_copy_static (desc);
1360 if (strcmp (pango_font_description_get_family (tmp_desc), "emoji") == 0)
1361 pango_font_description_set_family_static (tmp_desc, "Apple Color Emoji");
1362 else
1363 pango_font_description_set_family_static (tmp_desc, "Sans");
1364
1365 pango_core_text_fontset_key_init (&key, ctfontmap, context, tmp_desc,
1366 language);
1367
1368 fontset = g_hash_table_lookup (ctfontmap->fontset_hash, &key);
1369 if (G_LIKELY (fontset))
1370 insert_in_hash = FALSE;
1371 else
1372 fontset = pango_core_text_fontset_new (&key, tmp_desc);
1373
1374 if (G_UNLIKELY (!fontset))
1375 {
1376 /* We could not load Sans in the requested style; reset
1377 * variant, weight and stretch to sensible defaults (we should
1378 * be able to adhere the PangoStyle with "Sans").
1379 */
1380 pango_font_description_set_variant (tmp_desc, PANGO_VARIANT_NORMAL);
1381 pango_font_description_set_weight (tmp_desc, PANGO_WEIGHT_NORMAL);
1382 pango_font_description_set_stretch (tmp_desc, PANGO_STRETCH_NORMAL);
1383
1384 if (!warned_full_fallback)
1385 {
1386 char *ctmp;
1387
1388 warned_full_fallback = TRUE;
1389
1390 ctmp = pango_font_description_to_string (desc);
1391 g_warning ("couldn't load font \"%s\", modified variant/"
1392 "weight/stretch as fallback, expect ugly output.",
1393 ctmp);
1394 g_free (ctmp);
1395 }
1396
1397 fontset = g_hash_table_lookup (ctfontmap->fontset_hash, &key);
1398 if (G_LIKELY (fontset))
1399 insert_in_hash = FALSE;
1400 else
1401 fontset = pango_core_text_fontset_new (&key, tmp_desc);
1402
1403 if (G_UNLIKELY (!fontset))
1404 {
1405 /* If even that failed, display a sensible error message
1406 * and bail out, in contrast to failing randomly.
1407 */
1408 g_error ("Could not load fallback font, bailing out.");
1409 }
1410 }
1411
1412 if (tmp_desc)
1413 pango_font_description_free (tmp_desc);
1414 }
1415
1416 if (insert_in_hash)
1417 g_hash_table_insert (ctfontmap->fontset_hash,
1418 pango_core_text_fontset_get_key (fontset),
1419 fontset);
1420 }
1421
1422 /* Cannot use pango_core_text_fontset_key_free() here */
1423 pango_font_description_free (key.desc);
1424
1425 return g_object_ref (fontset);
1426 }
1427
1428 static void
pango_core_text_font_map_init(PangoCoreTextFontMap * ctfontmap)1429 pango_core_text_font_map_init (PangoCoreTextFontMap *ctfontmap)
1430 {
1431 PangoCoreTextFamily *family;
1432 CTFontCollectionRef collection;
1433 CFArrayRef ctfaces;
1434 CFIndex i, count;
1435
1436 ctfontmap->serial = 1;
1437 ctfontmap->families = g_hash_table_new_full (g_str_hash, g_str_equal,
1438 g_free, g_object_unref);
1439
1440
1441 ctfontmap->font_hash = g_hash_table_new_full ((GHashFunc)pango_core_text_font_key_hash,
1442 (GEqualFunc)pango_core_text_font_key_equal,
1443 (GDestroyNotify)pango_core_text_font_key_free,
1444 NULL);
1445
1446 ctfontmap->fontset_hash = g_hash_table_new_full ((GHashFunc)pango_core_text_fontset_key_hash,
1447 (GEqualFunc)pango_core_text_fontset_key_equal,
1448 NULL,
1449 (GDestroyNotify)g_object_unref);
1450
1451 collection = CTFontCollectionCreateFromAvailableFonts (0);
1452 ctfaces = CTFontCollectionCreateMatchingFontDescriptors (collection);
1453 count = CFArrayGetCount (ctfaces);
1454
1455 for (i = 0; i < count; i++)
1456 {
1457 SInt64 font_traits;
1458 char *buffer;
1459 char *family_name;
1460 CFNumberRef number;
1461 CFDictionaryRef dict;
1462 CTFontDescriptorRef desc = CFArrayGetValueAtIndex (ctfaces, i);
1463
1464 buffer = ct_font_descriptor_get_family_name (desc, TRUE);
1465 if (!buffer)
1466 continue;
1467
1468 family_name = g_utf8_casefold (buffer, -1);
1469
1470 family = g_hash_table_lookup (ctfontmap->families, family_name);
1471 if (!family)
1472 {
1473 family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
1474 g_hash_table_insert (ctfontmap->families, g_strdup (family_name),
1475 family);
1476
1477 family->family_name = g_strdup (buffer);
1478 }
1479
1480 g_free (buffer);
1481
1482 g_free (family_name);
1483
1484 /* We assume that all faces in the family are monospaced or none. */
1485 dict = CTFontDescriptorCopyAttribute (desc, kCTFontTraitsAttribute);
1486 number = (CFNumberRef)CFDictionaryGetValue (dict,
1487 kCTFontSymbolicTrait);
1488
1489 if (CFNumberGetValue (number, kCFNumberSInt64Type, &font_traits))
1490 {
1491 if ((font_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait)
1492 family->is_monospace = TRUE;
1493 }
1494
1495 CFRelease (dict);
1496 }
1497
1498 /* Insert aliases */
1499 /* Keep in sync with get_real_family() */
1500 gchar* aliases[] = {
1501 "Sans", "Serif", "system-ui", "cursive", "fantasy", "Monospace"
1502 };
1503
1504 for (int i = 0; i < G_N_ELEMENTS(aliases); i++)
1505 {
1506 family = g_object_new (PANGO_TYPE_CORE_TEXT_FAMILY, NULL);
1507 family->family_name = g_strdup (aliases[i]);
1508 if (g_ascii_strcasecmp (family->family_name, "Monospace") == 0)
1509 family->is_monospace = TRUE;
1510 g_hash_table_insert (ctfontmap->families,
1511 g_utf8_casefold (family->family_name, -1), family);
1512 }
1513 }
1514
1515 static PangoFontFace *
pango_core_text_font_map_get_face(PangoFontMap * fontmap,PangoFont * font)1516 pango_core_text_font_map_get_face (PangoFontMap *fontmap,
1517 PangoFont *font)
1518 {
1519 PangoCoreTextFont *cfont = PANGO_CORE_TEXT_FONT (font);
1520
1521 return PANGO_FONT_FACE (_pango_core_text_font_get_face (cfont));
1522 }
1523
1524 static void
pango_core_text_font_map_class_init(PangoCoreTextFontMapClass * class)1525 pango_core_text_font_map_class_init (PangoCoreTextFontMapClass *class)
1526 {
1527 GObjectClass *object_class = G_OBJECT_CLASS (class);
1528 PangoFontMapClass *fontmap_class = PANGO_FONT_MAP_CLASS (class);
1529
1530 object_class->finalize = pango_core_text_font_map_finalize;
1531
1532 fontmap_class->load_font = pango_core_text_font_map_load_font;
1533 fontmap_class->list_families = pango_core_text_font_map_list_families;
1534 fontmap_class->load_fontset = pango_core_text_font_map_load_fontset;
1535 fontmap_class->shape_engine_type = PANGO_RENDER_TYPE_CORE_TEXT;
1536 fontmap_class->get_serial = pango_core_text_font_map_get_serial;
1537 fontmap_class->changed = pango_core_text_font_map_changed;
1538 fontmap_class->get_face = pango_core_text_font_map_get_face;
1539 }
1540
1541 /*
1542 * PangoCoreTextFontSet
1543 */
1544
1545 static void pango_core_text_fontset_finalize (GObject *object);
1546 static void pango_core_text_fontset_init (PangoCoreTextFontset *fontset);
1547 static PangoLanguage * pango_core_text_fontset_get_language (PangoFontset *fontset);
1548 static PangoFont * pango_core_text_fontset_get_font (PangoFontset *fontset,
1549 guint wc);
1550 static void pango_core_text_fontset_foreach (PangoFontset *fontset,
1551 PangoFontsetForeachFunc func,
1552 gpointer data);
1553
1554 struct _PangoCoreTextFontset
1555 {
1556 PangoFontset parent_instance;
1557
1558 const gchar *orig_family;
1559 PangoFontDescription *orig_description;
1560
1561 PangoCoreTextFontsetKey *key;
1562 CFArrayRef cascade_list;
1563
1564 GPtrArray *fonts;
1565 GPtrArray *coverages;
1566 guint real_font_count;
1567 };
1568
1569 struct _PangoCoreTextFontsetClass
1570 {
1571 PangoFontsetClass parent_instance;
1572 };
1573
1574 typedef struct _PangoCoreTextFontsetClass PangoCoreTextFontsetClass;
1575
1576 G_DEFINE_TYPE (PangoCoreTextFontset,
1577 pango_core_text_fontset,
1578 PANGO_TYPE_FONTSET);
1579
1580 #if !defined(MAC_OS_X_VERSION_10_8) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
1581 /* This symbol does exist in the CoreText library shipped with Snow
1582 * Leopard and Lion, however, it is not found in the public header files.
1583 */
1584 CFArrayRef CTFontCopyDefaultCascadeList (CTFontRef font_ref);
1585 #endif
1586
1587 static PangoCoreTextFontset *
pango_core_text_fontset_new(PangoCoreTextFontsetKey * key,const PangoFontDescription * description)1588 pango_core_text_fontset_new (PangoCoreTextFontsetKey *key,
1589 const PangoFontDescription *description)
1590 {
1591 PangoCoreTextFamily *font_family;
1592 PangoCoreTextFontset *fontset;
1593 PangoCoreTextFont *best_font = NULL;
1594 gchar **family_names;
1595 const gchar *family;
1596 gchar *name;
1597 int i;
1598
1599 fontset = g_object_new (PANGO_TYPE_CORE_TEXT_FONTSET, NULL);
1600 family = pango_font_description_get_family (description);
1601 family_names = g_strsplit (family ? family : "", ",", -1);
1602
1603 for (i = 0; family_names[i]; ++i)
1604 {
1605 name = g_utf8_casefold (family_names[i], -1);
1606 font_family = g_hash_table_lookup (key->fontmap->families, name);
1607 g_free (name);
1608
1609 if (font_family)
1610 {
1611 PangoCoreTextFace *family_face;
1612 PangoCoreTextFont *font;
1613
1614 /* Force a listing of the available faces */
1615 pango_font_family_list_faces ((PangoFontFamily *)font_family, NULL, NULL);
1616
1617 if (find_best_match (font_family, description, &family_face))
1618 {
1619 font = pango_core_text_font_map_new_font (key->fontmap,
1620 key,
1621 family_face->ctfontdescriptor,
1622 family_face->synthetic_italic);
1623
1624 if (font)
1625 {
1626 g_ptr_array_add (fontset->fonts, font);
1627 if (best_font == NULL) best_font = font;
1628 }
1629 }
1630 }
1631 }
1632
1633 g_strfreev (family_names);
1634
1635 if (!best_font)
1636 {
1637 g_object_unref (fontset);
1638 return NULL;
1639 }
1640
1641 /* Create a font set with best font */
1642 fontset->key = pango_core_text_fontset_key_copy (key);
1643 fontset->orig_description = pango_font_description_copy (description);
1644
1645 fontset->real_font_count = fontset->fonts->len;
1646
1647 /* Add the cascade list for this language */
1648 #if defined(MAC_OS_X_VERSION_10_8) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
1649 {
1650 CFArrayRef language_pref_list = NULL;
1651 CFStringRef languages[1];
1652
1653 if (key->language)
1654 {
1655 languages[0] = CFStringCreateWithCString (NULL,
1656 pango_language_to_string (key->language),
1657 kCFStringEncodingASCII);
1658 language_pref_list = CFArrayCreate (kCFAllocatorDefault,
1659 (const void **) languages,
1660 1,
1661 &kCFTypeArrayCallBacks);
1662 }
1663
1664 fontset->cascade_list = CTFontCopyDefaultCascadeListForLanguages (pango_core_text_font_get_ctfont (best_font), language_pref_list);
1665
1666 if (language_pref_list)
1667 {
1668 CFRelease (languages[0]);
1669 CFRelease (language_pref_list);
1670 }
1671 }
1672 #else
1673 /* There is unfortunately no public API to retrieve the cascade list
1674 * on Mac OS X < 10.8, so we use the following undocumented public function.
1675 */
1676 fontset->cascade_list = CTFontCopyDefaultCascadeList (pango_core_text_font_get_ctfont (best_font));
1677 #endif
1678
1679 /* length of cascade list + real_font_count for the "real" fonts at the front */
1680 g_ptr_array_set_size (fontset->fonts, CFArrayGetCount (fontset->cascade_list) + fontset->real_font_count);
1681 g_ptr_array_set_size (fontset->coverages, CFArrayGetCount (fontset->cascade_list) + fontset->real_font_count);
1682
1683 return fontset;
1684 }
1685
1686 static PangoFont *
pango_core_text_fontset_load_font(PangoCoreTextFontset * ctfontset,CTFontDescriptorRef ctdescriptor)1687 pango_core_text_fontset_load_font (PangoCoreTextFontset *ctfontset,
1688 CTFontDescriptorRef ctdescriptor)
1689 {
1690 PangoCoreTextFontsetKey *key;
1691 PangoCoreTextFont *font;
1692
1693 key = pango_core_text_fontset_get_key (ctfontset);
1694
1695 /* For now, we will default the fallbacks to not have synthetic italic,
1696 * in the future this may be improved.
1697 */
1698 font = pango_core_text_font_map_new_font (ctfontset->key->fontmap,
1699 ctfontset->key,
1700 ctdescriptor,
1701 FALSE);
1702
1703 return PANGO_FONT (font);
1704 }
1705
1706 static PangoFont *
pango_core_text_fontset_get_font_at(PangoCoreTextFontset * ctfontset,unsigned int i)1707 pango_core_text_fontset_get_font_at (PangoCoreTextFontset *ctfontset,
1708 unsigned int i)
1709 {
1710 /* These fonts are loaded as soon as the fontset is created */
1711 if (i < ctfontset->real_font_count)
1712 return g_ptr_array_index (ctfontset->fonts, i);
1713
1714 if (i >= ctfontset->fonts->len)
1715 return NULL;
1716
1717 if (g_ptr_array_index (ctfontset->fonts, i) == NULL)
1718 {
1719 CTFontDescriptorRef ctdescriptor = CFArrayGetValueAtIndex (ctfontset->cascade_list, i - ctfontset->real_font_count);
1720 PangoFont *font = pango_core_text_fontset_load_font (ctfontset, ctdescriptor);
1721 g_ptr_array_index (ctfontset->fonts, i) = font;
1722 g_ptr_array_index (ctfontset->coverages, i) = NULL;
1723 }
1724
1725 return g_ptr_array_index (ctfontset->fonts, i);
1726 }
1727
1728 static void
pango_core_text_fontset_class_init(PangoCoreTextFontsetClass * klass)1729 pango_core_text_fontset_class_init (PangoCoreTextFontsetClass *klass)
1730 {
1731 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1732 PangoFontsetClass *fontset_class = PANGO_FONTSET_CLASS (klass);
1733
1734 object_class->finalize = pango_core_text_fontset_finalize;
1735
1736 fontset_class->get_font = pango_core_text_fontset_get_font;
1737 fontset_class->get_language = pango_core_text_fontset_get_language;
1738 fontset_class->foreach = pango_core_text_fontset_foreach;
1739 }
1740
1741 static void
pango_core_text_fontset_init(PangoCoreTextFontset * ctfontset)1742 pango_core_text_fontset_init (PangoCoreTextFontset *ctfontset)
1743 {
1744 ctfontset->key = NULL;
1745 ctfontset->cascade_list = NULL;
1746 ctfontset->fonts = g_ptr_array_new ();
1747 ctfontset->coverages = g_ptr_array_new ();
1748 ctfontset->real_font_count = 0;
1749 }
1750
1751 static void
pango_core_text_fontset_finalize(GObject * object)1752 pango_core_text_fontset_finalize (GObject *object)
1753 {
1754 PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (object);
1755 unsigned int i;
1756
1757 for (i = 0; i < ctfontset->fonts->len; i++)
1758 {
1759 PangoFont *font = g_ptr_array_index (ctfontset->fonts, i);
1760 if (font)
1761 g_object_unref (font);
1762 }
1763 g_ptr_array_free (ctfontset->fonts, TRUE);
1764
1765 for (i = 0; i < ctfontset->coverages->len; i++)
1766 {
1767 PangoCoverage *coverage = g_ptr_array_index (ctfontset->coverages, i);
1768 if (coverage)
1769 pango_coverage_unref (coverage);
1770 }
1771 g_ptr_array_free (ctfontset->coverages, TRUE);
1772
1773 if (ctfontset->cascade_list)
1774 CFRelease (ctfontset->cascade_list);
1775
1776 pango_font_description_free (ctfontset->orig_description);
1777
1778 if (ctfontset->key)
1779 pango_core_text_fontset_key_free (ctfontset->key);
1780
1781 G_OBJECT_CLASS (pango_core_text_fontset_parent_class)->finalize (object);
1782 }
1783
1784 static PangoCoreTextFontsetKey *
pango_core_text_fontset_get_key(PangoCoreTextFontset * fontset)1785 pango_core_text_fontset_get_key (PangoCoreTextFontset *fontset)
1786 {
1787 return fontset->key;
1788 }
1789
1790 static PangoLanguage *
pango_core_text_fontset_get_language(PangoFontset * fontset)1791 pango_core_text_fontset_get_language (PangoFontset *fontset)
1792 {
1793 PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (fontset);
1794
1795 return pango_core_text_fontset_key_get_language (pango_core_text_fontset_get_key (ctfontset));
1796 }
1797
1798 static PangoFont *
pango_core_text_fontset_get_font(PangoFontset * fontset,guint wc)1799 pango_core_text_fontset_get_font (PangoFontset *fontset,
1800 guint wc)
1801 {
1802 PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (fontset);
1803 PangoCoverageLevel best_level = PANGO_COVERAGE_NONE;
1804 PangoCoverageLevel level;
1805 PangoFont *font;
1806 PangoCoverage *coverage;
1807 int result = -1;
1808 unsigned int i;
1809
1810 for (i = 0; i < ctfontset->fonts->len; i++)
1811 {
1812 PangoFont *font = pango_core_text_fontset_get_font_at (ctfontset, i);
1813 if (!font)
1814 continue;
1815
1816 coverage = g_ptr_array_index (ctfontset->coverages, i);
1817
1818 if (coverage == NULL)
1819 {
1820 font = g_ptr_array_index (ctfontset->fonts, i);
1821
1822 coverage = pango_font_get_coverage (font, ctfontset->key->language);
1823 g_ptr_array_index (ctfontset->coverages, i) = coverage;
1824 }
1825
1826 level = pango_coverage_get (coverage, wc);
1827
1828 if (result == -1 || level > best_level)
1829 {
1830 result = i;
1831 best_level = level;
1832 if (level == PANGO_COVERAGE_EXACT)
1833 break;
1834 }
1835 }
1836
1837 if (G_UNLIKELY (result == -1))
1838 return NULL;
1839
1840 font = g_ptr_array_index (ctfontset->fonts, result);
1841 return g_object_ref (font);
1842 }
1843
1844 static void
pango_core_text_fontset_foreach(PangoFontset * fontset,PangoFontsetForeachFunc func,gpointer data)1845 pango_core_text_fontset_foreach (PangoFontset *fontset,
1846 PangoFontsetForeachFunc func,
1847 gpointer data)
1848 {
1849 PangoCoreTextFontset *ctfontset = PANGO_CORE_TEXT_FONTSET (fontset);
1850 unsigned int i;
1851
1852 for (i = 0; i < ctfontset->fonts->len; i++)
1853 {
1854 PangoFont *font = pango_core_text_fontset_get_font_at (ctfontset, i);
1855 if (!font)
1856 continue;
1857
1858 if ((* func) (fontset, font, data))
1859 return;
1860 }
1861 }
1862
1863 PangoCoreTextFace *
pango_core_text_font_map_find_face(PangoCoreTextFontMap * map,const PangoCoreTextFontKey * key)1864 pango_core_text_font_map_find_face (PangoCoreTextFontMap *map,
1865 const PangoCoreTextFontKey *key)
1866 {
1867 CTFontDescriptorRef desc;
1868 gboolean synthetic_italic;
1869 char *family;
1870 char *family_name;
1871 char *style_name;
1872 PangoWeight weight;
1873 CTFontSymbolicTraits traits;
1874 PangoCoreTextFamily *font_family;
1875 PangoCoreTextFace *result = NULL;
1876
1877 desc = pango_core_text_font_key_get_ctfontdescriptor (key);
1878 synthetic_italic = pango_core_text_font_key_get_synthetic_italic (key);
1879
1880 family_name = ct_font_descriptor_get_family_name (desc, FALSE);
1881 style_name = ct_font_descriptor_get_style_name (desc);
1882 weight = ct_font_descriptor_get_weight (desc);
1883 traits = ct_font_descriptor_get_traits (desc);
1884
1885 family = g_utf8_casefold (family_name, -1);
1886
1887 font_family = g_hash_table_lookup (map->families, family);
1888
1889 if (font_family)
1890 {
1891 pango_font_family_list_faces ((PangoFontFamily *)font_family, NULL, NULL);
1892
1893 for (int i = 0; i < font_family->n_faces; i++)
1894 {
1895 PangoCoreTextFace *face = (PangoCoreTextFace *)font_family->faces[i];
1896
1897 if (face->weight == weight &&
1898 face->traits == traits &&
1899 face->synthetic_italic == synthetic_italic &&
1900 strcmp (face->style_name, style_name) == 0)
1901 {
1902 result = face;
1903 break;
1904 }
1905 }
1906 }
1907
1908 g_free (family);
1909 g_free (family_name);
1910 g_free (style_name);
1911
1912 return result;
1913 }
1914