1 /* Pango
2  * fonts.c:
3  *
4  * Copyright (C) 1999 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 #include <stdlib.h>
24 #include <math.h>
25 #include <string.h>
26 
27 #include <gio/gio.h>
28 
29 #include "pango-types.h"
30 #include "pango-font-private.h"
31 #include "pango-fontmap.h"
32 #include "pango-impl-utils.h"
33 
34 struct _PangoFontDescription
35 {
36   char *family_name;
37 
38   PangoStyle style;
39   PangoVariant variant;
40   PangoWeight weight;
41   PangoStretch stretch;
42   PangoGravity gravity;
43 
44   char *variations;
45 
46   guint16 mask;
47   guint static_family : 1;
48   guint static_variations : 1;
49   guint size_is_absolute : 1;
50 
51   int size;
52 };
53 
54 G_DEFINE_BOXED_TYPE (PangoFontDescription, pango_font_description,
55                      pango_font_description_copy,
56                      pango_font_description_free);
57 
58 static const PangoFontDescription pfd_defaults = {
59   NULL,                 /* family_name */
60 
61   PANGO_STYLE_NORMAL,   /* style */
62   PANGO_VARIANT_NORMAL, /* variant */
63   PANGO_WEIGHT_NORMAL,  /* weight */
64   PANGO_STRETCH_NORMAL, /* stretch */
65   PANGO_GRAVITY_SOUTH,  /* gravity */
66   NULL,                 /* variations */
67 
68   0,                    /* mask */
69   0,                    /* static_family */
70   0,                    /* static_variations*/
71   0,                    /* size_is_absolute */
72 
73   0,                    /* size */
74 };
75 
76 /**
77  * pango_font_description_new:
78  *
79  * Creates a new font description structure with all fields unset.
80  *
81  * Return value: the newly allocated `PangoFontDescription`, which
82  *   should be freed using [method@Pango.FontDescription.free].
83  */
84 PangoFontDescription *
pango_font_description_new(void)85 pango_font_description_new (void)
86 {
87   PangoFontDescription *desc = g_slice_new (PangoFontDescription);
88 
89   *desc = pfd_defaults;
90 
91   return desc;
92 }
93 
94 /**
95  * pango_font_description_set_family:
96  * @desc: a `PangoFontDescription`.
97  * @family: a string representing the family name.
98  *
99  * Sets the family name field of a font description.
100  *
101  * The family
102  * name represents a family of related font styles, and will
103  * resolve to a particular `PangoFontFamily`. In some uses of
104  * `PangoFontDescription`, it is also possible to use a comma
105  * separated list of family names for this field.
106  */
107 void
pango_font_description_set_family(PangoFontDescription * desc,const char * family)108 pango_font_description_set_family (PangoFontDescription *desc,
109                                    const char           *family)
110 {
111   g_return_if_fail (desc != NULL);
112 
113   pango_font_description_set_family_static (desc, family ? g_strdup (family) : NULL);
114   if (family)
115     desc->static_family = FALSE;
116 }
117 
118 /**
119  * pango_font_description_set_family_static:
120  * @desc: a `PangoFontDescription`
121  * @family: a string representing the family name
122  *
123  * Sets the family name field of a font description, without copying the string.
124  *
125  * This is like [method@Pango.FontDescription.set_family], except that no
126  * copy of @family is made. The caller must make sure that the
127  * string passed in stays around until @desc has been freed or the
128  * name is set again. This function can be used if @family is a static
129  * string such as a C string literal, or if @desc is only needed temporarily.
130  */
131 void
pango_font_description_set_family_static(PangoFontDescription * desc,const char * family)132 pango_font_description_set_family_static (PangoFontDescription *desc,
133                                           const char           *family)
134 {
135   g_return_if_fail (desc != NULL);
136 
137   if (desc->family_name == family)
138     return;
139 
140   if (desc->family_name && !desc->static_family)
141     g_free (desc->family_name);
142 
143   if (family)
144     {
145       desc->family_name = (char *)family;
146       desc->static_family = TRUE;
147       desc->mask |= PANGO_FONT_MASK_FAMILY;
148     }
149   else
150     {
151       desc->family_name = pfd_defaults.family_name;
152       desc->static_family = pfd_defaults.static_family;
153       desc->mask &= ~PANGO_FONT_MASK_FAMILY;
154     }
155 }
156 
157 /**
158  * pango_font_description_get_family:
159  * @desc: a `PangoFontDescription`.
160  *
161  * Gets the family name field of a font description.
162  *
163  * See [method@Pango.FontDescription.set_family].
164  *
165  * Return value: (nullable): the family name field for the font
166  *   description, or %NULL if not previously set. This has the same
167  *   life-time as the font description itself and should not be freed.
168  */
169 const char *
pango_font_description_get_family(const PangoFontDescription * desc)170 pango_font_description_get_family (const PangoFontDescription *desc)
171 {
172   g_return_val_if_fail (desc != NULL, NULL);
173 
174   return desc->family_name;
175 }
176 
177 /**
178  * pango_font_description_set_style:
179  * @desc: a `PangoFontDescription`
180  * @style: the style for the font description
181  *
182  * Sets the style field of a `PangoFontDescription`.
183  *
184  * The [enum@Pango.Style] enumeration describes whether the font is
185  * slanted and the manner in which it is slanted; it can be either
186  * %PANGO_STYLE_NORMAL, %PANGO_STYLE_ITALIC, or %PANGO_STYLE_OBLIQUE.
187  *
188  * Most fonts will either have a italic style or an oblique style,
189  * but not both, and font matching in Pango will match italic
190  * specifications with oblique fonts and vice-versa if an exact
191  * match is not found.
192  */
193 void
pango_font_description_set_style(PangoFontDescription * desc,PangoStyle style)194 pango_font_description_set_style (PangoFontDescription *desc,
195                                   PangoStyle            style)
196 {
197   g_return_if_fail (desc != NULL);
198 
199   desc->style = style;
200   desc->mask |= PANGO_FONT_MASK_STYLE;
201 }
202 
203 /**
204  * pango_font_description_get_style:
205  * @desc: a `PangoFontDescription`
206  *
207  * Gets the style field of a `PangoFontDescription`.
208  *
209  * See [method@Pango.FontDescription.set_style].
210  *
211  * Return value: the style field for the font description.
212  *   Use [method@Pango.FontDescription.get_set_fields] to
213  *   find out if the field was explicitly set or not.
214  */
215 PangoStyle
pango_font_description_get_style(const PangoFontDescription * desc)216 pango_font_description_get_style (const PangoFontDescription *desc)
217 {
218   g_return_val_if_fail (desc != NULL, pfd_defaults.style);
219 
220   return desc->style;
221 }
222 
223 /**
224  * pango_font_description_set_variant:
225  * @desc: a `PangoFontDescription`
226  * @variant: the variant type for the font description.
227  *
228  * Sets the variant field of a font description.
229  *
230  * The [enum@Pango.Variant] can either be %PANGO_VARIANT_NORMAL
231  * or %PANGO_VARIANT_SMALL_CAPS.
232  */
233 void
pango_font_description_set_variant(PangoFontDescription * desc,PangoVariant variant)234 pango_font_description_set_variant (PangoFontDescription *desc,
235                                     PangoVariant          variant)
236 {
237   g_return_if_fail (desc != NULL);
238 
239   desc->variant = variant;
240   desc->mask |= PANGO_FONT_MASK_VARIANT;
241 }
242 
243 /**
244  * pango_font_description_get_variant:
245  * @desc: a `PangoFontDescription`.
246  *
247  * Gets the variant field of a `PangoFontDescription`.
248  *
249  * See [method@Pango.FontDescription.set_variant].
250  *
251  * Return value: the variant field for the font description.
252  *   Use [method@Pango.FontDescription.get_set_fields] to find
253  *   out if the field was explicitly set or not.
254  */
255 PangoVariant
pango_font_description_get_variant(const PangoFontDescription * desc)256 pango_font_description_get_variant (const PangoFontDescription *desc)
257 {
258   g_return_val_if_fail (desc != NULL, pfd_defaults.variant);
259 
260   return desc->variant;
261 }
262 
263 /**
264  * pango_font_description_set_weight:
265  * @desc: a `PangoFontDescription`
266  * @weight: the weight for the font description.
267  *
268  * Sets the weight field of a font description.
269  *
270  * The weight field
271  * specifies how bold or light the font should be. In addition
272  * to the values of the [enum@Pango.Weight] enumeration, other
273  * intermediate numeric values are possible.
274  */
275 void
pango_font_description_set_weight(PangoFontDescription * desc,PangoWeight weight)276 pango_font_description_set_weight (PangoFontDescription *desc,
277                                    PangoWeight          weight)
278 {
279   g_return_if_fail (desc != NULL);
280 
281   desc->weight = weight;
282   desc->mask |= PANGO_FONT_MASK_WEIGHT;
283 }
284 
285 /**
286  * pango_font_description_get_weight:
287  * @desc: a `PangoFontDescription`
288  *
289  * Gets the weight field of a font description.
290  *
291  * See [method@Pango.FontDescription.set_weight].
292  *
293  * Return value: the weight field for the font description.
294  *   Use [method@Pango.FontDescription.get_set_fields] to find
295  *   out if the field was explicitly set or not.
296  */
297 PangoWeight
pango_font_description_get_weight(const PangoFontDescription * desc)298 pango_font_description_get_weight (const PangoFontDescription *desc)
299 {
300   g_return_val_if_fail (desc != NULL, pfd_defaults.weight);
301 
302   return desc->weight;
303 }
304 
305 /**
306  * pango_font_description_set_stretch:
307  * @desc: a `PangoFontDescription`
308  * @stretch: the stretch for the font description
309  *
310  * Sets the stretch field of a font description.
311  *
312  * The [enum@Pango.Stretch] field specifies how narrow or
313  * wide the font should be.
314  */
315 void
pango_font_description_set_stretch(PangoFontDescription * desc,PangoStretch stretch)316 pango_font_description_set_stretch (PangoFontDescription *desc,
317                                     PangoStretch          stretch)
318 {
319   g_return_if_fail (desc != NULL);
320 
321   desc->stretch = stretch;
322   desc->mask |= PANGO_FONT_MASK_STRETCH;
323 }
324 
325 /**
326  * pango_font_description_get_stretch:
327  * @desc: a `PangoFontDescription`.
328  *
329  * Gets the stretch field of a font description.
330  *
331  * See [method@Pango.FontDescription.set_stretch].
332  *
333  * Return value: the stretch field for the font description.
334  *   Use [method@Pango.FontDescription.get_set_fields] to find
335  *   out if the field was explicitly set or not.
336  */
337 PangoStretch
pango_font_description_get_stretch(const PangoFontDescription * desc)338 pango_font_description_get_stretch (const PangoFontDescription *desc)
339 {
340   g_return_val_if_fail (desc != NULL, pfd_defaults.stretch);
341 
342   return desc->stretch;
343 }
344 
345 /**
346  * pango_font_description_set_size:
347  * @desc: a `PangoFontDescription`
348  * @size: the size of the font in points, scaled by %PANGO_SCALE.
349  *   (That is, a @size value of 10 * PANGO_SCALE is a 10 point font.
350  *   The conversion factor between points and device units depends on
351  *   system configuration and the output device. For screen display, a
352  *   logical DPI of 96 is common, in which case a 10 point font corresponds
353  *   to a 10 * (96 / 72) = 13.3 pixel font.
354  *   Use [method@Pango.FontDescription.set_absolute_size] if you need
355  *   a particular size in device units.
356  *
357  * Sets the size field of a font description in fractional points.
358  *
359  * This is mutually exclusive with
360  * [method@Pango.FontDescription.set_absolute_size].
361  */
362 void
pango_font_description_set_size(PangoFontDescription * desc,gint size)363 pango_font_description_set_size (PangoFontDescription *desc,
364                                  gint                  size)
365 {
366   g_return_if_fail (desc != NULL);
367   g_return_if_fail (size >= 0);
368 
369   desc->size = size;
370   desc->size_is_absolute = FALSE;
371   desc->mask |= PANGO_FONT_MASK_SIZE;
372 }
373 
374 /**
375  * pango_font_description_get_size:
376  * @desc: a `PangoFontDescription`
377  *
378  * Gets the size field of a font description.
379  *
380  * See [method@Pango.FontDescription.set_size].
381  *
382  * Return value: the size field for the font description in points
383  *   or device units. You must call
384  *   [method@Pango.FontDescription.get_size_is_absolute] to find out
385  *   which is the case. Returns 0 if the size field has not previously
386  *   been set or it has been set to 0 explicitly.
387  *   Use [method@Pango.FontDescription.get_set_fields] to find out
388  *   if the field was explicitly set or not.
389  */
390 gint
pango_font_description_get_size(const PangoFontDescription * desc)391 pango_font_description_get_size (const PangoFontDescription *desc)
392 {
393   g_return_val_if_fail (desc != NULL, pfd_defaults.size);
394 
395   return desc->size;
396 }
397 
398 /**
399  * pango_font_description_set_absolute_size:
400  * @desc: a `PangoFontDescription`
401  * @size: the new size, in Pango units. There are %PANGO_SCALE Pango units
402  *   in one device unit. For an output backend where a device unit is a pixel,
403  *   a @size value of 10 * PANGO_SCALE gives a 10 pixel font.
404  *
405  * Sets the size field of a font description, in device units.
406  *
407  * This is mutually exclusive with [method@Pango.FontDescription.set_size]
408  * which sets the font size in points.
409  *
410  * Since: 1.8
411  */
412 void
pango_font_description_set_absolute_size(PangoFontDescription * desc,double size)413 pango_font_description_set_absolute_size (PangoFontDescription *desc,
414                                           double                size)
415 {
416   g_return_if_fail (desc != NULL);
417   g_return_if_fail (size >= 0);
418 
419   desc->size = size;
420   desc->size_is_absolute = TRUE;
421   desc->mask |= PANGO_FONT_MASK_SIZE;
422 }
423 
424 /**
425  * pango_font_description_get_size_is_absolute:
426  * @desc: a `PangoFontDescription`
427  *
428  * Determines whether the size of the font is in points (not absolute)
429  * or device units (absolute).
430  *
431  * See [method@Pango.FontDescription.set_size]
432  * and [method@Pango.FontDescription.set_absolute_size].
433  *
434  * Return value: whether the size for the font description is in
435  *   points or device units. Use [method@Pango.FontDescription.get_set_fields]
436  *   to find out if the size field of the font description was explicitly
437  *   set or not.
438  *
439  * Since: 1.8
440  */
441 gboolean
pango_font_description_get_size_is_absolute(const PangoFontDescription * desc)442 pango_font_description_get_size_is_absolute (const PangoFontDescription *desc)
443 {
444   g_return_val_if_fail (desc != NULL, pfd_defaults.size_is_absolute);
445 
446   return desc->size_is_absolute;
447 }
448 
449 /**
450  * pango_font_description_set_gravity:
451  * @desc: a `PangoFontDescription`
452  * @gravity: the gravity for the font description.
453  *
454  * Sets the gravity field of a font description.
455  *
456  * The gravity field
457  * specifies how the glyphs should be rotated. If @gravity is
458  * %PANGO_GRAVITY_AUTO, this actually unsets the gravity mask on
459  * the font description.
460  *
461  * This function is seldom useful to the user. Gravity should normally
462  * be set on a `PangoContext`.
463  *
464  * Since: 1.16
465  */
466 void
pango_font_description_set_gravity(PangoFontDescription * desc,PangoGravity gravity)467 pango_font_description_set_gravity (PangoFontDescription *desc,
468                                     PangoGravity          gravity)
469 {
470   g_return_if_fail (desc != NULL);
471 
472   if (gravity == PANGO_GRAVITY_AUTO)
473     {
474       pango_font_description_unset_fields (desc, PANGO_FONT_MASK_GRAVITY);
475       return;
476     }
477 
478   desc->gravity = gravity;
479   desc->mask |= PANGO_FONT_MASK_GRAVITY;
480 }
481 
482 /**
483  * pango_font_description_get_gravity:
484  * @desc: a `PangoFontDescription`
485  *
486  * Gets the gravity field of a font description.
487  *
488  * See [method@Pango.FontDescription.set_gravity].
489  *
490  * Return value: the gravity field for the font description.
491  *   Use [method@Pango.FontDescription.get_set_fields] to find out
492  *   if the field was explicitly set or not.
493  *
494  * Since: 1.16
495  */
496 PangoGravity
pango_font_description_get_gravity(const PangoFontDescription * desc)497 pango_font_description_get_gravity (const PangoFontDescription *desc)
498 {
499   g_return_val_if_fail (desc != NULL, pfd_defaults.gravity);
500 
501   return desc->gravity;
502 }
503 
504 /**
505  * pango_font_description_set_variations_static:
506  * @desc: a `PangoFontDescription`
507  * @variations: a string representing the variations
508  *
509  * Sets the variations field of a font description.
510  *
511  * This is like [method@Pango.FontDescription.set_variations], except
512  * that no copy of @variations is made. The caller must make sure that
513  * the string passed in stays around until @desc has been freed
514  * or the name is set again. This function can be used if
515  * @variations is a static string such as a C string literal,
516  * or if @desc is only needed temporarily.
517  *
518  * Since: 1.42
519  */
520 void
pango_font_description_set_variations_static(PangoFontDescription * desc,const char * variations)521 pango_font_description_set_variations_static (PangoFontDescription *desc,
522                                               const char           *variations)
523 {
524   g_return_if_fail (desc != NULL);
525 
526   if (desc->variations == variations)
527     return;
528 
529   if (desc->variations && !desc->static_variations)
530     g_free (desc->variations);
531 
532   if (variations)
533     {
534       desc->variations = (char *)variations;
535       desc->static_variations = TRUE;
536       desc->mask |= PANGO_FONT_MASK_VARIATIONS;
537     }
538   else
539     {
540       desc->variations = pfd_defaults.variations;
541       desc->static_variations = pfd_defaults.static_variations;
542       desc->mask &= ~PANGO_FONT_MASK_VARIATIONS;
543     }
544 }
545 
546 /**
547  * pango_font_description_set_variations:
548  * @desc: a `PangoFontDescription`.
549  * @variations: a string representing the variations
550  *
551  * Sets the variations field of a font description.
552  *
553  * OpenType font variations allow to select a font instance by
554  * specifying values for a number of axes, such as width or weight.
555  *
556  * The format of the variations string is
557  *
558  *     AXIS1=VALUE,AXIS2=VALUE...
559  *
560  * with each AXIS a 4 character tag that identifies a font axis,
561  * and each VALUE a floating point number. Unknown axes are ignored,
562  * and values are clamped to their allowed range.
563  *
564  * Pango does not currently have a way to find supported axes of
565  * a font. Both harfbuzz or freetype have API for this.
566  *
567  * Since: 1.42
568  */
569 void
pango_font_description_set_variations(PangoFontDescription * desc,const char * variations)570 pango_font_description_set_variations (PangoFontDescription *desc,
571                                        const char           *variations)
572 {
573   g_return_if_fail (desc != NULL);
574 
575   pango_font_description_set_variations_static (desc, g_strdup (variations));
576   if (variations)
577     desc->static_variations = FALSE;
578 }
579 
580 /**
581  * pango_font_description_get_variations:
582  * @desc: a `PangoFontDescription`
583  *
584  * Gets the variations field of a font description.
585  *
586  * See [method@Pango.FontDescription.set_variations].
587  *
588  * Return value: (nullable): the variations field for the font
589  *   description, or %NULL if not previously set. This has the same
590  *   life-time as the font description itself and should not be freed.
591  *
592  * Since: 1.42
593  */
594 const char *
pango_font_description_get_variations(const PangoFontDescription * desc)595 pango_font_description_get_variations (const PangoFontDescription *desc)
596 {
597   g_return_val_if_fail (desc != NULL, NULL);
598 
599   return desc->variations;
600 }
601 
602 /**
603  * pango_font_description_get_set_fields:
604  * @desc: a `PangoFontDescription`
605  *
606  * Determines which fields in a font description have been set.
607  *
608  * Return value: a bitmask with bits set corresponding to the
609  *   fields in @desc that have been set.
610  */
611 PangoFontMask
pango_font_description_get_set_fields(const PangoFontDescription * desc)612 pango_font_description_get_set_fields (const PangoFontDescription *desc)
613 {
614   g_return_val_if_fail (desc != NULL, pfd_defaults.mask);
615 
616   return desc->mask;
617 }
618 
619 /**
620  * pango_font_description_unset_fields:
621  * @desc: a `PangoFontDescription`
622  * @to_unset: bitmask of fields in the @desc to unset.
623  *
624  * Unsets some of the fields in a `PangoFontDescription`.
625  *
626  * The unset fields will get back to their default values.
627  */
628 void
pango_font_description_unset_fields(PangoFontDescription * desc,PangoFontMask to_unset)629 pango_font_description_unset_fields (PangoFontDescription *desc,
630                                      PangoFontMask         to_unset)
631 {
632   PangoFontDescription unset_desc;
633 
634   g_return_if_fail (desc != NULL);
635 
636   unset_desc = pfd_defaults;
637   unset_desc.mask = to_unset;
638 
639   pango_font_description_merge_static (desc, &unset_desc, TRUE);
640 
641   desc->mask &= ~to_unset;
642 }
643 
644 /**
645  * pango_font_description_merge:
646  * @desc: a `PangoFontDescription`
647  * @desc_to_merge: (nullable): the `PangoFontDescription` to merge from,
648  *   or %NULL
649  * @replace_existing: if %TRUE, replace fields in @desc with the
650  *   corresponding values from @desc_to_merge, even if they
651  *   are already exist.
652  *
653  * Merges the fields that are set in @desc_to_merge into the fields in
654  * @desc.
655  *
656  * If @replace_existing is %FALSE, only fields in @desc that
657  * are not already set are affected. If %TRUE, then fields that are
658  * already set will be replaced as well.
659  *
660  * If @desc_to_merge is %NULL, this function performs nothing.
661  */
662 void
pango_font_description_merge(PangoFontDescription * desc,const PangoFontDescription * desc_to_merge,gboolean replace_existing)663 pango_font_description_merge (PangoFontDescription       *desc,
664                               const PangoFontDescription *desc_to_merge,
665                               gboolean                    replace_existing)
666 {
667   gboolean family_merged;
668   gboolean variations_merged;
669 
670   g_return_if_fail (desc != NULL);
671 
672   if (desc_to_merge == NULL)
673     return;
674 
675   family_merged = desc_to_merge->family_name && (replace_existing || !desc->family_name);
676   variations_merged = desc_to_merge->variations && (replace_existing || !desc->variations);
677 
678   pango_font_description_merge_static (desc, desc_to_merge, replace_existing);
679 
680   if (family_merged)
681     {
682       desc->family_name = g_strdup (desc->family_name);
683       desc->static_family = FALSE;
684     }
685 
686   if (variations_merged)
687     {
688       desc->variations = g_strdup (desc->variations);
689       desc->static_variations = FALSE;
690     }
691 }
692 
693 /**
694  * pango_font_description_merge_static:
695  * @desc: a `PangoFontDescription`
696  * @desc_to_merge: the `PangoFontDescription` to merge from
697  * @replace_existing: if %TRUE, replace fields in @desc with the
698  *   corresponding values from @desc_to_merge, even if they
699  *   are already exist.
700  *
701  * Merges the fields that are set in @desc_to_merge into the fields in
702  * @desc, without copying allocated fields.
703  *
704  * This is like [method@Pango.FontDescription.merge], but only a shallow copy
705  * is made of the family name and other allocated fields. @desc can only
706  * be used until @desc_to_merge is modified or freed. This is meant to
707  * be used when the merged font description is only needed temporarily.
708  */
709 void
pango_font_description_merge_static(PangoFontDescription * desc,const PangoFontDescription * desc_to_merge,gboolean replace_existing)710 pango_font_description_merge_static (PangoFontDescription       *desc,
711                                      const PangoFontDescription *desc_to_merge,
712                                      gboolean                    replace_existing)
713 {
714   PangoFontMask new_mask;
715 
716   g_return_if_fail (desc != NULL);
717   g_return_if_fail (desc_to_merge != NULL);
718 
719   if (replace_existing)
720     new_mask = desc_to_merge->mask;
721   else
722     new_mask = desc_to_merge->mask & ~desc->mask;
723 
724   if (new_mask & PANGO_FONT_MASK_FAMILY)
725     pango_font_description_set_family_static (desc, desc_to_merge->family_name);
726   if (new_mask & PANGO_FONT_MASK_STYLE)
727     desc->style = desc_to_merge->style;
728   if (new_mask & PANGO_FONT_MASK_VARIANT)
729     desc->variant = desc_to_merge->variant;
730   if (new_mask & PANGO_FONT_MASK_WEIGHT)
731     desc->weight = desc_to_merge->weight;
732   if (new_mask & PANGO_FONT_MASK_STRETCH)
733     desc->stretch = desc_to_merge->stretch;
734   if (new_mask & PANGO_FONT_MASK_SIZE)
735     {
736       desc->size = desc_to_merge->size;
737       desc->size_is_absolute = desc_to_merge->size_is_absolute;
738     }
739   if (new_mask & PANGO_FONT_MASK_GRAVITY)
740     desc->gravity = desc_to_merge->gravity;
741   if (new_mask & PANGO_FONT_MASK_VARIATIONS)
742     pango_font_description_set_variations_static (desc, desc_to_merge->variations);
743 
744   desc->mask |= new_mask;
745 }
746 
747 static gint
compute_distance(const PangoFontDescription * a,const PangoFontDescription * b)748 compute_distance (const PangoFontDescription *a,
749                   const PangoFontDescription *b)
750 {
751   if (a->style == b->style)
752     {
753       return abs((int)(a->weight) - (int)(b->weight));
754     }
755   else if (a->style != PANGO_STYLE_NORMAL &&
756            b->style != PANGO_STYLE_NORMAL)
757     {
758       /* Equate oblique and italic, but with a big penalty
759        */
760       return 1000000 + abs ((int)(a->weight) - (int)(b->weight));
761     }
762   else
763     return G_MAXINT;
764 }
765 
766 /**
767  * pango_font_description_better_match:
768  * @desc: a `PangoFontDescription`
769  * @old_match: (nullable): a `PangoFontDescription`, or %NULL
770  * @new_match: a `PangoFontDescription`
771  *
772  * Determines if the style attributes of @new_match are a closer match
773  * for @desc than those of @old_match are, or if @old_match is %NULL,
774  * determines if @new_match is a match at all.
775  *
776  * Approximate matching is done for weight and style; other style attributes
777  * must match exactly. Style attributes are all attributes other than family
778  * and size-related attributes. Approximate matching for style considers
779  * %PANGO_STYLE_OBLIQUE and %PANGO_STYLE_ITALIC as matches, but not as good
780  * a match as when the styles are equal.
781  *
782  * Note that @old_match must match @desc.
783  *
784  * Return value: %TRUE if @new_match is a better match
785  */
786 gboolean
pango_font_description_better_match(const PangoFontDescription * desc,const PangoFontDescription * old_match,const PangoFontDescription * new_match)787 pango_font_description_better_match (const PangoFontDescription *desc,
788                                      const PangoFontDescription *old_match,
789                                      const PangoFontDescription *new_match)
790 {
791   g_return_val_if_fail (desc != NULL, G_MAXINT);
792   g_return_val_if_fail (new_match != NULL, G_MAXINT);
793 
794   if (new_match->variant == desc->variant &&
795       new_match->stretch == desc->stretch &&
796       new_match->gravity == desc->gravity)
797     {
798       int old_distance = old_match ? compute_distance (desc, old_match) : G_MAXINT;
799       int new_distance = compute_distance (desc, new_match);
800 
801       if (new_distance < old_distance)
802         return TRUE;
803     }
804 
805   return FALSE;
806 }
807 
808 /**
809  * pango_font_description_copy:
810  * @desc: (nullable): a `PangoFontDescription`, may be %NULL
811  *
812  * Make a copy of a `PangoFontDescription`.
813  *
814  * Return value: (nullable): the newly allocated `PangoFontDescription`,
815  *   which should be freed with [method@Pango.FontDescription.free],
816  *   or %NULL if @desc was %NULL.
817  */
818 PangoFontDescription *
pango_font_description_copy(const PangoFontDescription * desc)819 pango_font_description_copy (const PangoFontDescription *desc)
820 {
821   PangoFontDescription *result;
822 
823   if (desc == NULL)
824     return NULL;
825 
826   result = g_slice_new (PangoFontDescription);
827 
828   *result = *desc;
829 
830   if (result->family_name)
831     {
832       result->family_name = g_strdup (result->family_name);
833       result->static_family = FALSE;
834     }
835 
836   result->variations = g_strdup (result->variations);
837   result->static_variations = FALSE;
838 
839   return result;
840 }
841 
842 /**
843  * pango_font_description_copy_static:
844  * @desc: (nullable): a `PangoFontDescription`, may be %NULL
845  *
846  * Make a copy of a `PangoFontDescription`, but don't duplicate
847  * allocated fields.
848  *
849  * This is like [method@Pango.FontDescription.copy], but only a shallow
850  * copy is made of the family name and other allocated fields. The result
851  * can only be used until @desc is modified or freed. This is meant
852  * to be used when the copy is only needed temporarily.
853  *
854  * Return value: (nullable): the newly allocated `PangoFontDescription`,
855  *   which should be freed with [method@Pango.FontDescription.free],
856  *   or %NULL if @desc was %NULL.
857  */
858 PangoFontDescription *
pango_font_description_copy_static(const PangoFontDescription * desc)859 pango_font_description_copy_static (const PangoFontDescription *desc)
860 {
861   PangoFontDescription *result;
862 
863   if (desc == NULL)
864     return NULL;
865 
866   result = g_slice_new (PangoFontDescription);
867 
868   *result = *desc;
869   if (result->family_name)
870     result->static_family = TRUE;
871 
872 
873   if (result->variations)
874     result->static_variations = TRUE;
875 
876   return result;
877 }
878 
879 /**
880  * pango_font_description_equal:
881  * @desc1: a `PangoFontDescription`
882  * @desc2: another `PangoFontDescription`
883  *
884  * Compares two font descriptions for equality.
885  *
886  * Two font descriptions are considered equal if the fonts they describe
887  * are provably identical. This means that their masks do not have to match,
888  * as long as other fields are all the same. (Two font descriptions may
889  * result in identical fonts being loaded, but still compare %FALSE.)
890  *
891  * Return value: %TRUE if the two font descriptions are identical,
892  *   %FALSE otherwise.
893  */
894 gboolean
pango_font_description_equal(const PangoFontDescription * desc1,const PangoFontDescription * desc2)895 pango_font_description_equal (const PangoFontDescription *desc1,
896                               const PangoFontDescription *desc2)
897 {
898   g_return_val_if_fail (desc1 != NULL, FALSE);
899   g_return_val_if_fail (desc2 != NULL, FALSE);
900 
901   return desc1->style == desc2->style &&
902          desc1->variant == desc2->variant &&
903          desc1->weight == desc2->weight &&
904          desc1->stretch == desc2->stretch &&
905          desc1->size == desc2->size &&
906          desc1->size_is_absolute == desc2->size_is_absolute &&
907          desc1->gravity == desc2->gravity &&
908          (desc1->family_name == desc2->family_name ||
909           (desc1->family_name && desc2->family_name && g_ascii_strcasecmp (desc1->family_name, desc2->family_name) == 0)) &&
910          (g_strcmp0 (desc1->variations, desc2->variations) == 0);
911 }
912 
913 #define TOLOWER(c) \
914   (((c) >= 'A' && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
915 
916 static guint
case_insensitive_hash(const char * key)917 case_insensitive_hash (const char *key)
918 {
919   const char *p = key;
920   guint h = TOLOWER (*p);
921 
922   if (h)
923     {
924       for (p += 1; *p != '\0'; p++)
925         h = (h << 5) - h + TOLOWER (*p);
926     }
927 
928   return h;
929 }
930 
931 /**
932  * pango_font_description_hash:
933  * @desc: a `PangoFontDescription`
934  *
935  * Computes a hash of a `PangoFontDescription` structure.
936  *
937  * This is suitable to be used, for example, as an argument
938  * to g_hash_table_new(). The hash value is independent of @desc->mask.
939  *
940  * Return value: the hash value.
941  */
942 guint
pango_font_description_hash(const PangoFontDescription * desc)943 pango_font_description_hash (const PangoFontDescription *desc)
944 {
945   guint hash = 0;
946 
947   g_return_val_if_fail (desc != NULL, 0);
948 
949   if (desc->family_name)
950     hash = case_insensitive_hash (desc->family_name);
951   if (desc->variations)
952     hash ^= g_str_hash (desc->variations);
953   hash ^= desc->size;
954   hash ^= desc->size_is_absolute ? 0xc33ca55a : 0;
955   hash ^= desc->style << 16;
956   hash ^= desc->variant << 18;
957   hash ^= desc->weight << 16;
958   hash ^= desc->stretch << 26;
959   hash ^= desc->gravity << 28;
960 
961   return hash;
962 }
963 
964 /**
965  * pango_font_description_free:
966  * @desc: (nullable): a `PangoFontDescription`, may be %NULL
967  *
968  * Frees a font description.
969  */
970 void
pango_font_description_free(PangoFontDescription * desc)971 pango_font_description_free (PangoFontDescription *desc)
972 {
973   if (desc == NULL)
974     return;
975 
976   if (desc->family_name && !desc->static_family)
977     g_free (desc->family_name);
978 
979   if (desc->variations && !desc->static_variations)
980     g_free (desc->variations);
981 
982   g_slice_free (PangoFontDescription, desc);
983 }
984 
985 /**
986  * pango_font_descriptions_free:
987  * @descs: (nullable) (array length=n_descs) (transfer full): a pointer
988  *   to an array of `PangoFontDescription`, may be %NULL
989  * @n_descs: number of font descriptions in @descs
990  *
991  * Frees an array of font descriptions.
992  */
993 void
pango_font_descriptions_free(PangoFontDescription ** descs,int n_descs)994 pango_font_descriptions_free (PangoFontDescription **descs,
995                               int                    n_descs)
996 {
997   int i;
998 
999   if (descs == NULL)
1000     return;
1001 
1002   for (i = 0; i<n_descs; i++)
1003     pango_font_description_free (descs[i]);
1004   g_free (descs);
1005 }
1006 
1007 typedef struct
1008 {
1009   int value;
1010   const char str[16];
1011 } FieldMap;
1012 
1013 static const FieldMap style_map[] = {
1014   { PANGO_STYLE_NORMAL, "" },
1015   { PANGO_STYLE_NORMAL, "Roman" },
1016   { PANGO_STYLE_OBLIQUE, "Oblique" },
1017   { PANGO_STYLE_ITALIC, "Italic" }
1018 };
1019 
1020 static const FieldMap variant_map[] = {
1021   { PANGO_VARIANT_NORMAL, "" },
1022   { PANGO_VARIANT_SMALL_CAPS, "Small-Caps" }
1023 };
1024 
1025 static const FieldMap weight_map[] = {
1026   { PANGO_WEIGHT_THIN, "Thin" },
1027   { PANGO_WEIGHT_ULTRALIGHT, "Ultra-Light" },
1028   { PANGO_WEIGHT_ULTRALIGHT, "Extra-Light" },
1029   { PANGO_WEIGHT_LIGHT, "Light" },
1030   { PANGO_WEIGHT_SEMILIGHT, "Semi-Light" },
1031   { PANGO_WEIGHT_SEMILIGHT, "Demi-Light" },
1032   { PANGO_WEIGHT_BOOK, "Book" },
1033   { PANGO_WEIGHT_NORMAL, "" },
1034   { PANGO_WEIGHT_NORMAL, "Regular" },
1035   { PANGO_WEIGHT_MEDIUM, "Medium" },
1036   { PANGO_WEIGHT_SEMIBOLD, "Semi-Bold" },
1037   { PANGO_WEIGHT_SEMIBOLD, "Demi-Bold" },
1038   { PANGO_WEIGHT_BOLD, "Bold" },
1039   { PANGO_WEIGHT_ULTRABOLD, "Ultra-Bold" },
1040   { PANGO_WEIGHT_ULTRABOLD, "Extra-Bold" },
1041   { PANGO_WEIGHT_HEAVY, "Heavy" },
1042   { PANGO_WEIGHT_HEAVY, "Black" },
1043   { PANGO_WEIGHT_ULTRAHEAVY, "Ultra-Heavy" },
1044   { PANGO_WEIGHT_ULTRAHEAVY, "Extra-Heavy" },
1045   { PANGO_WEIGHT_ULTRAHEAVY, "Ultra-Black" },
1046   { PANGO_WEIGHT_ULTRAHEAVY, "Extra-Black" }
1047 };
1048 
1049 static const FieldMap stretch_map[] = {
1050   { PANGO_STRETCH_ULTRA_CONDENSED, "Ultra-Condensed" },
1051   { PANGO_STRETCH_EXTRA_CONDENSED, "Extra-Condensed" },
1052   { PANGO_STRETCH_CONDENSED,       "Condensed" },
1053   { PANGO_STRETCH_SEMI_CONDENSED,  "Semi-Condensed" },
1054   { PANGO_STRETCH_NORMAL,          "" },
1055   { PANGO_STRETCH_SEMI_EXPANDED,   "Semi-Expanded" },
1056   { PANGO_STRETCH_EXPANDED,        "Expanded" },
1057   { PANGO_STRETCH_EXTRA_EXPANDED,  "Extra-Expanded" },
1058   { PANGO_STRETCH_ULTRA_EXPANDED,  "Ultra-Expanded" }
1059 };
1060 
1061 static const FieldMap gravity_map[] = {
1062   { PANGO_GRAVITY_SOUTH, "Not-Rotated" },
1063   { PANGO_GRAVITY_SOUTH, "South" },
1064   { PANGO_GRAVITY_NORTH, "Upside-Down" },
1065   { PANGO_GRAVITY_NORTH, "North" },
1066   { PANGO_GRAVITY_EAST,  "Rotated-Left" },
1067   { PANGO_GRAVITY_EAST,  "East" },
1068   { PANGO_GRAVITY_WEST,  "Rotated-Right" },
1069   { PANGO_GRAVITY_WEST,  "West" }
1070 };
1071 
1072 static gboolean
field_matches(const gchar * s1,const gchar * s2,gsize n)1073 field_matches (const gchar *s1,
1074                const gchar *s2,
1075                gsize n)
1076 {
1077   gint c1, c2;
1078 
1079   g_return_val_if_fail (s1 != NULL, 0);
1080   g_return_val_if_fail (s2 != NULL, 0);
1081 
1082   while (n && *s1 && *s2)
1083     {
1084       c1 = (gint)(guchar) TOLOWER (*s1);
1085       c2 = (gint)(guchar) TOLOWER (*s2);
1086       if (c1 != c2) {
1087         if (c1 == '-') {
1088           s1++;
1089           continue;
1090         }
1091         return FALSE;
1092       }
1093       s1++; s2++;
1094       n--;
1095     }
1096 
1097   return n == 0 && *s1 == '\0';
1098 }
1099 
1100 static gboolean
parse_int(const char * word,size_t wordlen,int * out)1101 parse_int (const char *word,
1102            size_t      wordlen,
1103            int        *out)
1104 {
1105   char *end;
1106   long val = strtol (word, &end, 10);
1107   int i = val;
1108 
1109   if (end != word && (end == word + wordlen) && val >= 0 && val == i)
1110     {
1111       if (out)
1112         *out = i;
1113 
1114       return TRUE;
1115     }
1116 
1117   return FALSE;
1118 }
1119 
1120 static gboolean
find_field(const char * what,const FieldMap * map,int n_elements,const char * str,int len,int * val)1121 find_field (const char *what,
1122             const FieldMap *map,
1123             int n_elements,
1124             const char *str,
1125             int len,
1126             int *val)
1127 {
1128   int i;
1129   gboolean had_prefix = FALSE;
1130 
1131   if (what)
1132     {
1133       i = strlen (what);
1134       if (len > i && 0 == strncmp (what, str, i) && str[i] == '=')
1135         {
1136           str += i + 1;
1137           len -= i + 1;
1138           had_prefix = TRUE;
1139         }
1140     }
1141 
1142   for (i=0; i<n_elements; i++)
1143     {
1144       if (map[i].str[0] && field_matches (map[i].str, str, len))
1145         {
1146           if (val)
1147             *val = map[i].value;
1148           return TRUE;
1149         }
1150     }
1151 
1152   if (!what || had_prefix)
1153     return parse_int (str, len, val);
1154 
1155   return FALSE;
1156 }
1157 
1158 static gboolean
find_field_any(const char * str,int len,PangoFontDescription * desc)1159 find_field_any (const char *str, int len, PangoFontDescription *desc)
1160 {
1161   if (field_matches ("Normal", str, len))
1162     return TRUE;
1163 
1164 #define FIELD(NAME, MASK) \
1165   G_STMT_START { \
1166   if (find_field (G_STRINGIFY (NAME), NAME##_map, G_N_ELEMENTS (NAME##_map), str, len, \
1167                   desc ? (int *)(void *)&desc->NAME : NULL)) \
1168     { \
1169       if (desc) \
1170         desc->mask |= MASK; \
1171       return TRUE; \
1172     } \
1173   } G_STMT_END
1174 
1175   FIELD (weight,  PANGO_FONT_MASK_WEIGHT);
1176   FIELD (style,   PANGO_FONT_MASK_STYLE);
1177   FIELD (stretch, PANGO_FONT_MASK_STRETCH);
1178   FIELD (variant, PANGO_FONT_MASK_VARIANT);
1179   FIELD (gravity, PANGO_FONT_MASK_GRAVITY);
1180 
1181 #undef FIELD
1182 
1183   return FALSE;
1184 }
1185 
1186 static const char *
getword(const char * str,const char * last,size_t * wordlen,const char * stop)1187 getword (const char *str, const char *last, size_t *wordlen, const char *stop)
1188 {
1189   const char *result;
1190 
1191   while (last > str && g_ascii_isspace (*(last - 1)))
1192     last--;
1193 
1194   result = last;
1195   while (result > str && !g_ascii_isspace (*(result - 1)) && !strchr (stop, *(result - 1)))
1196     result--;
1197 
1198   *wordlen = last - result;
1199 
1200   return result;
1201 }
1202 
1203 static gboolean
parse_size(const char * word,size_t wordlen,int * pango_size,gboolean * size_is_absolute)1204 parse_size (const char *word,
1205             size_t      wordlen,
1206             int        *pango_size,
1207             gboolean   *size_is_absolute)
1208 {
1209   char *end;
1210   double size = g_ascii_strtod (word, &end);
1211 
1212   if (end != word &&
1213       (end == word + wordlen ||
1214        (end + 2 == word + wordlen && !strncmp (end, "px", 2))
1215       ) && size >= 0 && size <= 1000000) /* word is a valid float */
1216     {
1217       if (pango_size)
1218         *pango_size = (int)(size * PANGO_SCALE + 0.5);
1219 
1220       if (size_is_absolute)
1221         *size_is_absolute = end < word + wordlen;
1222 
1223       return TRUE;
1224     }
1225 
1226   return FALSE;
1227 }
1228 
1229 static gboolean
parse_variations(const char * word,size_t wordlen,char ** variations)1230 parse_variations (const char  *word,
1231                   size_t       wordlen,
1232                   char       **variations)
1233 {
1234   if (word[0] != '@')
1235     {
1236       *variations = NULL;
1237       return FALSE;
1238     }
1239 
1240   /* XXX: actually validate here */
1241   *variations = g_strndup (word + 1, wordlen - 1);
1242 
1243   return TRUE;
1244 }
1245 
1246 /**
1247  * pango_font_description_from_string:
1248  * @str: string representation of a font description.
1249  *
1250  * Creates a new font description from a string representation.
1251  *
1252  * The string must have the form
1253  *
1254  *     "\[FAMILY-LIST] \[STYLE-OPTIONS] \[SIZE] \[VARIATIONS]",
1255  *
1256  * where FAMILY-LIST is a comma-separated list of families optionally
1257  * terminated by a comma, STYLE_OPTIONS is a whitespace-separated list
1258  * of words where each word describes one of style, variant, weight,
1259  * stretch, or gravity, and SIZE is a decimal number (size in points)
1260  * or optionally followed by the unit modifier "px" for absolute size.
1261  * VARIATIONS is a comma-separated list of font variation
1262  * specifications of the form "\@axis=value" (the = sign is optional).
1263  *
1264  * The following words are understood as styles:
1265  * "Normal", "Roman", "Oblique", "Italic".
1266  *
1267  * The following words are understood as variants:
1268  * "Small-Caps".
1269  *
1270  * The following words are understood as weights:
1271  * "Thin", "Ultra-Light", "Extra-Light", "Light", "Semi-Light",
1272  * "Demi-Light", "Book", "Regular", "Medium", "Semi-Bold", "Demi-Bold",
1273  * "Bold", "Ultra-Bold", "Extra-Bold", "Heavy", "Black", "Ultra-Black",
1274  * "Extra-Black".
1275  *
1276  * The following words are understood as stretch values:
1277  * "Ultra-Condensed", "Extra-Condensed", "Condensed", "Semi-Condensed",
1278  * "Semi-Expanded", "Expanded", "Extra-Expanded", "Ultra-Expanded".
1279  *
1280  * The following words are understood as gravity values:
1281  * "Not-Rotated", "South", "Upside-Down", "North", "Rotated-Left",
1282  * "East", "Rotated-Right", "West".
1283  *
1284  * Any one of the options may be absent. If FAMILY-LIST is absent, then
1285  * the family_name field of the resulting font description will be
1286  * initialized to %NULL. If STYLE-OPTIONS is missing, then all style
1287  * options will be set to the default values. If SIZE is missing, the
1288  * size in the resulting font description will be set to 0.
1289  *
1290  * A typical example:
1291  *
1292  *     "Cantarell Italic Light 15 \@wght=200"
1293  *
1294  * Return value: a new `PangoFontDescription`.
1295  */
1296 PangoFontDescription *
pango_font_description_from_string(const char * str)1297 pango_font_description_from_string (const char *str)
1298 {
1299   PangoFontDescription *desc;
1300   const char *p, *last;
1301   size_t len, wordlen;
1302 
1303   g_return_val_if_fail (str != NULL, NULL);
1304 
1305   desc = pango_font_description_new ();
1306 
1307   desc->mask = PANGO_FONT_MASK_STYLE |
1308                PANGO_FONT_MASK_WEIGHT |
1309                PANGO_FONT_MASK_VARIANT |
1310                PANGO_FONT_MASK_STRETCH;
1311 
1312   len = strlen (str);
1313   last = str + len;
1314   p = getword (str, last, &wordlen, "");
1315   /* Look for variations at the end of the string */
1316   if (wordlen != 0)
1317     {
1318       if (parse_variations (p, wordlen, &desc->variations))
1319         {
1320           desc->mask |= PANGO_FONT_MASK_VARIATIONS;
1321           last = p;
1322         }
1323     }
1324 
1325   p = getword (str, last, &wordlen, ",");
1326   /* Look for a size */
1327   if (wordlen != 0)
1328     {
1329       gboolean size_is_absolute;
1330       if (parse_size (p, wordlen, &desc->size, &size_is_absolute))
1331         {
1332           desc->size_is_absolute = size_is_absolute;
1333           desc->mask |= PANGO_FONT_MASK_SIZE;
1334           last = p;
1335         }
1336     }
1337 
1338   /* Now parse style words
1339    */
1340   p = getword (str, last, &wordlen, ",");
1341   while (wordlen != 0)
1342     {
1343       if (!find_field_any (p, wordlen, desc))
1344         break;
1345       else
1346         {
1347           last = p;
1348           p = getword (str, last, &wordlen, ",");
1349         }
1350     }
1351 
1352   /* Remainder (str => p) is family list. Trim off trailing commas and leading and trailing white space
1353    */
1354 
1355   while (last > str && g_ascii_isspace (*(last - 1)))
1356     last--;
1357 
1358   if (last > str && *(last - 1) == ',')
1359     last--;
1360 
1361   while (last > str && g_ascii_isspace (*(last - 1)))
1362     last--;
1363 
1364   while (last > str && g_ascii_isspace (*str))
1365     str++;
1366 
1367   if (str != last)
1368     {
1369       int i;
1370       char **families;
1371 
1372       desc->family_name = g_strndup (str, last - str);
1373 
1374       /* Now sanitize it to trim space from around individual family names.
1375        * bug #499624 */
1376 
1377       families = g_strsplit (desc->family_name, ",", -1);
1378 
1379       for (i = 0; families[i]; i++)
1380         g_strstrip (families[i]);
1381 
1382       g_free (desc->family_name);
1383       desc->family_name = g_strjoinv (",", families);
1384       g_strfreev (families);
1385 
1386       desc->mask |= PANGO_FONT_MASK_FAMILY;
1387     }
1388 
1389   return desc;
1390 }
1391 
1392 static void
append_field(GString * str,const char * what,const FieldMap * map,int n_elements,int val)1393 append_field (GString *str, const char *what, const FieldMap *map, int n_elements, int val)
1394 {
1395   int i;
1396   for (i=0; i<n_elements; i++)
1397     {
1398       if (map[i].value != val)
1399         continue;
1400 
1401       if (G_LIKELY (map[i].str[0]))
1402         {
1403           if (G_LIKELY (str->len > 0 && str->str[str->len -1] != ' '))
1404             g_string_append_c (str, ' ');
1405           g_string_append (str, map[i].str);
1406         }
1407       return;
1408     }
1409 
1410   if (G_LIKELY (str->len > 0 || str->str[str->len -1] != ' '))
1411     g_string_append_c (str, ' ');
1412   g_string_append_printf (str, "%s=%d", what, val);
1413 }
1414 
1415 /**
1416  * pango_font_description_to_string:
1417  * @desc: a `PangoFontDescription`
1418  *
1419  * Creates a string representation of a font description.
1420  *
1421  * See [func@Pango.FontDescription.from_string] for a description
1422  * of the format of the string representation. The family list in
1423  * the string description will only have a terminating comma if
1424  * the last word of the list is a valid style option.
1425  *
1426  * Return value: a new string that must be freed with g_free().
1427  */
1428 char *
pango_font_description_to_string(const PangoFontDescription * desc)1429 pango_font_description_to_string (const PangoFontDescription *desc)
1430 {
1431   GString *result;
1432 
1433   g_return_val_if_fail (desc != NULL, NULL);
1434 
1435   result = g_string_new (NULL);
1436 
1437   if (G_LIKELY (desc->family_name && desc->mask & PANGO_FONT_MASK_FAMILY))
1438     {
1439       const char *p;
1440       size_t wordlen;
1441 
1442       g_string_append (result, desc->family_name);
1443 
1444       /* We need to add a trailing comma if the family name ends
1445        * in a keyword like "Bold", or if the family name ends in
1446        * a number and no keywords will be added.
1447        */
1448       p = getword (desc->family_name, desc->family_name + strlen(desc->family_name), &wordlen, ",");
1449       if (wordlen != 0 &&
1450           (find_field_any (p, wordlen, NULL) ||
1451            (parse_size (p, wordlen, NULL, NULL) &&
1452             desc->weight == PANGO_WEIGHT_NORMAL &&
1453             desc->style == PANGO_STYLE_NORMAL &&
1454             desc->stretch == PANGO_STRETCH_NORMAL &&
1455             desc->variant == PANGO_VARIANT_NORMAL &&
1456             (desc->mask & (PANGO_FONT_MASK_GRAVITY | PANGO_FONT_MASK_SIZE)) == 0)))
1457         g_string_append_c (result, ',');
1458     }
1459 
1460 #define FIELD(NAME, MASK) \
1461   append_field (result, G_STRINGIFY (NAME), NAME##_map, G_N_ELEMENTS (NAME##_map), desc->NAME)
1462 
1463   FIELD (weight,  PANGO_FONT_MASK_WEIGHT);
1464   FIELD (style,   PANGO_FONT_MASK_STYLE);
1465   FIELD (stretch, PANGO_FONT_MASK_STRETCH);
1466   FIELD (variant, PANGO_FONT_MASK_VARIANT);
1467   if (desc->mask & PANGO_FONT_MASK_GRAVITY)
1468     FIELD (gravity, PANGO_FONT_MASK_GRAVITY);
1469 
1470 #undef FIELD
1471 
1472   if (result->len == 0)
1473     g_string_append (result, "Normal");
1474 
1475   if (desc->mask & PANGO_FONT_MASK_SIZE)
1476     {
1477       char buf[G_ASCII_DTOSTR_BUF_SIZE];
1478 
1479       if (result->len > 0 || result->str[result->len -1] != ' ')
1480         g_string_append_c (result, ' ');
1481 
1482       g_ascii_dtostr (buf, sizeof (buf), (double)desc->size / PANGO_SCALE);
1483       g_string_append (result, buf);
1484 
1485       if (desc->size_is_absolute)
1486         g_string_append (result, "px");
1487     }
1488 
1489   if (desc->variations && desc->mask & PANGO_FONT_MASK_VARIATIONS)
1490     {
1491       g_string_append (result, " @");
1492       g_string_append (result, desc->variations);
1493     }
1494 
1495   return g_string_free (result, FALSE);
1496 }
1497 
1498 /**
1499  * pango_font_description_to_filename:
1500  * @desc: a `PangoFontDescription`
1501  *
1502  * Creates a filename representation of a font description.
1503  *
1504  * The filename is identical to the result from calling
1505  * [method@Pango.FontDescription.to_string], but with underscores
1506  * instead of characters that are untypical in filenames, and in
1507  * lower case only.
1508  *
1509  * Return value: a new string that must be freed with g_free().
1510  */
1511 char *
pango_font_description_to_filename(const PangoFontDescription * desc)1512 pango_font_description_to_filename (const PangoFontDescription *desc)
1513 {
1514   char *result;
1515   char *p;
1516 
1517   g_return_val_if_fail (desc != NULL, NULL);
1518 
1519   result = pango_font_description_to_string (desc);
1520 
1521   p = result;
1522   while (*p)
1523     {
1524       if (G_UNLIKELY ((guchar) *p >= 128))
1525         /* skip over non-ASCII chars */;
1526       else if (strchr ("-+_.", *p) == NULL && !g_ascii_isalnum (*p))
1527         *p = '_';
1528       else
1529         *p = g_ascii_tolower (*p);
1530       p++;
1531     }
1532 
1533   return result;
1534 }
1535 
1536 static gboolean
parse_field(const char * what,const FieldMap * map,int n_elements,const char * str,int * val,gboolean warn)1537 parse_field (const char *what,
1538              const FieldMap *map,
1539              int n_elements,
1540              const char *str,
1541              int *val,
1542              gboolean warn)
1543 {
1544   gboolean found;
1545   int len = strlen (str);
1546 
1547   if (G_UNLIKELY (*str == '\0'))
1548     return FALSE;
1549 
1550   if (field_matches ("Normal", str, len))
1551     {
1552       /* find the map entry with empty string */
1553       int i;
1554 
1555       for (i = 0; i < n_elements; i++)
1556         if (map[i].str[0] == '\0')
1557           {
1558             *val = map[i].value;
1559             return TRUE;
1560           }
1561 
1562       *val = 0;
1563       return TRUE;
1564     }
1565 
1566   found = find_field (NULL, map, n_elements, str, len, val);
1567 
1568   if (!found && warn)
1569     {
1570         int i;
1571         GString *s = g_string_new (NULL);
1572 
1573         for (i = 0; i < n_elements; i++)
1574           {
1575             if (i)
1576               g_string_append_c (s, '/');
1577             g_string_append (s, map[i].str[0] == '\0' ? "Normal" : map[i].str);
1578           }
1579 
1580         g_warning ("%s must be one of %s or a number",
1581                    what,
1582                    s->str);
1583 
1584         g_string_free (s, TRUE);
1585     }
1586 
1587   return found;
1588 }
1589 
1590 #define FIELD(NAME, MASK) \
1591   parse_field (G_STRINGIFY (NAME), NAME##_map, G_N_ELEMENTS (NAME##_map), str, (int *)(void *)NAME, warn)
1592 
1593 /**
1594  * pango_parse_style:
1595  * @str: a string to parse.
1596  * @style: (out): a `PangoStyle` to store the result in.
1597  * @warn: if %TRUE, issue a g_warning() on bad input.
1598  *
1599  * Parses a font style.
1600  *
1601  * The allowed values are "normal", "italic" and "oblique", case
1602  * variations being
1603  * ignored.
1604  *
1605  * Return value: %TRUE if @str was successfully parsed.
1606  */
1607 gboolean
pango_parse_style(const char * str,PangoStyle * style,gboolean warn)1608 pango_parse_style (const char *str,
1609                    PangoStyle *style,
1610                    gboolean    warn)
1611 {
1612   return FIELD (style,   PANGO_FONT_MASK_STYLE);
1613 }
1614 
1615 /**
1616  * pango_parse_variant:
1617  * @str: a string to parse.
1618  * @variant: (out): a `PangoVariant` to store the result in.
1619  * @warn: if %TRUE, issue a g_warning() on bad input.
1620  *
1621  * Parses a font variant.
1622  *
1623  * The allowed values are "normal" and "smallcaps" or "small_caps",
1624  * case variations being ignored.
1625  *
1626  * Return value: %TRUE if @str was successfully parsed.
1627  */
1628 gboolean
pango_parse_variant(const char * str,PangoVariant * variant,gboolean warn)1629 pango_parse_variant (const char   *str,
1630                      PangoVariant *variant,
1631                      gboolean      warn)
1632 {
1633   return FIELD (variant, PANGO_FONT_MASK_VARIANT);
1634 }
1635 
1636 /**
1637  * pango_parse_weight:
1638  * @str: a string to parse.
1639  * @weight: (out): a `PangoWeight` to store the result in.
1640  * @warn: if %TRUE, issue a g_warning() on bad input.
1641  *
1642  * Parses a font weight.
1643  *
1644  * The allowed values are "heavy",
1645  * "ultrabold", "bold", "normal", "light", "ultraleight"
1646  * and integers. Case variations are ignored.
1647  *
1648  * Return value: %TRUE if @str was successfully parsed.
1649  */
1650 gboolean
pango_parse_weight(const char * str,PangoWeight * weight,gboolean warn)1651 pango_parse_weight (const char  *str,
1652                     PangoWeight *weight,
1653                     gboolean     warn)
1654 {
1655   return FIELD (weight,  PANGO_FONT_MASK_WEIGHT);
1656 }
1657 
1658 /**
1659  * pango_parse_stretch:
1660  * @str: a string to parse.
1661  * @stretch: (out): a `PangoStretch` to store the result in.
1662  * @warn: if %TRUE, issue a g_warning() on bad input.
1663  *
1664  * Parses a font stretch.
1665  *
1666  * The allowed values are
1667  * "ultra_condensed", "extra_condensed", "condensed",
1668  * "semi_condensed", "normal", "semi_expanded", "expanded",
1669  * "extra_expanded" and "ultra_expanded". Case variations are
1670  * ignored and the '_' characters may be omitted.
1671  *
1672  * Return value: %TRUE if @str was successfully parsed.
1673  */
1674 gboolean
pango_parse_stretch(const char * str,PangoStretch * stretch,gboolean warn)1675 pango_parse_stretch (const char   *str,
1676                      PangoStretch *stretch,
1677                      gboolean      warn)
1678 {
1679   return FIELD (stretch, PANGO_FONT_MASK_STRETCH);
1680 }
1681 
1682 
1683 /*
1684  * PangoFont
1685  */
1686 
1687 typedef struct {
1688   hb_font_t *hb_font;
1689 } PangoFontPrivate;
1690 
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(PangoFont,pango_font,G_TYPE_OBJECT)1691 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (PangoFont, pango_font, G_TYPE_OBJECT)
1692 
1693 static void
1694 pango_font_finalize (GObject *object)
1695 {
1696   PangoFont *font = PANGO_FONT (object);
1697   PangoFontPrivate *priv = pango_font_get_instance_private (font);
1698 
1699   hb_font_destroy (priv->hb_font);
1700 
1701   G_OBJECT_CLASS (pango_font_parent_class)->finalize (object);
1702 }
1703 
1704 static void
pango_font_class_init(PangoFontClass * class G_GNUC_UNUSED)1705 pango_font_class_init (PangoFontClass *class G_GNUC_UNUSED)
1706 {
1707   GObjectClass *object_class = G_OBJECT_CLASS (class);
1708 
1709   object_class->finalize = pango_font_finalize;
1710 }
1711 
1712 static void
pango_font_init(PangoFont * font G_GNUC_UNUSED)1713 pango_font_init (PangoFont *font G_GNUC_UNUSED)
1714 {
1715 }
1716 
1717 /**
1718  * pango_font_describe:
1719  * @font: a `PangoFont`
1720  *
1721  * Returns a description of the font, with font size set in points.
1722  *
1723  * Use [method@Pango.Font.describe_with_absolute_size] if you want
1724  * the font size in device units.
1725  *
1726  * Return value: a newly-allocated `PangoFontDescription` object.
1727  */
1728 PangoFontDescription *
pango_font_describe(PangoFont * font)1729 pango_font_describe (PangoFont *font)
1730 {
1731   g_return_val_if_fail (font != NULL, NULL);
1732 
1733   return PANGO_FONT_GET_CLASS (font)->describe (font);
1734 }
1735 
1736 /**
1737  * pango_font_describe_with_absolute_size:
1738  * @font: a `PangoFont`
1739  *
1740  * Returns a description of the font, with absolute font size set
1741  * in device units.
1742  *
1743  * Use [method@Pango.Font.describe] if you want the font size in points.
1744  *
1745  * Return value: a newly-allocated `PangoFontDescription` object.
1746  *
1747  * Since: 1.14
1748  */
1749 PangoFontDescription *
pango_font_describe_with_absolute_size(PangoFont * font)1750 pango_font_describe_with_absolute_size (PangoFont *font)
1751 {
1752   g_return_val_if_fail (font != NULL, NULL);
1753 
1754   if (G_UNLIKELY (!PANGO_FONT_GET_CLASS (font)->describe_absolute))
1755     {
1756       g_warning ("describe_absolute not implemented for this font class, report this as a bug");
1757       return pango_font_describe (font);
1758     }
1759 
1760   return PANGO_FONT_GET_CLASS (font)->describe_absolute (font);
1761 }
1762 
1763 /**
1764  * pango_font_get_coverage:
1765  * @font: a `PangoFont`
1766  * @language: the language tag
1767  *
1768  * Computes the coverage map for a given font and language tag.
1769  *
1770  * Return value: (transfer full): a newly-allocated `PangoCoverage`
1771  *   object.
1772  */
1773 PangoCoverage *
pango_font_get_coverage(PangoFont * font,PangoLanguage * language)1774 pango_font_get_coverage (PangoFont     *font,
1775                          PangoLanguage *language)
1776 {
1777   g_return_val_if_fail (font != NULL, NULL);
1778 
1779   return PANGO_FONT_GET_CLASS (font)->get_coverage (font, language);
1780 }
1781 
1782 /**
1783  * pango_font_find_shaper:
1784  * @font: a `PangoFont`
1785  * @language: the language tag
1786  * @ch: a Unicode character.
1787  *
1788  * Finds the best matching shaper for a font for a particular
1789  * language tag and character point.
1790  *
1791  * Return value: (transfer none): the best matching shaper.
1792  * Deprecated: Shape engines are no longer used
1793  */
1794 PangoEngineShape *
pango_font_find_shaper(PangoFont * font,PangoLanguage * language,guint32 ch)1795 pango_font_find_shaper (PangoFont     *font,
1796                         PangoLanguage *language,
1797                         guint32        ch)
1798 {
1799   return NULL;
1800 }
1801 
1802 /**
1803  * pango_font_get_glyph_extents:
1804  * @font: (nullable): a `PangoFont`
1805  * @glyph: the glyph index
1806  * @ink_rect: (out) (optional): rectangle used to store the extents of the glyph as drawn
1807  * @logical_rect: (out) (optional): rectangle used to store the logical extents of the glyph
1808  *
1809  * Gets the logical and ink extents of a glyph within a font.
1810  *
1811  * The coordinate system for each rectangle has its origin at the
1812  * base line and horizontal origin of the character with increasing
1813  * coordinates extending to the right and down. The macros PANGO_ASCENT(),
1814  * PANGO_DESCENT(), PANGO_LBEARING(), and PANGO_RBEARING() can be used to convert
1815  * from the extents rectangle to more traditional font metrics. The units
1816  * of the rectangles are in 1/PANGO_SCALE of a device unit.
1817  *
1818  * If @font is %NULL, this function gracefully sets some sane values in the
1819  * output variables and returns.
1820  */
1821 void
pango_font_get_glyph_extents(PangoFont * font,PangoGlyph glyph,PangoRectangle * ink_rect,PangoRectangle * logical_rect)1822 pango_font_get_glyph_extents  (PangoFont      *font,
1823                                PangoGlyph      glyph,
1824                                PangoRectangle *ink_rect,
1825                                PangoRectangle *logical_rect)
1826 {
1827   if (G_UNLIKELY (!font))
1828     {
1829       if (ink_rect)
1830         {
1831           ink_rect->x = PANGO_SCALE;
1832           ink_rect->y = - (PANGO_UNKNOWN_GLYPH_HEIGHT - 1) * PANGO_SCALE;
1833           ink_rect->height = (PANGO_UNKNOWN_GLYPH_HEIGHT - 2) * PANGO_SCALE;
1834           ink_rect->width = (PANGO_UNKNOWN_GLYPH_WIDTH - 2) * PANGO_SCALE;
1835         }
1836       if (logical_rect)
1837         {
1838           logical_rect->x = 0;
1839           logical_rect->y = - PANGO_UNKNOWN_GLYPH_HEIGHT * PANGO_SCALE;
1840           logical_rect->height = PANGO_UNKNOWN_GLYPH_HEIGHT * PANGO_SCALE;
1841           logical_rect->width = PANGO_UNKNOWN_GLYPH_WIDTH * PANGO_SCALE;
1842         }
1843       return;
1844     }
1845 
1846   PANGO_FONT_GET_CLASS (font)->get_glyph_extents (font, glyph, ink_rect, logical_rect);
1847 }
1848 
1849 /**
1850  * pango_font_get_metrics:
1851  * @font: (nullable): a `PangoFont`
1852  * @language: (nullable): language tag used to determine which script
1853  *   to get the metrics for, or %NULL to indicate to get the metrics for
1854  *   the entire font.
1855  *
1856  * Gets overall metric information for a font.
1857  *
1858  * Since the metrics may be substantially different for different scripts,
1859  * a language tag can be provided to indicate that the metrics should be
1860  * retrieved that correspond to the script(s) used by that language.
1861  *
1862  * If @font is %NULL, this function gracefully sets some sane values in the
1863  * output variables and returns.
1864  *
1865  * Return value: a `PangoFontMetrics` object. The caller must call
1866  *   [method@Pango.FontMetrics.unref] when finished using the object.
1867  */
1868 PangoFontMetrics *
pango_font_get_metrics(PangoFont * font,PangoLanguage * language)1869 pango_font_get_metrics (PangoFont     *font,
1870                         PangoLanguage *language)
1871 {
1872   if (G_UNLIKELY (!font))
1873     {
1874       PangoFontMetrics *metrics = pango_font_metrics_new ();
1875 
1876       metrics->ascent = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT;
1877       metrics->descent = 0;
1878       metrics->height = 0;
1879       metrics->approximate_char_width = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_WIDTH;
1880       metrics->approximate_digit_width = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_WIDTH;
1881       metrics->underline_position = -PANGO_SCALE;
1882       metrics->underline_thickness = PANGO_SCALE;
1883       metrics->strikethrough_position = PANGO_SCALE * PANGO_UNKNOWN_GLYPH_HEIGHT / 2;
1884       metrics->strikethrough_thickness = PANGO_SCALE;
1885 
1886       return metrics;
1887     }
1888 
1889   return PANGO_FONT_GET_CLASS (font)->get_metrics (font, language);
1890 }
1891 
1892 /**
1893  * pango_font_get_font_map:
1894  * @font: (nullable): a `PangoFont`
1895  *
1896  * Gets the font map for which the font was created.
1897  *
1898  * Note that the font maintains a *weak* reference to
1899  * the font map, so if all references to font map are
1900  * dropped, the font map will be finalized even if there
1901  * are fonts created with the font map that are still alive.
1902  * In that case this function will return %NULL.
1903  *
1904  * It is the responsibility of the user to ensure that the
1905  * font map is kept alive. In most uses this is not an issue
1906  * as a `PangoContext` holds a reference to the font map.
1907  *
1908  * Return value: (transfer none) (nullable): the `PangoFontMap`
1909  *   for the font
1910  *
1911  * Since: 1.10
1912  */
1913 PangoFontMap *
pango_font_get_font_map(PangoFont * font)1914 pango_font_get_font_map (PangoFont *font)
1915 {
1916   if (G_UNLIKELY (!font))
1917     return NULL;
1918 
1919   if (PANGO_FONT_GET_CLASS (font)->get_font_map)
1920     return PANGO_FONT_GET_CLASS (font)->get_font_map (font);
1921   else
1922     return NULL;
1923 }
1924 
1925 /**
1926  * pango_font_get_face:
1927  * @font: a `PangoFont`
1928  *
1929  * Gets the `PangoFontFace` to which @font belongs.
1930  *
1931  * Returns: (transfer none): the `PangoFontFace`
1932  *
1933  * Since: 1.46
1934  */
1935 PangoFontFace *
pango_font_get_face(PangoFont * font)1936 pango_font_get_face (PangoFont *font)
1937 {
1938   PangoFontMap *map = pango_font_get_font_map (font);
1939 
1940   return PANGO_FONT_MAP_GET_CLASS (map)->get_face (map,font);
1941 }
1942 
1943 /**
1944  * pango_font_get_hb_font: (skip)
1945  * @font: a `PangoFont`
1946  *
1947  * Get a `hb_font_t` object backing this font.
1948  *
1949  * Note that the objects returned by this function are cached
1950  * and immutable. If you need to make changes to the `hb_font_t`,
1951  * use hb_font_create_sub_font().
1952  *
1953  * Returns: (transfer none) (nullable): the `hb_font_t` object
1954  *   backing the font
1955  *
1956  * Since: 1.44
1957  */
1958 hb_font_t *
pango_font_get_hb_font(PangoFont * font)1959 pango_font_get_hb_font (PangoFont *font)
1960 {
1961   PangoFontPrivate *priv = pango_font_get_instance_private (font);
1962 
1963   g_return_val_if_fail (PANGO_IS_FONT (font), NULL);
1964 
1965   if (priv->hb_font)
1966     return priv->hb_font;
1967 
1968   priv->hb_font = PANGO_FONT_GET_CLASS (font)->create_hb_font (font);
1969 
1970   hb_font_make_immutable (priv->hb_font);
1971 
1972   return priv->hb_font;
1973 }
1974 
1975 G_DEFINE_BOXED_TYPE (PangoFontMetrics, pango_font_metrics,
1976                      pango_font_metrics_ref,
1977                      pango_font_metrics_unref);
1978 
1979 /**
1980  * pango_font_metrics_new:
1981  *
1982  * Creates a new `PangoFontMetrics` structure.
1983  *
1984  * This is only for internal use by Pango backends and there is
1985  * no public way to set the fields of the structure.
1986  *
1987  * Return value: a newly-created `PangoFontMetrics` structure
1988  *   with a reference count of 1.
1989  */
1990 PangoFontMetrics *
pango_font_metrics_new(void)1991 pango_font_metrics_new (void)
1992 {
1993   PangoFontMetrics *metrics = g_slice_new0 (PangoFontMetrics);
1994   metrics->ref_count = 1;
1995 
1996   return metrics;
1997 }
1998 
1999 /**
2000  * pango_font_metrics_ref:
2001  * @metrics: (nullable): a `PangoFontMetrics` structure, may be %NULL
2002  *
2003  * Increase the reference count of a font metrics structure by one.
2004  *
2005  * Return value: (nullable): @metrics
2006  */
2007 PangoFontMetrics *
pango_font_metrics_ref(PangoFontMetrics * metrics)2008 pango_font_metrics_ref (PangoFontMetrics *metrics)
2009 {
2010   if (metrics == NULL)
2011     return NULL;
2012 
2013   g_atomic_int_inc ((int *) &metrics->ref_count);
2014 
2015   return metrics;
2016 }
2017 
2018 /**
2019  * pango_font_metrics_unref:
2020  * @metrics: (nullable): a `PangoFontMetrics` structure, may be %NULL
2021  *
2022  * Decrease the reference count of a font metrics structure by one.
2023  * If the result is zero, frees the structure and any associated memory.
2024  */
2025 void
pango_font_metrics_unref(PangoFontMetrics * metrics)2026 pango_font_metrics_unref (PangoFontMetrics *metrics)
2027 {
2028   if (metrics == NULL)
2029     return;
2030 
2031   g_return_if_fail (metrics->ref_count > 0 );
2032 
2033   if (g_atomic_int_dec_and_test ((int *) &metrics->ref_count))
2034     g_slice_free (PangoFontMetrics, metrics);
2035 }
2036 
2037 /**
2038  * pango_font_metrics_get_ascent:
2039  * @metrics: a `PangoFontMetrics` structure
2040  *
2041  * Gets the ascent from a font metrics structure.
2042  *
2043  * The ascent is the distance from the baseline to the logical top
2044  * of a line of text. (The logical top may be above or below the top
2045  * of the actual drawn ink. It is necessary to lay out the text to
2046  * figure where the ink will be.)
2047  *
2048  * Return value: the ascent, in Pango units.
2049  */
2050 int
pango_font_metrics_get_ascent(PangoFontMetrics * metrics)2051 pango_font_metrics_get_ascent (PangoFontMetrics *metrics)
2052 {
2053   g_return_val_if_fail (metrics != NULL, 0);
2054 
2055   return metrics->ascent;
2056 }
2057 
2058 /**
2059  * pango_font_metrics_get_descent:
2060  * @metrics: a `PangoFontMetrics` structure
2061  *
2062  * Gets the descent from a font metrics structure.
2063  *
2064  * The descent is the distance from the baseline to the logical bottom
2065  * of a line of text. (The logical bottom may be above or below the
2066  * bottom of the actual drawn ink. It is necessary to lay out the text
2067  * to figure where the ink will be.)
2068  *
2069  * Return value: the descent, in Pango units.
2070  */
2071 int
pango_font_metrics_get_descent(PangoFontMetrics * metrics)2072 pango_font_metrics_get_descent (PangoFontMetrics *metrics)
2073 {
2074   g_return_val_if_fail (metrics != NULL, 0);
2075 
2076   return metrics->descent;
2077 }
2078 
2079 /**
2080  * pango_font_metrics_get_height:
2081  * @metrics: a `PangoFontMetrics` structure
2082  *
2083  * Gets the line height from a font metrics structure.
2084  *
2085  * The line height is the distance between successive baselines
2086  * in wrapped text.
2087  *
2088  * If the line height is not available, 0 is returned.
2089  *
2090  * Return value: the height, in Pango units
2091  *
2092  * Since: 1.44
2093  */
2094 int
pango_font_metrics_get_height(PangoFontMetrics * metrics)2095 pango_font_metrics_get_height (PangoFontMetrics *metrics)
2096 {
2097   g_return_val_if_fail (metrics != NULL, 0);
2098 
2099   return metrics->height;
2100 }
2101 
2102 /**
2103  * pango_font_metrics_get_approximate_char_width:
2104  * @metrics: a `PangoFontMetrics` structure
2105  *
2106  * Gets the approximate character width for a font metrics structure.
2107  *
2108  * This is merely a representative value useful, for example, for
2109  * determining the initial size for a window. Actual characters in
2110  * text will be wider and narrower than this.
2111  *
2112  * Return value: the character width, in Pango units.
2113  */
2114 int
pango_font_metrics_get_approximate_char_width(PangoFontMetrics * metrics)2115 pango_font_metrics_get_approximate_char_width (PangoFontMetrics *metrics)
2116 {
2117   g_return_val_if_fail (metrics != NULL, 0);
2118 
2119   return metrics->approximate_char_width;
2120 }
2121 
2122 /**
2123  * pango_font_metrics_get_approximate_digit_width:
2124  * @metrics: a `PangoFontMetrics` structure
2125  *
2126  * Gets the approximate digit width for a font metrics structure.
2127  *
2128  * This is merely a representative value useful, for example, for
2129  * determining the initial size for a window. Actual digits in
2130  * text can be wider or narrower than this, though this value
2131  * is generally somewhat more accurate than the result of
2132  * pango_font_metrics_get_approximate_char_width() for digits.
2133  *
2134  * Return value: the digit width, in Pango units.
2135  */
2136 int
pango_font_metrics_get_approximate_digit_width(PangoFontMetrics * metrics)2137 pango_font_metrics_get_approximate_digit_width (PangoFontMetrics *metrics)
2138 {
2139   g_return_val_if_fail (metrics != NULL, 0);
2140 
2141   return metrics->approximate_digit_width;
2142 }
2143 
2144 /**
2145  * pango_font_metrics_get_underline_position:
2146  * @metrics: a `PangoFontMetrics` structure
2147  *
2148  * Gets the suggested position to draw the underline.
2149  *
2150  * The value returned is the distance *above* the baseline of the top
2151  * of the underline. Since most fonts have underline positions beneath
2152  * the baseline, this value is typically negative.
2153  *
2154  * Return value: the suggested underline position, in Pango units.
2155  *
2156  * Since: 1.6
2157  */
2158 int
pango_font_metrics_get_underline_position(PangoFontMetrics * metrics)2159 pango_font_metrics_get_underline_position (PangoFontMetrics *metrics)
2160 {
2161   g_return_val_if_fail (metrics != NULL, 0);
2162 
2163   return metrics->underline_position;
2164 }
2165 
2166 /**
2167  * pango_font_metrics_get_underline_thickness:
2168  * @metrics: a `PangoFontMetrics` structure
2169  *
2170  * Gets the suggested thickness to draw for the underline.
2171  *
2172  * Return value: the suggested underline thickness, in Pango units.
2173  *
2174  * Since: 1.6
2175  */
2176 int
pango_font_metrics_get_underline_thickness(PangoFontMetrics * metrics)2177 pango_font_metrics_get_underline_thickness (PangoFontMetrics *metrics)
2178 {
2179   g_return_val_if_fail (metrics != NULL, 0);
2180 
2181   return metrics->underline_thickness;
2182 }
2183 
2184 /**
2185  * pango_font_metrics_get_strikethrough_position:
2186  * @metrics: a `PangoFontMetrics` structure
2187  *
2188  * Gets the suggested position to draw the strikethrough.
2189  *
2190  * The value returned is the distance *above* the
2191  * baseline of the top of the strikethrough.
2192  *
2193  * Return value: the suggested strikethrough position, in Pango units.
2194  *
2195  * Since: 1.6
2196  */
2197 int
pango_font_metrics_get_strikethrough_position(PangoFontMetrics * metrics)2198 pango_font_metrics_get_strikethrough_position (PangoFontMetrics *metrics)
2199 {
2200   g_return_val_if_fail (metrics != NULL, 0);
2201 
2202   return metrics->strikethrough_position;
2203 }
2204 
2205 /**
2206  * pango_font_metrics_get_strikethrough_thickness:
2207  * @metrics: a `PangoFontMetrics` structure
2208  *
2209  * Gets the suggested thickness to draw for the strikethrough.
2210  *
2211  * Return value: the suggested strikethrough thickness, in Pango units.
2212  *
2213  * Since: 1.6
2214  */
2215 int
pango_font_metrics_get_strikethrough_thickness(PangoFontMetrics * metrics)2216 pango_font_metrics_get_strikethrough_thickness (PangoFontMetrics *metrics)
2217 {
2218   g_return_val_if_fail (metrics != NULL, 0);
2219 
2220   return metrics->strikethrough_thickness;
2221 }
2222 
2223 /*
2224  * PangoFontFamily
2225  */
2226 
2227 static GType
pango_font_family_get_item_type(GListModel * list)2228 pango_font_family_get_item_type (GListModel *list)
2229 {
2230   return PANGO_TYPE_FONT_FACE;
2231 }
2232 
2233 static guint
pango_font_family_get_n_items(GListModel * list)2234 pango_font_family_get_n_items (GListModel *list)
2235 {
2236   PangoFontFamily *family = PANGO_FONT_FAMILY (list);
2237   int n_faces;
2238 
2239   pango_font_family_list_faces (family, NULL, &n_faces);
2240 
2241   return (guint)n_faces;
2242 }
2243 
2244 static gpointer
pango_font_family_get_item(GListModel * list,guint position)2245 pango_font_family_get_item (GListModel *list,
2246                             guint       position)
2247 {
2248   PangoFontFamily *family = PANGO_FONT_FAMILY (list);
2249   PangoFontFace **faces;
2250   int n_faces;
2251   PangoFontFace *face;
2252 
2253   pango_font_family_list_faces (family, &faces, &n_faces);
2254 
2255   if (position < n_faces)
2256     face = g_object_ref (faces[position]);
2257   else
2258     face = NULL;
2259 
2260   g_free (faces);
2261 
2262   return face;
2263 }
2264 
2265 static void
pango_font_family_list_model_init(GListModelInterface * iface)2266 pango_font_family_list_model_init (GListModelInterface *iface)
2267 {
2268   iface->get_item_type = pango_font_family_get_item_type;
2269   iface->get_n_items = pango_font_family_get_n_items;
2270   iface->get_item = pango_font_family_get_item;
2271 }
2272 
2273 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PangoFontFamily, pango_font_family, G_TYPE_OBJECT,
2274                                   G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, pango_font_family_list_model_init))
2275 
2276 static PangoFontFace *pango_font_family_real_get_face (PangoFontFamily *family,
2277                                                        const char      *name);
2278 
2279 static void
pango_font_family_class_init(PangoFontFamilyClass * class G_GNUC_UNUSED)2280 pango_font_family_class_init (PangoFontFamilyClass *class G_GNUC_UNUSED)
2281 {
2282   class->get_face = pango_font_family_real_get_face;
2283 }
2284 
2285 static void
pango_font_family_init(PangoFontFamily * family G_GNUC_UNUSED)2286 pango_font_family_init (PangoFontFamily *family G_GNUC_UNUSED)
2287 {
2288 }
2289 
2290 /**
2291  * pango_font_family_get_name:
2292  * @family: a `PangoFontFamily`
2293  *
2294  * Gets the name of the family.
2295  *
2296  * The name is unique among all fonts for the font backend and can
2297  * be used in a `PangoFontDescription` to specify that a face from
2298  * this family is desired.
2299  *
2300  * Return value: the name of the family. This string is owned
2301  *   by the family object and must not be modified or freed.
2302  */
2303 const char *
pango_font_family_get_name(PangoFontFamily * family)2304 pango_font_family_get_name (PangoFontFamily  *family)
2305 {
2306   g_return_val_if_fail (PANGO_IS_FONT_FAMILY (family), NULL);
2307 
2308   return PANGO_FONT_FAMILY_GET_CLASS (family)->get_name (family);
2309 }
2310 
2311 /**
2312  * pango_font_family_list_faces:
2313  * @family: a `PangoFontFamily`
2314  * @faces: (out) (optional) (array length=n_faces) (transfer container):
2315  *   location to store an array of pointers to `PangoFontFace` objects,
2316  *   or %NULL. This array should be freed with g_free() when it is no
2317  *   longer needed.
2318  * @n_faces: (out): location to store number of elements in @faces.
2319  *
2320  * Lists the different font faces that make up @family.
2321  *
2322  * The faces in a family share a common design, but differ in slant, weight,
2323  * width and other aspects.
2324  */
2325 void
pango_font_family_list_faces(PangoFontFamily * family,PangoFontFace *** faces,int * n_faces)2326 pango_font_family_list_faces (PangoFontFamily  *family,
2327                               PangoFontFace  ***faces,
2328                               int              *n_faces)
2329 {
2330   g_return_if_fail (PANGO_IS_FONT_FAMILY (family));
2331 
2332   PANGO_FONT_FAMILY_GET_CLASS (family)->list_faces (family, faces, n_faces);
2333 }
2334 
2335 static PangoFontFace *
pango_font_family_real_get_face(PangoFontFamily * family,const char * name)2336 pango_font_family_real_get_face (PangoFontFamily *family,
2337                                  const char      *name)
2338 {
2339   PangoFontFace **faces;
2340   int n_faces;
2341   PangoFontFace *face;
2342   int i;
2343 
2344   pango_font_family_list_faces (family, &faces, &n_faces);
2345 
2346   face = NULL;
2347   if (name == NULL)
2348     {
2349       face = faces[0];
2350     }
2351   else
2352     {
2353       for (i = 0; i < n_faces; i++)
2354         {
2355           if (strcmp (name, pango_font_face_get_face_name (faces[i])) == 0)
2356             {
2357               face = faces[i];
2358               break;
2359             }
2360         }
2361     }
2362 
2363   g_free (faces);
2364 
2365   return face;
2366 }
2367 
2368 /**
2369  * pango_font_family_get_face:
2370  * @family: a `PangoFontFamily`
2371  * @name: (nullable): the name of a face. If the name is %NULL,
2372  *   the family's default face (fontconfig calls it "Regular")
2373  *   will be returned.
2374  *
2375  * Gets the `PangoFontFace` of @family with the given name.
2376  *
2377  * Returns: (transfer none) (nullable): the `PangoFontFace`,
2378  *   or %NULL if no face with the given name exists.
2379  *
2380  * Since: 1.46
2381  */
2382 PangoFontFace *
pango_font_family_get_face(PangoFontFamily * family,const char * name)2383 pango_font_family_get_face (PangoFontFamily *family,
2384                             const char      *name)
2385 {
2386   g_return_val_if_fail (PANGO_IS_FONT_FAMILY (family), NULL);
2387 
2388   return PANGO_FONT_FAMILY_GET_CLASS (family)->get_face (family, name);
2389 }
2390 
2391 /**
2392  * pango_font_family_is_monospace:
2393  * @family: a `PangoFontFamily`
2394  *
2395  * A monospace font is a font designed for text display where the the
2396  * characters form a regular grid.
2397  *
2398  * For Western languages this would
2399  * mean that the advance width of all characters are the same, but
2400  * this categorization also includes Asian fonts which include
2401  * double-width characters: characters that occupy two grid cells.
2402  * g_unichar_iswide() returns a result that indicates whether a
2403  * character is typically double-width in a monospace font.
2404  *
2405  * The best way to find out the grid-cell size is to call
2406  * [method@Pango.FontMetrics.get_approximate_digit_width], since the
2407  * results of [method@Pango.FontMetrics.get_approximate_char_width] may
2408  * be affected by double-width characters.
2409  *
2410  * Return value: %TRUE if the family is monospace.
2411  *
2412  * Since: 1.4
2413  */
2414 gboolean
pango_font_family_is_monospace(PangoFontFamily * family)2415 pango_font_family_is_monospace (PangoFontFamily  *family)
2416 {
2417   g_return_val_if_fail (PANGO_IS_FONT_FAMILY (family), FALSE);
2418 
2419   if (PANGO_FONT_FAMILY_GET_CLASS (family)->is_monospace)
2420     return PANGO_FONT_FAMILY_GET_CLASS (family)->is_monospace (family);
2421   else
2422     return FALSE;
2423 }
2424 
2425 /**
2426  * pango_font_family_is_variable:
2427  * @family: a `PangoFontFamily`
2428  *
2429  * A variable font is a font which has axes that can be modified to
2430  * produce different faces.
2431  *
2432  * Return value: %TRUE if the family is variable
2433  *
2434  * Since: 1.44
2435  */
2436 gboolean
pango_font_family_is_variable(PangoFontFamily * family)2437 pango_font_family_is_variable (PangoFontFamily  *family)
2438 {
2439   g_return_val_if_fail (PANGO_IS_FONT_FAMILY (family), FALSE);
2440 
2441   if (PANGO_FONT_FAMILY_GET_CLASS (family)->is_variable)
2442     return PANGO_FONT_FAMILY_GET_CLASS (family)->is_variable (family);
2443   else
2444     return FALSE;
2445 }
2446 
2447 /*
2448  * PangoFontFace
2449  */
2450 
G_DEFINE_ABSTRACT_TYPE(PangoFontFace,pango_font_face,G_TYPE_OBJECT)2451 G_DEFINE_ABSTRACT_TYPE (PangoFontFace, pango_font_face, G_TYPE_OBJECT)
2452 
2453 static void
2454 pango_font_face_class_init (PangoFontFaceClass *class G_GNUC_UNUSED)
2455 {
2456 }
2457 
2458 static void
pango_font_face_init(PangoFontFace * face G_GNUC_UNUSED)2459 pango_font_face_init (PangoFontFace *face G_GNUC_UNUSED)
2460 {
2461 }
2462 
2463 /**
2464  * pango_font_face_describe:
2465  * @face: a `PangoFontFace`
2466  *
2467  * Returns the family, style, variant, weight and stretch of
2468  * a `PangoFontFace`. The size field of the resulting font description
2469  * will be unset.
2470  *
2471  * Return value: a newly-created `PangoFontDescription` structure
2472  *   holding the description of the face. Use [method@Pango.FontDescription.free]
2473  *   to free the result.
2474  */
2475 PangoFontDescription *
pango_font_face_describe(PangoFontFace * face)2476 pango_font_face_describe (PangoFontFace *face)
2477 {
2478   g_return_val_if_fail (PANGO_IS_FONT_FACE (face), NULL);
2479 
2480   return PANGO_FONT_FACE_GET_CLASS (face)->describe (face);
2481 }
2482 
2483 /**
2484  * pango_font_face_is_synthesized:
2485  * @face: a `PangoFontFace`
2486  *
2487  * Returns whether a `PangoFontFace` is synthesized by the underlying
2488  * font rendering engine from another face, perhaps by shearing, emboldening,
2489  * or lightening it.
2490  *
2491  * Return value: whether @face is synthesized.
2492  *
2493  * Since: 1.18
2494  */
2495 gboolean
pango_font_face_is_synthesized(PangoFontFace * face)2496 pango_font_face_is_synthesized (PangoFontFace  *face)
2497 {
2498   g_return_val_if_fail (PANGO_IS_FONT_FACE (face), FALSE);
2499 
2500   if (PANGO_FONT_FACE_GET_CLASS (face)->is_synthesized != NULL)
2501     return PANGO_FONT_FACE_GET_CLASS (face)->is_synthesized (face);
2502   else
2503     return FALSE;
2504 }
2505 
2506 /**
2507  * pango_font_face_get_face_name:
2508  * @face: a `PangoFontFace`.
2509  *
2510  * Gets a name representing the style of this face among the
2511  * different faces in the `PangoFontFamily` for the face. The
2512  * name is suitable for displaying to users.
2513  *
2514  * Return value: the face name for the face. This string is
2515  *   owned by the face object and must not be modified or freed.
2516  */
2517 const char *
pango_font_face_get_face_name(PangoFontFace * face)2518 pango_font_face_get_face_name (PangoFontFace *face)
2519 {
2520   g_return_val_if_fail (PANGO_IS_FONT_FACE (face), NULL);
2521 
2522   return PANGO_FONT_FACE_GET_CLASS (face)->get_face_name (face);
2523 }
2524 
2525 /**
2526  * pango_font_face_list_sizes:
2527  * @face: a `PangoFontFace`.
2528  * @sizes: (out) (array length=n_sizes) (nullable) (optional):
2529  *   location to store a pointer to an array of int. This array
2530  *   should be freed with g_free().
2531  * @n_sizes: location to store the number of elements in @sizes
2532  *
2533  * List the available sizes for a font.
2534  *
2535  * This is only applicable to bitmap fonts. For scalable fonts, stores
2536  * %NULL at the location pointed to by @sizes and 0 at the location pointed
2537  * to by @n_sizes. The sizes returned are in Pango units and are sorted
2538  * in ascending order.
2539  *
2540  * Since: 1.4
2541  */
2542 void
pango_font_face_list_sizes(PangoFontFace * face,int ** sizes,int * n_sizes)2543 pango_font_face_list_sizes (PangoFontFace  *face,
2544                             int           **sizes,
2545                             int            *n_sizes)
2546 {
2547   g_return_if_fail (PANGO_IS_FONT_FACE (face));
2548   g_return_if_fail (sizes == NULL || n_sizes != NULL);
2549 
2550   if (n_sizes == NULL)
2551     return;
2552 
2553   if (PANGO_FONT_FACE_GET_CLASS (face)->list_sizes != NULL)
2554     PANGO_FONT_FACE_GET_CLASS (face)->list_sizes (face, sizes, n_sizes);
2555   else
2556     {
2557       if (sizes != NULL)
2558         *sizes = NULL;
2559       *n_sizes = 0;
2560     }
2561 }
2562 
2563 /**
2564  * pango_font_face_get_family:
2565  * @face: a `PangoFontFace`
2566  *
2567  * Gets the `PangoFontFamily` that @face belongs to.
2568  *
2569  * Returns: (transfer none): the `PangoFontFamily`
2570  *
2571  * Since: 1.46
2572  */
2573 PangoFontFamily *
pango_font_face_get_family(PangoFontFace * face)2574 pango_font_face_get_family (PangoFontFace *face)
2575 {
2576   g_return_val_if_fail (PANGO_IS_FONT_FACE (face), NULL);
2577 
2578   return PANGO_FONT_FACE_GET_CLASS (face)->get_family (face);
2579 }
2580 
2581 /**
2582  * pango_font_has_char:
2583  * @font: a `PangoFont`
2584  * @wc: a Unicode character
2585  *
2586  * Returns whether the font provides a glyph for this character.
2587  *
2588  * Returns %TRUE if @font can render @wc
2589  *
2590  * Since: 1.44
2591  */
2592 gboolean
pango_font_has_char(PangoFont * font,gunichar wc)2593 pango_font_has_char (PangoFont *font,
2594                      gunichar   wc)
2595 {
2596   PangoCoverage *coverage = pango_font_get_coverage (font, pango_language_get_default ());
2597   PangoCoverageLevel result = pango_coverage_get (coverage, wc);
2598   pango_coverage_unref (coverage);
2599   return result != PANGO_COVERAGE_NONE;
2600 }
2601 
2602 /**
2603  * pango_font_get_features:
2604  * @font: a `PangoFont`
2605  * @features: (out caller-allocates) (array length=len): Array to features in
2606  * @len: the length of @features
2607  * @num_features: (inout): the number of used items in @features
2608  *
2609  * Obtain the OpenType features that are provided by the font.
2610  *
2611  * These are passed to the rendering system, together with features
2612  * that have been explicitly set via attributes.
2613  *
2614  * Note that this does not include OpenType features which the
2615  * rendering system enables by default.
2616  *
2617  * Since: 1.44
2618  */
2619 void
pango_font_get_features(PangoFont * font,hb_feature_t * features,guint len,guint * num_features)2620 pango_font_get_features (PangoFont    *font,
2621                          hb_feature_t *features,
2622                          guint         len,
2623                          guint        *num_features)
2624 {
2625   if (PANGO_FONT_GET_CLASS (font)->get_features)
2626     PANGO_FONT_GET_CLASS (font)->get_features (font, features, len, num_features);
2627 }
2628