1/* Pango
2 * pangofc-font.c: Shared interfaces for fontconfig-based backends
3 *
4 * Copyright (C) 2003 Red Hat Software
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22#include "config.h"
23
24#include "pango-font-private.h"
25#include "pangofc-font-private.h"
26#include "pangofc-fontmap.h"
27#include "pangofc-fontmap-private.h"
28#include "pangofc-private.h"
29#include "pango-layout.h"
30#include "pango-impl-utils.h"
31
32#include <hb-ot.h>
33
34enum {
35 PROP_0,
36 PROP_PATTERN,
37 PROP_FONTMAP
38};
39
40typedef struct _PangoFcFontPrivate PangoFcFontPrivate;
41
42struct _PangoFcFontPrivate
43{
44 PangoFcDecoder *decoder;
45 PangoFcFontKey *key;
46};
47
48static gboolean pango_fc_font_real_has_char (PangoFcFont *font,
49 gunichar wc);
50static guint pango_fc_font_real_get_glyph (PangoFcFont *font,
51 gunichar wc);
52
53static void pango_fc_font_finalize (GObject *object);
54static void pango_fc_font_set_property (GObject *object,
55 guint prop_id,
56 const GValue *value,
57 GParamSpec *pspec);
58static void pango_fc_font_get_property (GObject *object,
59 guint prop_id,
60 GValue *value,
61 GParamSpec *pspec);
62static PangoCoverage * pango_fc_font_get_coverage (PangoFont *font,
63 PangoLanguage *language);
64static PangoFontMetrics * pango_fc_font_get_metrics (PangoFont *font,
65 PangoLanguage *language);
66static PangoFontMap * pango_fc_font_get_font_map (PangoFont *font);
67static PangoFontDescription *pango_fc_font_describe (PangoFont *font);
68static PangoFontDescription *pango_fc_font_describe_absolute (PangoFont *font);
69static void pango_fc_font_get_features (PangoFont *font,
70 hb_feature_t *features,
71 guint len,
72 guint *num_features);
73static hb_font_t * pango_fc_font_create_hb_font (PangoFont *font);
74static PangoLanguage ** _pango_fc_font_get_languages (PangoFont *font);
75static gboolean _pango_fc_font_is_hinted (PangoFont *font);
76static void _pango_fc_font_get_scale_factors (PangoFont *font,
77 double *x_scale,
78 double *y_scale);
79static void pango_fc_font_get_matrix (PangoFont *font,
80 PangoMatrix *matrix);
81static int pango_fc_font_get_absolute_size (PangoFont *font);
82static PangoVariant pango_fc_font_get_variant (PangoFont *font);
83
84#define PANGO_FC_FONT_LOCK_FACE(font) (PANGO_FC_FONT_GET_CLASS (font)->lock_face (font))
85#define PANGO_FC_FONT_UNLOCK_FACE(font) (PANGO_FC_FONT_GET_CLASS (font)->unlock_face (font))
86
87G_DEFINE_ABSTRACT_TYPE_WITH_CODE (PangoFcFont, pango_fc_font, PANGO_TYPE_FONT,
88 G_ADD_PRIVATE (PangoFcFont))
89
90static void
91pango_fc_font_class_init (PangoFcFontClass *class)
92{
93 GObjectClass *object_class = G_OBJECT_CLASS (class);
94 PangoFontClass *font_class = PANGO_FONT_CLASS (class);
95 PangoFontClassPrivate *pclass;
96
97 class->has_char = pango_fc_font_real_has_char;
98 class->get_glyph = pango_fc_font_real_get_glyph;
99 class->get_unknown_glyph = NULL;
100
101 object_class->finalize = pango_fc_font_finalize;
102 object_class->set_property = pango_fc_font_set_property;
103 object_class->get_property = pango_fc_font_get_property;
104 font_class->describe = pango_fc_font_describe;
105 font_class->describe_absolute = pango_fc_font_describe_absolute;
106 font_class->get_coverage = pango_fc_font_get_coverage;
107 font_class->get_metrics = pango_fc_font_get_metrics;
108 font_class->get_font_map = pango_fc_font_get_font_map;
109 font_class->get_features = pango_fc_font_get_features;
110 font_class->create_hb_font = pango_fc_font_create_hb_font;
111
112 pclass = g_type_class_get_private (klass: (GTypeClass *) class, PANGO_TYPE_FONT);
113
114 pclass->get_languages = _pango_fc_font_get_languages;
115 pclass->is_hinted = _pango_fc_font_is_hinted;
116 pclass->get_scale_factors = _pango_fc_font_get_scale_factors;
117 pclass->get_matrix = pango_fc_font_get_matrix;
118 pclass->get_absolute_size = pango_fc_font_get_absolute_size;
119 pclass->get_variant = pango_fc_font_get_variant;
120
121 /**
122 * PangoFcFont:pattern:
123 *
124 * The fontconfig pattern for this font.
125 */
126 g_object_class_install_property (oclass: object_class, property_id: PROP_PATTERN,
127 pspec: g_param_spec_pointer (name: "pattern",
128 nick: "Pattern",
129 blurb: "The fontconfig pattern for this font",
130 flags: G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
131 G_PARAM_STATIC_STRINGS));
132
133 /**
134 * PangoFcFont:fontmap:
135 *
136 * The PangoFc font map this font is associated with.
137 */
138 g_object_class_install_property (oclass: object_class, property_id: PROP_FONTMAP,
139 pspec: g_param_spec_object (name: "fontmap",
140 nick: "Font Map",
141 blurb: "The PangoFc font map this font is associated with (Since: 1.26)",
142 PANGO_TYPE_FC_FONT_MAP,
143 flags: G_PARAM_READWRITE |
144 G_PARAM_STATIC_STRINGS));
145}
146
147static void
148pango_fc_font_init (PangoFcFont *fcfont)
149{
150 fcfont->priv = pango_fc_font_get_instance_private (self: fcfont);
151}
152
153static void
154free_metrics_info (PangoFcMetricsInfo *info)
155{
156 pango_font_metrics_unref (metrics: info->metrics);
157 g_slice_free (PangoFcMetricsInfo, info);
158}
159
160static void
161pango_fc_font_finalize (GObject *object)
162{
163 PangoFcFont *fcfont = PANGO_FC_FONT (object);
164 PangoFcFontPrivate *priv = fcfont->priv;
165 PangoFcFontMap *fontmap;
166
167 g_slist_foreach (list: fcfont->metrics_by_lang, func: (GFunc)free_metrics_info, NULL);
168 g_slist_free (list: fcfont->metrics_by_lang);
169
170 fontmap = g_weak_ref_get (weak_ref: (GWeakRef *) &fcfont->fontmap);
171 if (fontmap)
172 {
173 _pango_fc_font_map_remove (PANGO_FC_FONT_MAP (fcfont->fontmap), fcfont);
174 g_weak_ref_clear (weak_ref: (GWeakRef *) &fcfont->fontmap);
175 g_object_unref (object: fontmap);
176 }
177
178 pango_font_description_free (desc: fcfont->description);
179 FcPatternDestroy (p: fcfont->font_pattern);
180
181 if (priv->decoder)
182 _pango_fc_font_set_decoder (font: fcfont, NULL);
183
184 G_OBJECT_CLASS (pango_fc_font_parent_class)->finalize (object);
185}
186
187static gboolean
188pattern_is_hinted (FcPattern *pattern)
189{
190 FcBool hinting;
191
192 if (FcPatternGetBool (p: pattern,
193 FC_HINTING, n: 0, b: &hinting) != FcResultMatch)
194 hinting = FcTrue;
195
196 return hinting;
197}
198
199static gboolean
200pattern_is_transformed (FcPattern *pattern)
201{
202 FcMatrix *fc_matrix;
203
204 if (FcPatternGetMatrix (p: pattern, FC_MATRIX, n: 0, s: &fc_matrix) == FcResultMatch)
205 {
206 return fc_matrix->xx != 1 || fc_matrix->xy != 0 ||
207 fc_matrix->yx != 0 || fc_matrix->yy != 1;
208 }
209 else
210 return FALSE;
211}
212
213static void
214pango_fc_font_set_property (GObject *object,
215 guint prop_id,
216 const GValue *value,
217 GParamSpec *pspec)
218{
219 PangoFcFont *fcfont = PANGO_FC_FONT (object);
220
221 switch (prop_id)
222 {
223 case PROP_PATTERN:
224 {
225 FcPattern *pattern = g_value_get_pointer (value);
226
227 g_return_if_fail (pattern != NULL);
228 g_return_if_fail (fcfont->font_pattern == NULL);
229
230 FcPatternReference (p: pattern);
231 fcfont->font_pattern = pattern;
232 fcfont->description = font_description_from_pattern (pattern, TRUE, TRUE);
233 fcfont->is_hinted = pattern_is_hinted (pattern);
234 fcfont->is_transformed = pattern_is_transformed (pattern);
235 }
236 goto set_decoder;
237
238 case PROP_FONTMAP:
239 {
240 PangoFcFontMap *fcfontmap = PANGO_FC_FONT_MAP (g_value_get_object (value));
241
242 g_return_if_fail (fcfont->fontmap == NULL);
243 g_weak_ref_set (weak_ref: (GWeakRef *) &fcfont->fontmap, object: fcfontmap);
244 }
245 goto set_decoder;
246
247 default:
248 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249 return;
250 }
251
252set_decoder:
253 /* set decoder if both pattern and fontmap are set now */
254 if (fcfont->font_pattern && fcfont->fontmap)
255 _pango_fc_font_set_decoder (font: fcfont,
256 decoder: pango_fc_font_map_find_decoder (fcfontmap: (PangoFcFontMap *) fcfont->fontmap,
257 pattern: fcfont->font_pattern));
258}
259
260static void
261pango_fc_font_get_property (GObject *object,
262 guint prop_id,
263 GValue *value,
264 GParamSpec *pspec)
265{
266 switch (prop_id)
267 {
268 case PROP_PATTERN:
269 {
270 PangoFcFont *fcfont = PANGO_FC_FONT (object);
271 g_value_set_pointer (value, v_pointer: fcfont->font_pattern);
272 }
273 break;
274 case PROP_FONTMAP:
275 {
276 PangoFcFont *fcfont = PANGO_FC_FONT (object);
277 PangoFontMap *fontmap = g_weak_ref_get (weak_ref: (GWeakRef *) &fcfont->fontmap);
278 g_value_take_object (value, v_object: fontmap);
279 }
280 break;
281 default:
282 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283 break;
284 }
285}
286
287static PangoFontDescription *
288pango_fc_font_describe (PangoFont *font)
289{
290 PangoFcFont *fcfont = (PangoFcFont *)font;
291
292 return pango_font_description_copy (desc: fcfont->description);
293}
294
295static PangoFontDescription *
296pango_fc_font_describe_absolute (PangoFont *font)
297{
298 PangoFcFont *fcfont = (PangoFcFont *)font;
299 PangoFontDescription *desc = pango_font_description_copy (desc: fcfont->description);
300 double size;
301
302 if (FcPatternGetDouble (p: fcfont->font_pattern, FC_PIXEL_SIZE, n: 0, d: &size) == FcResultMatch)
303 pango_font_description_set_absolute_size (desc, size: size * PANGO_SCALE);
304
305 return desc;
306}
307
308static int
309pango_fc_font_get_absolute_size (PangoFont *font)
310{
311 PangoFcFont *fcfont = (PangoFcFont *)font;
312 double size;
313
314 if (FcPatternGetDouble (p: fcfont->font_pattern, FC_PIXEL_SIZE, n: 0, d: &size) == FcResultMatch)
315 return (int) (size * PANGO_SCALE);
316
317 return 0;
318}
319
320static PangoVariant
321pango_fc_font_get_variant (PangoFont *font)
322{
323 PangoFcFont *fcfont = (PangoFcFont *)font;
324 return pango_font_description_get_variant (desc: fcfont->description);
325}
326
327static PangoCoverage *
328pango_fc_font_get_coverage (PangoFont *font,
329 PangoLanguage *language G_GNUC_UNUSED)
330{
331 PangoFcFont *fcfont = (PangoFcFont *)font;
332 PangoFcFontPrivate *priv = fcfont->priv;
333 FcCharSet *charset;
334 PangoFcFontMap *fontmap;
335 PangoCoverage *coverage;
336
337 if (priv->decoder)
338 {
339 charset = pango_fc_decoder_get_charset (decoder: priv->decoder, fcfont);
340 return _pango_fc_font_map_fc_to_coverage (charset);
341 }
342
343 fontmap = g_weak_ref_get (weak_ref: (GWeakRef *) &fcfont->fontmap);
344 if (!fontmap)
345 return pango_coverage_new ();
346
347 coverage = _pango_fc_font_map_get_coverage (fcfontmap: fontmap, fcfont);
348 g_object_unref (object: fontmap);
349 return coverage;
350}
351
352/* For Xft, it would be slightly more efficient to simply to
353 * call Xft, and also more robust against changes in Xft.
354 * But for now, we simply use the same code for all backends.
355 *
356 * The code in this function is partly based on code from Xft,
357 * Copyright 2000 Keith Packard
358 */
359static void
360get_face_metrics (PangoFcFont *fcfont,
361 PangoFontMetrics *metrics)
362{
363 hb_font_t *hb_font = pango_font_get_hb_font (PANGO_FONT (fcfont));
364 hb_font_extents_t extents;
365 hb_position_t position;
366
367 FcMatrix *fc_matrix;
368 gboolean have_transform = FALSE;
369
370 hb_font_get_extents_for_direction (font: hb_font, direction: HB_DIRECTION_LTR, extents: &extents);
371
372 if (FcPatternGetMatrix (p: fcfont->font_pattern,
373 FC_MATRIX, n: 0, s: &fc_matrix) == FcResultMatch)
374 {
375 have_transform = (fc_matrix->xx != 1 || fc_matrix->xy != 0 ||
376 fc_matrix->yx != 0 || fc_matrix->yy != 1);
377 }
378
379 if (have_transform)
380 {
381 metrics->descent = - extents.descender * fc_matrix->yy;
382 metrics->ascent = extents.ascender * fc_matrix->yy;
383 metrics->height = (extents.ascender - extents.descender + extents.line_gap) * fc_matrix->yy;
384 }
385 else
386 {
387 metrics->descent = - extents.descender;
388 metrics->ascent = extents.ascender;
389 metrics->height = extents.ascender - extents.descender + extents.line_gap;
390 }
391
392 if (hb_ot_metrics_get_position (font: hb_font, metrics_tag: HB_OT_METRICS_TAG_UNDERLINE_SIZE, position: &position) &&
393 position != 0)
394 metrics->underline_thickness = position;
395 else
396 metrics->underline_thickness = PANGO_SCALE;
397
398 if (hb_ot_metrics_get_position (font: hb_font, metrics_tag: HB_OT_METRICS_TAG_UNDERLINE_OFFSET, position: &position) &&
399 position != 0)
400 metrics->underline_position = position;
401 else
402 metrics->underline_position = - PANGO_SCALE;
403
404 if (hb_ot_metrics_get_position (font: hb_font, metrics_tag: HB_OT_METRICS_TAG_STRIKEOUT_SIZE, position: &position) &&
405 position != 0)
406 metrics->strikethrough_thickness = position;
407 else
408 metrics->strikethrough_thickness = PANGO_SCALE;
409
410 if (hb_ot_metrics_get_position (font: hb_font, metrics_tag: HB_OT_METRICS_TAG_STRIKEOUT_OFFSET, position: &position) &&
411 position != 0)
412 metrics->strikethrough_position = position;
413 else
414 metrics->strikethrough_position = metrics->ascent / 2;
415}
416
417PangoFontMetrics *
418pango_fc_font_create_base_metrics_for_context (PangoFcFont *fcfont,
419 PangoContext *context)
420{
421 PangoFontMetrics *metrics;
422 metrics = pango_font_metrics_new ();
423
424 get_face_metrics (fcfont, metrics);
425
426 return metrics;
427}
428
429static int
430max_glyph_width (PangoLayout *layout)
431{
432 int max_width = 0;
433 GSList *l, *r;
434
435 for (l = pango_layout_get_lines_readonly (layout); l; l = l->next)
436 {
437 PangoLayoutLine *line = l->data;
438
439 for (r = line->runs; r; r = r->next)
440 {
441 PangoGlyphString *glyphs = ((PangoGlyphItem *)r->data)->glyphs;
442 int i;
443
444 for (i = 0; i < glyphs->num_glyphs; i++)
445 if (glyphs->glyphs[i].geometry.width > max_width)
446 max_width = glyphs->glyphs[i].geometry.width;
447 }
448 }
449
450 return max_width;
451}
452
453static PangoFontMetrics *
454pango_fc_font_get_metrics (PangoFont *font,
455 PangoLanguage *language)
456{
457 PangoFcFont *fcfont = PANGO_FC_FONT (font);
458 PangoFcMetricsInfo *info = NULL; /* Quiet gcc */
459 GSList *tmp_list;
460 static int in_get_metrics;
461
462 const char *sample_str = pango_language_get_sample_string (language);
463
464 tmp_list = fcfont->metrics_by_lang;
465 while (tmp_list)
466 {
467 info = tmp_list->data;
468
469 if (info->sample_str == sample_str) /* We _don't_ need strcmp */
470 break;
471
472 tmp_list = tmp_list->next;
473 }
474
475 if (!tmp_list)
476 {
477 PangoFontMap *fontmap;
478 PangoContext *context;
479
480 fontmap = g_weak_ref_get (weak_ref: (GWeakRef *) &fcfont->fontmap);
481 if (!fontmap)
482 return pango_font_metrics_new ();
483
484 info = g_slice_new0 (PangoFcMetricsInfo);
485
486 /* Note: we need to add info to the list before calling
487 * into PangoLayout below, to prevent recursion
488 */
489 fcfont->metrics_by_lang = g_slist_prepend (list: fcfont->metrics_by_lang,
490 data: info);
491
492 info->sample_str = sample_str;
493
494 context = pango_font_map_create_context (fontmap);
495 pango_context_set_language (context, language);
496
497 info->metrics = pango_fc_font_create_base_metrics_for_context (fcfont, context);
498
499 if (!in_get_metrics)
500 {
501 /* Compute derived metrics */
502 PangoLayout *layout;
503 PangoRectangle extents;
504 PangoFontDescription *desc = pango_font_describe_with_absolute_size (font);
505 gulong sample_str_width;
506
507 in_get_metrics = 1;
508
509 layout = pango_layout_new (context);
510 pango_layout_set_font_description (layout, desc);
511 pango_font_description_free (desc);
512
513 pango_layout_set_text (layout, text: sample_str, length: -1);
514 pango_layout_get_extents (layout, NULL, logical_rect: &extents);
515
516 sample_str_width = pango_utf8_strwidth (p: sample_str);
517 g_assert (sample_str_width > 0);
518 info->metrics->approximate_char_width = extents.width / sample_str_width;
519
520 pango_layout_set_text (layout, text: "0123456789", length: -1);
521 info->metrics->approximate_digit_width = max_glyph_width (layout);
522
523 g_object_unref (object: layout);
524
525 in_get_metrics = 0;
526 }
527
528 g_object_unref (object: context);
529 g_object_unref (object: fontmap);
530 }
531
532 return pango_font_metrics_ref (metrics: info->metrics);
533}
534
535static PangoFontMap *
536pango_fc_font_get_font_map (PangoFont *font)
537{
538 PangoFcFont *fcfont = PANGO_FC_FONT (font);
539
540 /* MT-unsafe. Oh well... The API is unsafe. */
541 return fcfont->fontmap;
542}
543
544static gboolean
545pango_fc_font_real_has_char (PangoFcFont *font,
546 gunichar wc)
547{
548 FcCharSet *charset;
549
550 if (FcPatternGetCharSet (p: font->font_pattern,
551 FC_CHARSET, n: 0, c: &charset) != FcResultMatch)
552 return FALSE;
553
554 return FcCharSetHasChar (fcs: charset, ucs4: wc);
555}
556
557static guint
558pango_fc_font_real_get_glyph (PangoFcFont *font,
559 gunichar wc)
560{
561 hb_font_t *hb_font = pango_font_get_hb_font (PANGO_FONT (font));
562 hb_codepoint_t glyph = PANGO_GET_UNKNOWN_GLYPH (wc);
563
564 hb_font_get_nominal_glyph (font: hb_font, unicode: wc, glyph: &glyph);
565
566 return glyph;
567}
568
569/**
570 * pango_fc_font_lock_face: (skip)
571 * @font: a `PangoFcFont`.
572 *
573 * Gets the FreeType `FT_Face` associated with a font.
574 *
575 * This face will be kept around until you call
576 * [method@PangoFc.Font.unlock_face].
577 *
578 * Return value: the FreeType `FT_Face` associated with @font.
579 *
580 * Since: 1.4
581 * Deprecated: 1.44: Use pango_font_get_hb_font() instead
582 */
583FT_Face
584pango_fc_font_lock_face (PangoFcFont *font)
585{
586 g_return_val_if_fail (PANGO_IS_FC_FONT (font), NULL);
587
588 return PANGO_FC_FONT_LOCK_FACE (font);
589}
590
591/**
592 * pango_fc_font_unlock_face:
593 * @font: a `PangoFcFont`.
594 *
595 * Releases a font previously obtained with
596 * [method@PangoFc.Font.lock_face].
597 *
598 * Since: 1.4
599 * Deprecated: 1.44: Use pango_font_get_hb_font() instead
600 */
601void
602pango_fc_font_unlock_face (PangoFcFont *font)
603{
604 g_return_if_fail (PANGO_IS_FC_FONT (font));
605
606 PANGO_FC_FONT_UNLOCK_FACE (font);
607}
608
609/**
610 * pango_fc_font_has_char:
611 * @font: a `PangoFcFont`
612 * @wc: Unicode codepoint to look up
613 *
614 * Determines whether @font has a glyph for the codepoint @wc.
615 *
616 * Return value: %TRUE if @font has the requested codepoint.
617 *
618 * Since: 1.4
619 * Deprecated: 1.44: Use [method@Pango.Font.has_char]
620 */
621gboolean
622pango_fc_font_has_char (PangoFcFont *font,
623 gunichar wc)
624{
625 PangoFcFontPrivate *priv = font->priv;
626 FcCharSet *charset;
627
628 g_return_val_if_fail (PANGO_IS_FC_FONT (font), FALSE);
629
630 if (priv->decoder)
631 {
632 charset = pango_fc_decoder_get_charset (decoder: priv->decoder, fcfont: font);
633 return FcCharSetHasChar (fcs: charset, ucs4: wc);
634 }
635
636 return PANGO_FC_FONT_GET_CLASS (font)->has_char (font, wc);
637}
638
639/**
640 * pango_fc_font_get_glyph:
641 * @font: a `PangoFcFont`
642 * @wc: Unicode character to look up
643 *
644 * Gets the glyph index for a given Unicode character
645 * for @font.
646 *
647 * If you only want to determine whether the font has
648 * the glyph, use [method@PangoFc.Font.has_char].
649 *
650 * Return value: the glyph index, or 0, if the Unicode
651 * character doesn't exist in the font.
652 *
653 * Since: 1.4
654 */
655PangoGlyph
656pango_fc_font_get_glyph (PangoFcFont *font,
657 gunichar wc)
658{
659 PangoFcFontPrivate *priv = font->priv;
660
661 /* Replace NBSP with a normal space; it should be invariant that
662 * they shape the same other than breaking properties.
663 */
664 if (wc == 0xA0)
665 wc = 0x20;
666
667 if (priv->decoder)
668 return pango_fc_decoder_get_glyph (decoder: priv->decoder, fcfont: font, wc);
669
670 return PANGO_FC_FONT_GET_CLASS (font)->get_glyph (font, wc);
671}
672
673
674/**
675 * pango_fc_font_get_unknown_glyph:
676 * @font: a `PangoFcFont`
677 * @wc: the Unicode character for which a glyph is needed.
678 *
679 * Returns the index of a glyph suitable for drawing @wc
680 * as an unknown character.
681 *
682 * Use PANGO_GET_UNKNOWN_GLYPH() instead.
683 *
684 * Return value: a glyph index into @font.
685 *
686 * Since: 1.4
687 */
688PangoGlyph
689pango_fc_font_get_unknown_glyph (PangoFcFont *font,
690 gunichar wc)
691{
692 if (font && PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph)
693 return PANGO_FC_FONT_GET_CLASS (font)->get_unknown_glyph (font, wc);
694
695 return PANGO_GET_UNKNOWN_GLYPH (wc);
696}
697
698void
699_pango_fc_font_shutdown (PangoFcFont *font)
700{
701 g_return_if_fail (PANGO_IS_FC_FONT (font));
702
703 if (PANGO_FC_FONT_GET_CLASS (font)->shutdown)
704 PANGO_FC_FONT_GET_CLASS (font)->shutdown (font);
705}
706
707/**
708 * pango_fc_font_kern_glyphs:
709 * @font: a `PangoFcFont`
710 * @glyphs: a `PangoGlyphString`
711 *
712 * This function used to adjust each adjacent pair of glyphs
713 * in @glyphs according to kerning information in @font.
714 *
715 * Since 1.44, it does nothing.
716 *
717 * Since: 1.4
718 * Deprecated: 1.32
719 */
720void
721pango_fc_font_kern_glyphs (PangoFcFont *font,
722 PangoGlyphString *glyphs)
723{
724}
725
726/**
727 * _pango_fc_font_get_decoder:
728 * @font: a `PangoFcFont`
729 *
730 * This will return any custom decoder set on this font.
731 *
732 * Return value: The custom decoder
733 *
734 * Since: 1.6
735 */
736PangoFcDecoder *
737_pango_fc_font_get_decoder (PangoFcFont *font)
738{
739 PangoFcFontPrivate *priv = font->priv;
740
741 return priv->decoder;
742}
743
744/**
745 * _pango_fc_font_set_decoder:
746 * @font: a `PangoFcFont`
747 * @decoder: a `PangoFcDecoder` to set for this font
748 *
749 * This sets a custom decoder for this font.
750 *
751 * Any previous decoder will be released before this one is set.
752 *
753 * Since: 1.6
754 */
755void
756_pango_fc_font_set_decoder (PangoFcFont *font,
757 PangoFcDecoder *decoder)
758{
759 PangoFcFontPrivate *priv = font->priv;
760
761 if (priv->decoder)
762 g_object_unref (object: priv->decoder);
763
764 priv->decoder = decoder;
765
766 if (priv->decoder)
767 g_object_ref (priv->decoder);
768}
769
770PangoFcFontKey *
771_pango_fc_font_get_font_key (PangoFcFont *fcfont)
772{
773 PangoFcFontPrivate *priv = fcfont->priv;
774
775 return priv->key;
776}
777
778void
779_pango_fc_font_set_font_key (PangoFcFont *fcfont,
780 PangoFcFontKey *key)
781{
782 PangoFcFontPrivate *priv = fcfont->priv;
783
784 priv->key = key;
785}
786
787/**
788 * pango_fc_font_get_raw_extents:
789 * @fcfont: a `PangoFcFont`
790 * @glyph: the glyph index to load
791 * @ink_rect: (out) (optional): location to store ink extents of the
792 * glyph
793 * @logical_rect: (out) (optional): location to store logical extents
794 * of the glyph
795 *
796 * Gets the extents of a single glyph from a font.
797 *
798 * The extents are in user space; that is, they are not transformed
799 * by any matrix in effect for the font.
800 *
801 * Long term, this functionality probably belongs in the default
802 * implementation of the get_glyph_extents() virtual function.
803 * The other possibility would be to to make it public in something
804 * like it's current form, and also expose glyph information
805 * caching functionality similar to pango_ft2_font_set_glyph_info().
806 *
807 * Since: 1.6
808 */
809void
810pango_fc_font_get_raw_extents (PangoFcFont *fcfont,
811 PangoGlyph glyph,
812 PangoRectangle *ink_rect,
813 PangoRectangle *logical_rect)
814{
815 g_return_if_fail (PANGO_IS_FC_FONT (fcfont));
816
817 if (glyph == PANGO_GLYPH_EMPTY)
818 {
819 if (ink_rect)
820 {
821 ink_rect->x = 0;
822 ink_rect->width = 0;
823 ink_rect->y = 0;
824 ink_rect->height = 0;
825 }
826
827 if (logical_rect)
828 {
829 logical_rect->x = 0;
830 logical_rect->width = 0;
831 logical_rect->y = 0;
832 logical_rect->height = 0;
833 }
834 }
835 else
836 {
837 hb_font_t *hb_font = pango_font_get_hb_font (PANGO_FONT (fcfont));
838 hb_glyph_extents_t extents;
839 hb_font_extents_t font_extents;
840
841 hb_font_get_glyph_extents (font: hb_font, glyph, extents: &extents);
842 hb_font_get_extents_for_direction (font: hb_font, direction: HB_DIRECTION_LTR, extents: &font_extents);
843
844 if (ink_rect)
845 {
846 ink_rect->x = extents.x_bearing;
847 ink_rect->width = extents.width;
848 ink_rect->y = -extents.y_bearing;
849 ink_rect->height = -extents.height;
850 }
851
852 if (logical_rect)
853 {
854 hb_position_t x, y;
855
856 hb_font_get_glyph_advance_for_direction (font: hb_font,
857 glyph,
858 direction: HB_DIRECTION_LTR,
859 x: &x, y: &y);
860
861 logical_rect->x = 0;
862 logical_rect->width = x;
863 logical_rect->y = - font_extents.ascender;
864 logical_rect->height = font_extents.ascender - font_extents.descender;
865 }
866 }
867}
868
869static void
870pango_fc_font_get_features (PangoFont *font,
871 hb_feature_t *features,
872 guint len,
873 guint *num_features)
874{
875 /* Setup features from fontconfig pattern. */
876 PangoFcFont *fc_font = PANGO_FC_FONT (font);
877 if (fc_font->font_pattern)
878 {
879 char *s;
880 while (*num_features < len &&
881 FcResultMatch == FcPatternGetString (p: fc_font->font_pattern,
882 FC_FONT_FEATURES,
883 n: *num_features,
884 s: (FcChar8 **) &s))
885 {
886 gboolean ret = hb_feature_from_string (str: s, len: -1, feature: &features[*num_features]);
887 features[*num_features].start = 0;
888 features[*num_features].end = (unsigned int) -1;
889 if (ret)
890 (*num_features)++;
891 }
892 }
893}
894
895extern gpointer get_gravity_class (void);
896
897static PangoGravity
898pango_fc_font_key_get_gravity (PangoFcFontKey *key)
899{
900 const FcPattern *pattern;
901 PangoGravity gravity = PANGO_GRAVITY_SOUTH;
902 FcChar8 *s;
903
904 pattern = pango_fc_font_key_get_pattern (key);
905 if (FcPatternGetString (p: pattern, PANGO_FC_GRAVITY, n: 0, s: (FcChar8 **)&s) == FcResultMatch)
906 {
907 GEnumValue *value = g_enum_get_value_by_nick (enum_class: get_gravity_class (), nick: (char *)s);
908 gravity = value->value;
909 }
910
911 return gravity;
912}
913
914static void
915get_font_size (PangoFcFontKey *key,
916 double *pixel_size,
917 double *point_size)
918{
919 const FcPattern *pattern;
920 double dpi;
921
922 pattern = pango_fc_font_key_get_pattern (key);
923 if (FcPatternGetDouble (p: pattern, FC_SIZE, n: 0, d: point_size) != FcResultMatch)
924 *point_size = 13.;
925
926 if (FcPatternGetDouble (p: pattern, FC_PIXEL_SIZE, n: 0, d: pixel_size) != FcResultMatch)
927 {
928 if (FcPatternGetDouble (p: pattern, FC_DPI, n: 0, d: &dpi) != FcResultMatch)
929 dpi = 72.;
930
931 *pixel_size = *point_size * dpi / 72.;
932 }
933}
934
935static void
936parse_variations (const char *variations,
937 hb_ot_var_axis_info_t *axes,
938 int n_axes,
939 float *coords)
940{
941 const char *p;
942 const char *end;
943 hb_variation_t var;
944 int i;
945
946 p = variations;
947 while (p && *p)
948 {
949 end = strchr (s: p, c: ',');
950 if (hb_variation_from_string (str: p, len: end ? end - p: -1, variation: &var))
951 {
952 for (i = 0; i < n_axes; i++)
953 {
954 if (axes[i].tag == var.tag)
955 {
956 coords[axes[i].axis_index] = var.value;
957 break;
958 }
959 }
960 }
961
962 p = end ? end + 1 : NULL;
963 }
964}
965
966static hb_font_t *
967pango_fc_font_create_hb_font (PangoFont *font)
968{
969 PangoFcFont *fc_font = PANGO_FC_FONT (font);
970 PangoFcFontKey *key;
971 hb_face_t *hb_face;
972 hb_font_t *hb_font;
973 double x_scale_inv, y_scale_inv;
974 double x_scale, y_scale;
975 double pixel_size;
976 double point_size;
977 double slant G_GNUC_UNUSED;
978
979 x_scale_inv = y_scale_inv = 1.0;
980 pixel_size = 1.0;
981 point_size = 1.0;
982 slant = 0.0;
983
984 key = _pango_fc_font_get_font_key (fcfont: fc_font);
985 if (key)
986 {
987 const FcPattern *pattern = pango_fc_font_key_get_pattern (key);
988 const PangoMatrix *ctm;
989 PangoMatrix font_matrix;
990 PangoGravity gravity;
991 FcMatrix fc_matrix, *fc_matrix_val;
992 double x, y;
993 int i;
994
995 ctm = pango_fc_font_key_get_matrix (key);
996 pango_matrix_get_font_scale_factors (matrix: ctm, xscale: &x_scale_inv, yscale: &y_scale_inv);
997
998 FcMatrixInit (&fc_matrix);
999 for (i = 0; FcPatternGetMatrix (p: pattern, FC_MATRIX, n: i, s: &fc_matrix_val) == FcResultMatch; i++)
1000 FcMatrixMultiply (result: &fc_matrix, a: &fc_matrix, b: fc_matrix_val);
1001
1002 font_matrix.xx = fc_matrix.xx;
1003 font_matrix.yx = - fc_matrix.yx;
1004 font_matrix.xy = fc_matrix.xy;
1005 font_matrix.yy = - fc_matrix.yy;
1006
1007 pango_matrix_get_font_scale_factors (matrix: &font_matrix, xscale: &x, yscale: &y);
1008 slant = pango_matrix_get_slant_ratio (matrix: &font_matrix);
1009
1010 x_scale_inv /= x;
1011 y_scale_inv /= y;
1012
1013 gravity = pango_fc_font_key_get_gravity (key);
1014 if (PANGO_GRAVITY_IS_IMPROPER (gravity))
1015 {
1016 x_scale_inv = -x_scale_inv;
1017 y_scale_inv = -y_scale_inv;
1018 }
1019
1020 get_font_size (key, pixel_size: &pixel_size, point_size: &point_size);
1021 }
1022
1023 x_scale = 1. / x_scale_inv;
1024 y_scale = 1. / y_scale_inv;
1025
1026 hb_face = pango_fc_font_map_get_hb_face (PANGO_FC_FONT_MAP (fc_font->fontmap), fcfont: fc_font);
1027
1028 hb_font = hb_font_create (face: hb_face);
1029 hb_font_set_scale (font: hb_font,
1030 x_scale: pixel_size * PANGO_SCALE * x_scale,
1031 y_scale: pixel_size * PANGO_SCALE * y_scale);
1032 hb_font_set_ptem (font: hb_font, ptem: point_size);
1033
1034#if HB_VERSION_ATLEAST (3, 3, 0)
1035 hb_font_set_synthetic_slant (hb_font, slant);
1036#endif
1037
1038 if (key)
1039 {
1040 const FcPattern *pattern = pango_fc_font_key_get_pattern (key);
1041 const char *variations;
1042 int index;
1043 unsigned int n_axes;
1044 hb_ot_var_axis_info_t *axes;
1045 float *coords;
1046 int i;
1047
1048 n_axes = hb_ot_var_get_axis_infos (face: hb_face, start_offset: 0, NULL, NULL);
1049 if (n_axes == 0)
1050 goto done;
1051
1052 axes = g_new0 (hb_ot_var_axis_info_t, n_axes);
1053 coords = g_new (float, n_axes);
1054
1055 hb_ot_var_get_axis_infos (face: hb_face, start_offset: 0, axes_count: &n_axes, axes_array: axes);
1056 for (i = 0; i < n_axes; i++)
1057 coords[axes[i].axis_index] = axes[i].default_value;
1058
1059 if (FcPatternGetInteger (p: pattern, FC_INDEX, n: 0, i: &index) == FcResultMatch &&
1060 index != 0)
1061 {
1062 unsigned int instance = (index >> 16) - 1;
1063 hb_ot_var_named_instance_get_design_coords (face: hb_face, instance_index: instance, coords_length: &n_axes, coords);
1064 }
1065
1066 if (FcPatternGetString (p: pattern, FC_FONT_VARIATIONS, n: 0, s: (FcChar8 **)&variations) == FcResultMatch)
1067 parse_variations (variations, axes, n_axes, coords);
1068
1069 variations = pango_fc_font_key_get_variations (key);
1070 if (variations)
1071 parse_variations (variations, axes, n_axes, coords);
1072
1073 hb_font_set_var_coords_design (font: hb_font, coords, coords_length: n_axes);
1074
1075 g_free (mem: coords);
1076 g_free (mem: axes);
1077 }
1078
1079done:
1080 return hb_font;
1081}
1082
1083/**
1084 * pango_fc_font_get_languages:
1085 * @font: a `PangoFcFont`
1086 *
1087 * Returns the languages that are supported by @font.
1088 *
1089 * This corresponds to the FC_LANG member of the FcPattern.
1090 *
1091 * The returned array is only valid as long as the font
1092 * and its fontmap are valid.
1093 *
1094 * Returns: (transfer none) (nullable): a %NULL-terminated
1095 * array of `PangoLanguage`*
1096 *
1097 * Since: 1.48
1098 * Deprecated: 1.50: Use pango_font_get_language()
1099 */
1100PangoLanguage **
1101pango_fc_font_get_languages (PangoFcFont *font)
1102{
1103 return pango_font_get_languages (PANGO_FONT (font));
1104}
1105
1106static PangoLanguage **
1107_pango_fc_font_get_languages (PangoFont *font)
1108{
1109 PangoFcFont * fcfont = PANGO_FC_FONT (font);
1110 PangoFcFontMap *fontmap;
1111 PangoLanguage **languages;
1112
1113 fontmap = g_weak_ref_get (weak_ref: (GWeakRef *) &fcfont->fontmap);
1114 if (!fontmap)
1115 return NULL;
1116
1117 languages = _pango_fc_font_map_get_languages (fcfontmap: fontmap, fcfont);
1118 g_object_unref (object: fontmap);
1119
1120 return languages;
1121}
1122
1123/**
1124 * pango_fc_font_get_pattern: (skip)
1125 * @font: a `PangoFcFont`
1126 *
1127 * Returns the FcPattern that @font is based on.
1128 *
1129 * Returns: the fontconfig pattern for this font
1130 *
1131 * Since: 1.48
1132 */
1133FcPattern *
1134pango_fc_font_get_pattern (PangoFcFont *font)
1135{
1136 return font->font_pattern;
1137}
1138
1139gboolean
1140_pango_fc_font_is_hinted (PangoFont *font)
1141{
1142 PangoFcFont *fcfont = PANGO_FC_FONT (font);
1143
1144 return fcfont->is_hinted;
1145}
1146
1147void
1148_pango_fc_font_get_scale_factors (PangoFont *font,
1149 double *x_scale,
1150 double *y_scale)
1151{
1152 PangoFcFont *fcfont = PANGO_FC_FONT (font);
1153 PangoFcFontPrivate *priv = fcfont->priv;
1154
1155 pango_matrix_get_font_scale_factors (matrix: pango_fc_font_key_get_matrix (key: priv->key), xscale: x_scale, yscale: y_scale);
1156}
1157
1158static void
1159pango_fc_font_get_matrix (PangoFont *font,
1160 PangoMatrix *matrix)
1161{
1162 PangoFcFont *fcfont = PANGO_FC_FONT (font);
1163 FcMatrix fc_matrix, *fc_matrix_val;
1164
1165 FcMatrixInit (&fc_matrix);
1166 for (int i = 0; FcPatternGetMatrix (p: fcfont->font_pattern, FC_MATRIX, n: i, s: &fc_matrix_val) == FcResultMatch; i++)
1167 FcMatrixMultiply (result: &fc_matrix, a: &fc_matrix, b: fc_matrix_val);
1168
1169 matrix->xx = fc_matrix.xx;
1170 matrix->xy = - fc_matrix.xy;
1171 matrix->yx = - fc_matrix.yx;
1172 matrix->yy = fc_matrix.yy;
1173 matrix->x0 = 0.;
1174 matrix->y0 = 0.;
1175}
1176

source code of gtk/subprojects/pango/pango/pangofc-font.c