1 /* Pango
2 * pango-fontmap.c: Font handling
3 *
4 * Copyright (C) 2000 Red Hat Software
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 #include "config.h"
23
24 #include <gio/gio.h>
25
26 #include "pango-fontmap-private.h"
27 #include "pango-fontset-private.h"
28 #include "pango-impl-utils.h"
29 #include <stdlib.h>
30
31 static PangoFontset *pango_font_map_real_load_fontset (PangoFontMap *fontmap,
32 PangoContext *context,
33 const PangoFontDescription *desc,
34 PangoLanguage *language);
35
36
37 static PangoFontFamily *pango_font_map_real_get_family (PangoFontMap *fontmap,
38 const char *name);
39
40 static void pango_font_map_real_changed (PangoFontMap *fontmap);
41
42 static void pango_font_map_list_model_init (GListModelInterface *iface);
43
44 typedef struct {
45 guint n_families;
46 } PangoFontMapPrivate;
47
G_DEFINE_ABSTRACT_TYPE_WITH_CODE(PangoFontMap,pango_font_map,G_TYPE_OBJECT,G_ADD_PRIVATE (PangoFontMap)G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,pango_font_map_list_model_init))48 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PangoFontMap, pango_font_map, G_TYPE_OBJECT,
49 G_ADD_PRIVATE (PangoFontMap)
50 G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, pango_font_map_list_model_init))
51
52 static void
53 pango_font_map_class_init (PangoFontMapClass *class)
54 {
55 class->load_fontset = pango_font_map_real_load_fontset;
56 class->get_family = pango_font_map_real_get_family;
57 class->changed = pango_font_map_real_changed;
58 }
59
60 static void
pango_font_map_init(PangoFontMap * fontmap G_GNUC_UNUSED)61 pango_font_map_init (PangoFontMap *fontmap G_GNUC_UNUSED)
62 {
63 }
64
65 /**
66 * pango_font_map_create_context:
67 * @fontmap: a `PangoFontMap`
68 *
69 * Creates a `PangoContext` connected to @fontmap.
70 *
71 * This is equivalent to [ctor@Pango.Context.new] followed by
72 * [method@Pango.Context.set_font_map].
73 *
74 * If you are using Pango as part of a higher-level system,
75 * that system may have it's own way of create a `PangoContext`.
76 * For instance, the GTK toolkit has, among others,
77 * gtk_widget_get_pango_context(). Use those instead.
78 *
79 * Return value: (transfer full): the newly allocated `PangoContext`,
80 * which should be freed with g_object_unref().
81 *
82 * Since: 1.22
83 */
84 PangoContext *
pango_font_map_create_context(PangoFontMap * fontmap)85 pango_font_map_create_context (PangoFontMap *fontmap)
86 {
87 PangoContext *context;
88
89 g_return_val_if_fail (fontmap != NULL, NULL);
90
91 context = pango_context_new ();
92 pango_context_set_font_map (context, fontmap);
93
94 return context;
95 }
96
97 /**
98 * pango_font_map_load_font:
99 * @fontmap: a `PangoFontMap`
100 * @context: the `PangoContext` the font will be used with
101 * @desc: a `PangoFontDescription` describing the font to load
102 *
103 * Load the font in the fontmap that is the closest match for @desc.
104 *
105 * Returns: (transfer full) (nullable): the newly allocated `PangoFont`
106 * loaded, or %NULL if no font matched.
107 */
108 PangoFont *
pango_font_map_load_font(PangoFontMap * fontmap,PangoContext * context,const PangoFontDescription * desc)109 pango_font_map_load_font (PangoFontMap *fontmap,
110 PangoContext *context,
111 const PangoFontDescription *desc)
112 {
113 g_return_val_if_fail (fontmap != NULL, NULL);
114
115 return PANGO_FONT_MAP_GET_CLASS (fontmap)->load_font (fontmap, context, desc);
116 }
117
118 /**
119 * pango_font_map_list_families:
120 * @fontmap: a `PangoFontMap`
121 * @families: (out) (array length=n_families) (transfer container): location to
122 * store a pointer to an array of `PangoFontFamily` *.
123 * This array should be freed with g_free().
124 * @n_families: (out): location to store the number of elements in @families
125 *
126 * List all families for a fontmap.
127 */
128 void
pango_font_map_list_families(PangoFontMap * fontmap,PangoFontFamily *** families,int * n_families)129 pango_font_map_list_families (PangoFontMap *fontmap,
130 PangoFontFamily ***families,
131 int *n_families)
132 {
133 PangoFontMapPrivate *priv = pango_font_map_get_instance_private (fontmap);
134 g_return_if_fail (fontmap != NULL);
135
136 PANGO_FONT_MAP_GET_CLASS (fontmap)->list_families (fontmap, families, n_families);
137
138 /* keep this value for GListModel::changed */
139 priv->n_families = *n_families;
140 }
141
142 /**
143 * pango_font_map_load_fontset:
144 * @fontmap: a `PangoFontMap`
145 * @context: the `PangoContext` the font will be used with
146 * @desc: a `PangoFontDescription` describing the font to load
147 * @language: a `PangoLanguage` the fonts will be used for
148 *
149 * Load a set of fonts in the fontmap that can be used to render
150 * a font matching @desc.
151 *
152 * Returns: (transfer full) (nullable): the newly allocated
153 * `PangoFontset` loaded, or %NULL if no font matched.
154 */
155 PangoFontset *
pango_font_map_load_fontset(PangoFontMap * fontmap,PangoContext * context,const PangoFontDescription * desc,PangoLanguage * language)156 pango_font_map_load_fontset (PangoFontMap *fontmap,
157 PangoContext *context,
158 const PangoFontDescription *desc,
159 PangoLanguage *language)
160 {
161 g_return_val_if_fail (fontmap != NULL, NULL);
162
163 return PANGO_FONT_MAP_GET_CLASS (fontmap)->load_fontset (fontmap, context, desc, language);
164 }
165
166 static void
pango_font_map_fontset_add_fonts(PangoFontMap * fontmap,PangoContext * context,PangoFontsetSimple * fonts,PangoFontDescription * desc,const char * family)167 pango_font_map_fontset_add_fonts (PangoFontMap *fontmap,
168 PangoContext *context,
169 PangoFontsetSimple *fonts,
170 PangoFontDescription *desc,
171 const char *family)
172 {
173 PangoFont *font;
174
175 pango_font_description_set_family_static (desc, family);
176 font = pango_font_map_load_font (fontmap, context, desc);
177 if (font)
178 pango_fontset_simple_append (fonts, font);
179 }
180
181 static PangoFontset *
pango_font_map_real_load_fontset(PangoFontMap * fontmap,PangoContext * context,const PangoFontDescription * desc,PangoLanguage * language)182 pango_font_map_real_load_fontset (PangoFontMap *fontmap,
183 PangoContext *context,
184 const PangoFontDescription *desc,
185 PangoLanguage *language)
186 {
187 PangoFontDescription *tmp_desc = pango_font_description_copy_static (desc);
188 const char *family;
189 char **families;
190 int i;
191 PangoFontsetSimple *fonts;
192 static GHashTable *warned_fonts = NULL; /* MT-safe */
193 G_LOCK_DEFINE_STATIC (warned_fonts);
194
195 family = pango_font_description_get_family (desc);
196 families = g_strsplit (family ? family : "", ",", -1);
197
198 fonts = pango_fontset_simple_new (language);
199
200 for (i = 0; families[i]; i++)
201 pango_font_map_fontset_add_fonts (fontmap,
202 context,
203 fonts,
204 tmp_desc,
205 families[i]);
206
207 g_strfreev (families);
208
209 /* The font description was completely unloadable, try with
210 * family == "Sans"
211 */
212 if (pango_fontset_simple_size (fonts) == 0)
213 {
214 char *ctmp1, *ctmp2;
215
216 pango_font_description_set_family_static (tmp_desc,
217 pango_font_description_get_family (desc));
218
219 ctmp1 = pango_font_description_to_string (desc);
220 pango_font_description_set_family_static (tmp_desc, "Sans");
221
222 G_LOCK (warned_fonts);
223 if (!warned_fonts || !g_hash_table_lookup (warned_fonts, ctmp1))
224 {
225 if (!warned_fonts)
226 warned_fonts = g_hash_table_new (g_str_hash, g_str_equal);
227
228 g_hash_table_insert (warned_fonts, g_strdup (ctmp1), GINT_TO_POINTER (1));
229
230 ctmp2 = pango_font_description_to_string (tmp_desc);
231 g_warning ("couldn't load font \"%s\", falling back to \"%s\", "
232 "expect ugly output.", ctmp1, ctmp2);
233 g_free (ctmp2);
234 }
235 G_UNLOCK (warned_fonts);
236 g_free (ctmp1);
237
238 pango_font_map_fontset_add_fonts (fontmap,
239 context,
240 fonts,
241 tmp_desc,
242 "Sans");
243 }
244
245 /* We couldn't try with Sans and the specified style. Try Sans Normal
246 */
247 if (pango_fontset_simple_size (fonts) == 0)
248 {
249 char *ctmp1, *ctmp2;
250
251 pango_font_description_set_family_static (tmp_desc, "Sans");
252 ctmp1 = pango_font_description_to_string (tmp_desc);
253 pango_font_description_set_style (tmp_desc, PANGO_STYLE_NORMAL);
254 pango_font_description_set_weight (tmp_desc, PANGO_WEIGHT_NORMAL);
255 pango_font_description_set_variant (tmp_desc, PANGO_VARIANT_NORMAL);
256 pango_font_description_set_stretch (tmp_desc, PANGO_STRETCH_NORMAL);
257
258 G_LOCK (warned_fonts);
259 if (!warned_fonts || !g_hash_table_lookup (warned_fonts, ctmp1))
260 {
261 g_hash_table_insert (warned_fonts, g_strdup (ctmp1), GINT_TO_POINTER (1));
262
263 ctmp2 = pango_font_description_to_string (tmp_desc);
264
265 g_warning ("couldn't load font \"%s\", falling back to \"%s\", "
266 "expect ugly output.", ctmp1, ctmp2);
267 g_free (ctmp2);
268 }
269 G_UNLOCK (warned_fonts);
270 g_free (ctmp1);
271
272 pango_font_map_fontset_add_fonts (fontmap,
273 context,
274 fonts,
275 tmp_desc,
276 "Sans");
277 }
278
279 pango_font_description_free (tmp_desc);
280
281 /* Everything failed, we are screwed, there is no way to continue,
282 * but lets just not crash here.
283 */
284 if (pango_fontset_simple_size (fonts) == 0)
285 g_warning ("All font fallbacks failed!!!!");
286
287 return PANGO_FONTSET (fonts);
288 }
289
290 /**
291 * pango_font_map_get_shape_engine_type:
292 * @fontmap: a `PangoFontMap`
293 *
294 * Returns the render ID for shape engines for this fontmap.
295 * See the `render_type` field of `PangoEngineInfo`.
296 *
297 * Return value (transfer none): the ID string for shape engines
298 * for this fontmap
299 *
300 * Since: 1.4
301 * Deprecated: 1.38
302 */
303 const char *
pango_font_map_get_shape_engine_type(PangoFontMap * fontmap)304 pango_font_map_get_shape_engine_type (PangoFontMap *fontmap)
305 {
306 g_return_val_if_fail (PANGO_IS_FONT_MAP (fontmap), NULL);
307
308 return PANGO_FONT_MAP_GET_CLASS (fontmap)->shape_engine_type;
309 }
310
311 /**
312 * pango_font_map_get_serial:
313 * @fontmap: a `PangoFontMap`
314 *
315 * Returns the current serial number of @fontmap.
316 *
317 * The serial number is initialized to an small number larger than zero
318 * when a new fontmap is created and is increased whenever the fontmap
319 * is changed. It may wrap, but will never have the value 0. Since it can
320 * wrap, never compare it with "less than", always use "not equals".
321 *
322 * The fontmap can only be changed using backend-specific API, like changing
323 * fontmap resolution.
324 *
325 * This can be used to automatically detect changes to a `PangoFontMap`,
326 * like in `PangoContext`.
327 *
328 * Return value: The current serial number of @fontmap.
329 *
330 * Since: 1.32.4
331 */
332 guint
pango_font_map_get_serial(PangoFontMap * fontmap)333 pango_font_map_get_serial (PangoFontMap *fontmap)
334 {
335 g_return_val_if_fail (PANGO_IS_FONT_MAP (fontmap), 0);
336
337 if (PANGO_FONT_MAP_GET_CLASS (fontmap)->get_serial)
338 return PANGO_FONT_MAP_GET_CLASS (fontmap)->get_serial (fontmap);
339 else
340 return 1;
341 }
342
343 static void
pango_font_map_real_changed(PangoFontMap * fontmap)344 pango_font_map_real_changed (PangoFontMap *fontmap)
345 {
346 PangoFontMapPrivate *priv = pango_font_map_get_instance_private (fontmap);
347 guint removed, added;
348
349 removed = priv->n_families;
350 added = g_list_model_get_n_items (G_LIST_MODEL (fontmap));
351
352 g_list_model_items_changed (G_LIST_MODEL (fontmap), 0, removed, added);
353 }
354
355 /**
356 * pango_font_map_changed:
357 * @fontmap: a `PangoFontMap`
358 *
359 * Forces a change in the context, which will cause any `PangoContext`
360 * using this fontmap to change.
361 *
362 * This function is only useful when implementing a new backend
363 * for Pango, something applications won't do. Backends should
364 * call this function if they have attached extra data to the
365 * context and such data is changed.
366 *
367 * Since: 1.34
368 */
369 void
pango_font_map_changed(PangoFontMap * fontmap)370 pango_font_map_changed (PangoFontMap *fontmap)
371 {
372 g_return_if_fail (PANGO_IS_FONT_MAP (fontmap));
373
374 if (PANGO_FONT_MAP_GET_CLASS (fontmap)->changed)
375 PANGO_FONT_MAP_GET_CLASS (fontmap)->changed (fontmap);
376 }
377
378 static PangoFontFamily *
pango_font_map_real_get_family(PangoFontMap * fontmap,const char * name)379 pango_font_map_real_get_family (PangoFontMap *fontmap,
380 const char *name)
381 {
382 PangoFontFamily **families;
383 int n_families;
384 PangoFontFamily *family;
385 int i;
386
387 pango_font_map_list_families (fontmap, &families, &n_families);
388
389 family = NULL;
390
391 for (i = 0; i < n_families; i++)
392 {
393 if (strcmp (name, pango_font_family_get_name (families[i])) == 0)
394 {
395 family = families[i];
396 break;
397 }
398 }
399
400 g_free (families);
401
402 return family;
403 }
404
405 /**
406 * pango_font_map_get_family:
407 * @fontmap: a `PangoFontMap`
408 * @name: a family name
409 *
410 * Gets a font family by name.
411 *
412 * Returns: (transfer none): the `PangoFontFamily`
413 *
414 * Since: 1.46
415 */
416 PangoFontFamily *
pango_font_map_get_family(PangoFontMap * fontmap,const char * name)417 pango_font_map_get_family (PangoFontMap *fontmap,
418 const char *name)
419 {
420 g_return_val_if_fail (PANGO_IS_FONT_MAP (fontmap), NULL);
421
422 return PANGO_FONT_MAP_GET_CLASS (fontmap)->get_family (fontmap, name);
423 }
424
425 static GType
pango_font_map_get_item_type(GListModel * list)426 pango_font_map_get_item_type (GListModel *list)
427 {
428 return PANGO_TYPE_FONT_FAMILY;
429 }
430
431 static guint
pango_font_map_get_n_items(GListModel * list)432 pango_font_map_get_n_items (GListModel *list)
433 {
434 PangoFontMap *fontmap = PANGO_FONT_MAP (list);
435 int n_families;
436
437 pango_font_map_list_families (fontmap, NULL, &n_families);
438
439 return (guint)n_families;
440 }
441
442 static gpointer
pango_font_map_get_item(GListModel * list,guint position)443 pango_font_map_get_item (GListModel *list,
444 guint position)
445 {
446 PangoFontMap *fontmap = PANGO_FONT_MAP (list);
447 PangoFontFamily **families;
448 int n_families;
449 PangoFontFamily *family;
450
451 pango_font_map_list_families (fontmap, &families, &n_families);
452
453 if (position < n_families)
454 family = g_object_ref (families[position]);
455 else
456 family = NULL;
457
458 g_free (families);
459
460 return family;
461 }
462
463 static void
pango_font_map_list_model_init(GListModelInterface * iface)464 pango_font_map_list_model_init (GListModelInterface *iface)
465 {
466 iface->get_item_type = pango_font_map_get_item_type;
467 iface->get_n_items = pango_font_map_get_n_items;
468 iface->get_item = pango_font_map_get_item;
469 }
470