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