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

source code of gtk/subprojects/pango/pango/pango-fontmap.c