diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-01-27 00:46:15 -0500 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-01-28 18:43:39 -0500 |
commit | 73effe2d038f05fb9b107eb9189068acb3e68415 (patch) | |
tree | a9b76ca845ace8ea25442496f7352e0ca61c3950 | |
parent | 71a597754cd977186a6c9541366a3c893c6ddfc2 (diff) | |
download | pango-73effe2d038f05fb9b107eb9189068acb3e68415.tar.gz |
Introduce user fonts
Add a way to create callback-based faces
and fonts. The cairo implementation of this
uses cairos user fonts.
New APIs: PangoUserFace and PangoUserFont
-rw-r--r-- | meson.build | 4 | ||||
-rw-r--r-- | pango/meson.build | 4 | ||||
-rw-r--r-- | pango/pango-generic-family-private.h | 3 | ||||
-rw-r--r-- | pango/pango-generic-family.c | 4 | ||||
-rw-r--r-- | pango/pango-hbface-private.h | 24 | ||||
-rw-r--r-- | pango/pango-hbface.c | 3 | ||||
-rw-r--r-- | pango/pango-hbface.h | 2 | ||||
-rw-r--r-- | pango/pango-hbfamily-private.h | 7 | ||||
-rw-r--r-- | pango/pango-hbfamily.c | 100 | ||||
-rw-r--r-- | pango/pango-hbfont-private.h | 23 | ||||
-rw-r--r-- | pango/pango-hbfont.c | 40 | ||||
-rw-r--r-- | pango/pango-hbfont.h | 3 | ||||
-rw-r--r-- | pango/pango-hbfontmap.c | 111 | ||||
-rw-r--r-- | pango/pango-hbfontmap.h | 4 | ||||
-rw-r--r-- | pango/pango-userface-private.h | 54 | ||||
-rw-r--r-- | pango/pango-userface.c | 484 | ||||
-rw-r--r-- | pango/pango-userface.h | 82 | ||||
-rw-r--r-- | pango/pango-userfont-private.h | 39 | ||||
-rw-r--r-- | pango/pango-userfont.c | 483 | ||||
-rw-r--r-- | pango/pango-userfont.h | 47 | ||||
-rw-r--r-- | pango/pango.h | 2 | ||||
-rw-r--r-- | pango/pangocairo-font.c | 115 | ||||
-rw-r--r-- | pango/pangofc-hbfontmap.c | 2 | ||||
-rw-r--r-- | pango/shape.c | 85 |
24 files changed, 1583 insertions, 142 deletions
diff --git a/meson.build b/meson.build index 0be2c83b..df98d6a9 100644 --- a/meson.build +++ b/meson.build @@ -450,6 +450,10 @@ if not cairo_dep.found() cairo_found_type = cairo_dep.type_name() endif +if cc.has_function('cairo_user_font_face_set_render_color_glyph_func', args: '-lcairo', dependencies: cairo_dep) + pango_conf.set('HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC', 1) +endif + pango_font_backends = [] pango_cairo_backends = [] diff --git a/pango/meson.build b/pango/meson.build index 3be27319..5cf392ac 100644 --- a/pango/meson.build +++ b/pango/meson.build @@ -39,6 +39,8 @@ pango_sources = [ 'pango-generic-family.c', 'pango-hbfont.c', 'pango-hbfontmap.c', + 'pango-userface.c', + 'pango-userfont.c', ] pango_headers = [ @@ -73,6 +75,8 @@ pango_headers = [ 'pango-hbface.h', 'pango-hbfont.h', 'pango-hbfontmap.h', + 'pango-userface.h', + 'pango-userfont.h', ] pango_installed_headers = pango_headers + [ 'pango-version-macros.h' ] diff --git a/pango/pango-generic-family-private.h b/pango/pango-generic-family-private.h index 4ba8c865..78e17610 100644 --- a/pango/pango-generic-family-private.h +++ b/pango/pango-generic-family-private.h @@ -21,7 +21,6 @@ #pragma once #include "pango-font.h" -#include "pango-hbface.h" #include "pango-generic-family.h" #include "pango-hbfamily-private.h" @@ -39,7 +38,7 @@ struct _PangoGenericFamily void pango_generic_family_set_font_map (PangoGenericFamily *self, PangoFontMap *map); -PangoHbFace * pango_generic_family_find_face (PangoGenericFamily *self, +PangoFontFace * pango_generic_family_find_face (PangoGenericFamily *self, PangoFontDescription *description, PangoLanguage *language, gunichar wc); diff --git a/pango/pango-generic-family.c b/pango/pango-generic-family.c index ceca7399..fd555eab 100644 --- a/pango/pango-generic-family.c +++ b/pango/pango-generic-family.c @@ -133,13 +133,13 @@ pango_generic_family_set_font_map (PangoGenericFamily *self, * * Returns: (transfer none) (nullable): the face */ -PangoHbFace * +PangoFontFace * pango_generic_family_find_face (PangoGenericFamily *self, PangoFontDescription *description, PangoLanguage *language, gunichar wc) { - PangoHbFace *face = NULL; + PangoFontFace *face = NULL; for (int i = 0; i < self->families->len; i++) { diff --git a/pango/pango-hbface-private.h b/pango/pango-hbface-private.h index 045a13ef..b1118006 100644 --- a/pango/pango-hbface-private.h +++ b/pango/pango-hbface-private.h @@ -25,21 +25,35 @@ #include "pango-language-set-private.h" #include <hb.h> +typedef struct _CommonFace CommonFace; +struct _CommonFace { + PangoFontFace parent_instance; + + PangoFontDescription *description; + char *name; + PangoFontFamily *family; + char *psname; + char *faceid; +}; + struct _PangoHbFace { PangoFontFace parent_instance; + PangoFontDescription *description; + char *name; + PangoFontFamily *family; + char *psname; + char *faceid; + + /* up to here shared with PangoUserFace */ + unsigned int index; int instance_id; char *file; hb_face_t *face; - char *psname; - char *faceid; hb_variation_t *variations; unsigned int n_variations; - char *name; - PangoFontFamily *family; - PangoFontDescription *description; PangoMatrix *matrix; double x_scale, y_scale; PangoLanguageSet *languages; diff --git a/pango/pango-hbface.c b/pango/pango-hbface.c index 7c93f9aa..5adc1061 100644 --- a/pango/pango-hbface.c +++ b/pango/pango-hbface.c @@ -283,7 +283,8 @@ pango_hb_face_finalize (GObject *object) { PangoHbFace *self = PANGO_HB_FACE (object); - hb_face_destroy (self->face); + if (self->face) + hb_face_destroy (self->face); pango_font_description_free (self->description); g_free (self->name); g_free (self->file); diff --git a/pango/pango-hbface.h b/pango/pango-hbface.h index 80f77509..04cac041 100644 --- a/pango/pango-hbface.h +++ b/pango/pango-hbface.h @@ -25,6 +25,8 @@ G_BEGIN_DECLS +typedef struct _PangoHbFont PangoHbFont; + #define PANGO_TYPE_HB_FACE (pango_hb_face_get_type ()) PANGO_AVAILABLE_IN_1_52 diff --git a/pango/pango-hbfamily-private.h b/pango/pango-hbfamily-private.h index 7b1dfa9a..40f9232a 100644 --- a/pango/pango-hbfamily-private.h +++ b/pango/pango-hbfamily-private.h @@ -21,7 +21,6 @@ #pragma once #include "pango-font.h" -#include "pango-hbface.h" #define PANGO_TYPE_HB_FAMILY (pango_hb_family_get_type ()) @@ -44,12 +43,12 @@ void pango_hb_family_set_font_map (PangoHbFamily PangoFontMap *map); void pango_hb_family_add_face (PangoHbFamily *self, - PangoHbFace *face); + PangoFontFace *face); void pango_hb_family_remove_face (PangoHbFamily *self, - PangoHbFace *face); + PangoFontFace *face); -PangoHbFace * pango_hb_family_find_face (PangoHbFamily *self, +PangoFontFace * pango_hb_family_find_face (PangoHbFamily *self, PangoFontDescription *description, PangoLanguage *language, gunichar wc); diff --git a/pango/pango-hbfamily.c b/pango/pango-hbfamily.c index 814ec5f8..ebed6200 100644 --- a/pango/pango-hbfamily.c +++ b/pango/pango-hbfamily.c @@ -25,6 +25,7 @@ #include "pango-hbfamily-private.h" #include "pango-impl-utils.h" #include "pango-hbface-private.h" +#include "pango-userface-private.h" #include "pango-font-private.h" /* {{{ GListModel implementation */ @@ -45,7 +46,7 @@ pango_hb_family_get_n_items (GListModel *list) static gpointer pango_hb_family_get_item (GListModel *list, - guint position) + guint position) { PangoHbFamily *self = PANGO_HB_FAMILY (list); @@ -66,28 +67,59 @@ pango_hb_family_list_model_init (GListModelInterface *iface) /* }}} */ /* {{{ Utilities */ +static void +face_set_family (PangoFontFace *face, + PangoFontFamily *family) +{ + if (PANGO_IS_HB_FACE (face)) + pango_hb_face_set_family (PANGO_HB_FACE (face), family); + else + pango_user_face_set_family (PANGO_USER_FACE (face), family); +} + +static const char * +face_get_faceid (PangoFontFace *face) +{ + if (PANGO_IS_HB_FACE (face)) + return pango_hb_face_get_faceid (PANGO_HB_FACE (face)); + else + return pango_user_face_get_faceid (PANGO_USER_FACE (face)); +} + +static gboolean +face_has_char (PangoFontFace *face, + gunichar wc) +{ + if (PANGO_IS_HB_FACE (face)) + return pango_hb_face_has_char (PANGO_HB_FACE (face), wc); + else + return pango_user_face_has_char (PANGO_USER_FACE (face), wc); +} + static int -sort_face_func (PangoHbFace *face1, - PangoHbFace *face2) +sort_face_func (PangoFontFace *face1, + PangoFontFace *face2) { + CommonFace *cf1 = (CommonFace *)face1; + CommonFace *cf2 = (CommonFace *)face2; int a, b; - a = pango_font_description_get_style (face1->description); - b = pango_font_description_get_style (face2->description); + a = pango_font_description_get_style (cf1->description); + b = pango_font_description_get_style (cf2->description); if (a != b) return a - b; - a = pango_font_description_get_weight (face1->description); - b = pango_font_description_get_weight (face2->description); + a = pango_font_description_get_weight (cf1->description); + b = pango_font_description_get_weight (cf2->description); if (a != b) return a - b; - a = pango_font_description_get_stretch (face1->description); - b = pango_font_description_get_stretch (face2->description); + a = pango_font_description_get_stretch (cf1->description); + b = pango_font_description_get_stretch (cf2->description); if (a != b) return a - b; - return strcmp (face1->name, face2->name); + return strcmp (cf1->name, cf2->name); } /* return 2 if face is a named instance, @@ -95,11 +127,11 @@ sort_face_func (PangoHbFace *face1, * 0 otherwise */ static int -hb_face_get_variableness (PangoHbFace *face) +face_get_variableness (PangoFontFace *face) { if (pango_font_face_is_variable (PANGO_FONT_FACE (face))) { - if (face->instance_id != -1) + if (PANGO_HB_FACE (face)->instance_id != -1) return 2; else return 1; @@ -250,7 +282,7 @@ pango_hb_family_new (const char *name) * @map: (nullable): a `PangoFontMap` * * Sets the map of @self. - */ + G*/ void pango_hb_family_set_font_map (PangoHbFamily *self, PangoFontMap *map) @@ -278,21 +310,24 @@ pango_hb_family_set_font_map (PangoHbFamily *self, */ void pango_hb_family_add_face (PangoHbFamily *self, - PangoHbFace *face) + PangoFontFace *face) { int position; + g_return_if_fail (PANGO_IS_HB_FACE (face) || PANGO_IS_USER_FACE (face)); + position = 0; while (position < self->faces->len) { - PangoHbFace *f = g_ptr_array_index (self->faces, position); + PangoFontFace *f = g_ptr_array_index (self->faces, position); if (sort_face_func (face, f) < 0) break; position++; } g_ptr_array_insert (self->faces, position, face); - pango_hb_face_set_family (face, PANGO_FONT_FAMILY (self)); + + face_set_family (face, PANGO_FONT_FAMILY (self)); g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1); } @@ -300,20 +335,23 @@ pango_hb_family_add_face (PangoHbFamily *self, /*< private > * pango_hb_family_remove_face: * @self: a `PangoHbFamily` - * @face: a `PangoHbFace` + * @face: a `PangoFontFace` * * Remove a `PangoFontFace` from a `PangoHbFamily`. */ void pango_hb_family_remove_face (PangoHbFamily *self, - PangoHbFace *face) + PangoFontFace *face) { unsigned int position; + g_return_if_fail (PANGO_IS_HB_FACE (face) || PANGO_IS_USER_FACE (face)); + if (!g_ptr_array_find (self->faces, face, &position)) return; - pango_hb_face_set_family (face, NULL); + face_set_family (face, NULL); + g_ptr_array_remove_index (self->faces, position); g_list_model_items_changed (G_LIST_MODEL (self), position, 1, 0); @@ -335,47 +373,49 @@ pango_hb_family_remove_face (PangoHbFamily *self, * * Returns: (transfer none) (nullable): the face */ -PangoHbFace * +PangoFontFace * pango_hb_family_find_face (PangoHbFamily *family, PangoFontDescription *description, PangoLanguage *language, gunichar wc) { - PangoHbFace *face = NULL; + PangoFontFace *face = NULL; int best_distance = G_MAXINT; int best_variableness = 0; /* First look for an exact match if the description has a faceid */ if (pango_font_description_get_set_fields (description) & PANGO_FONT_MASK_FACEID) { + const char *faceid = pango_font_description_get_faceid (description); + for (int i = 0; i < family->faces->len; i++) { - PangoHbFace *face2 = g_ptr_array_index (family->faces, i); + PangoFontFace *face2 = g_ptr_array_index (family->faces, i); + const char *faceid2 = face_get_faceid (face2); - if (g_strcmp0 (pango_font_description_get_faceid (description), - pango_hb_face_get_faceid (face2)) == 0) + if (g_strcmp0 (faceid, faceid2) == 0) return face2; } } for (int i = 0; i < family->faces->len; i++) { - PangoHbFace *face2 = g_ptr_array_index (family->faces, i); + PangoFontFace *face2 = g_ptr_array_index (family->faces, i); int distance; int variableness; - if (language && !pango_font_face_supports_language (PANGO_FONT_FACE (face2), language)) + if (language && !pango_font_face_supports_language (face2, language)) continue; - if (wc && !pango_hb_face_has_char (face2, wc)) + if (wc && !face_has_char (face2, wc)) continue; - if (!pango_font_description_is_similar (description, face2->description)) + if (!pango_font_description_is_similar (description, ((CommonFace *)face2)->description)) continue; - distance = pango_font_description_compute_distance (description, face2->description); + distance = pango_font_description_compute_distance (description, ((CommonFace *)face2)->description); - variableness = hb_face_get_variableness (face2); + variableness = face_get_variableness (PANGO_FONT_FACE (face2)); if (distance < best_distance || (distance == best_distance && variableness > best_variableness)) { diff --git a/pango/pango-hbfont-private.h b/pango/pango-hbfont-private.h index fea6162f..e24f8889 100644 --- a/pango/pango-hbfont-private.h +++ b/pango/pango-hbfont-private.h @@ -38,19 +38,36 @@ struct _HexBoxInfo double box_height; }; +typedef struct _CommonFont CommonFont; +struct _CommonFont +{ + PangoFont parent_instance; + + int size; + float dpi; + PangoGravity gravity; + PangoMatrix matrix; +}; + struct _PangoHbFont { PangoFont parent_instance; - PangoHbFace *face; int size; /* point size, scaled by PANGO_SCALE */ float dpi; + PangoGravity gravity; + PangoMatrix matrix; + + /* up to here shared with PangoUserFont */ + + PangoHbFace *face; hb_feature_t *features; unsigned int n_features; hb_variation_t *variations; unsigned int n_variations; - PangoGravity gravity; - PangoMatrix matrix; HexBoxInfo *hex_box_info; + PangoLanguage *approximate_char_lang; + int approximate_char_width; + int approximate_digit_width; }; diff --git a/pango/pango-hbfont.c b/pango/pango-hbfont.c index ccfb2e61..916c466e 100644 --- a/pango/pango-hbfont.c +++ b/pango/pango-hbfont.c @@ -47,7 +47,7 @@ * matrix. */ - /* {{{ Utilities */ +/* {{{ Utilities */ static int get_average_char_width (PangoFont *font, @@ -763,6 +763,7 @@ static PangoFontMetrics * pango_hb_font_get_metrics (PangoFont *font, PangoLanguage *language) { + PangoHbFont *self = PANGO_HB_FONT (font); hb_font_t *hb_font = pango_font_get_hb_font (font); PangoFontMetrics *metrics; hb_font_extents_t extents; @@ -796,8 +797,17 @@ pango_hb_font_get_metrics (PangoFont *font, else metrics->strikethrough_position = metrics->ascent / 2; - metrics->approximate_char_width = get_average_char_width (font, pango_language_get_sample_string (language)); - get_max_char_size (font, "0123456789", &metrics->approximate_digit_width, NULL); + if (self->approximate_char_width == 0 || self->approximate_char_lang != language) + { + self->approximate_char_width = get_average_char_width (font, pango_language_get_sample_string (language)); + self->approximate_char_lang = language; + } + + if (self->approximate_digit_width == 0) + get_max_char_size (font, "0123456789", &self->approximate_digit_width, NULL); + + metrics->approximate_char_width = self->approximate_char_width; + metrics->approximate_digit_width = self->approximate_digit_width; return metrics; } @@ -806,7 +816,6 @@ static hb_font_t * pango_hb_font_create_hb_font (PangoFont *font) { PangoHbFont *self = PANGO_HB_FONT (font); - hb_face_t *hb_face; hb_font_t *hb_font; double x_scale, y_scale; unsigned int n_axes; @@ -814,8 +823,7 @@ pango_hb_font_create_hb_font (PangoFont *font) float *coords; int size; - hb_face = pango_hb_face_get_hb_face (self->face); - hb_font = hb_font_create (hb_face); + hb_font = hb_font_create (pango_hb_face_get_hb_face (self->face)); size = self->size * self->dpi / 72.f; x_scale = self->face->x_scale; @@ -843,7 +851,7 @@ pango_hb_font_create_hb_font (PangoFont *font) axes = g_alloca (sizeof (hb_ot_var_axis_info_t) * n_axes); coords = g_alloca (sizeof (float) * n_axes); - hb_ot_var_get_axis_infos (hb_face, 0, &n_axes, axes); + hb_ot_var_get_axis_infos (self->face->face, 0, &n_axes, axes); if (self->face->instance_id >= 0) hb_ot_var_named_instance_get_design_coords (self->face->face, self->face->instance_id, &n_axes, coords); @@ -1042,6 +1050,24 @@ pango_hb_font_new_for_description (PangoHbFace *face, return pango_hb_font_new (face, size, features, n_features, variations, n_variations, gravity, dpi, matrix); } +/** + * pango_hb_font_get_size: + * @font: a `PangoHbFont` + * + * Returns the size of the font in points, scaled by `PANGO_SCALE`. + * + * This is the same value that was passed as size to [ctor@Pango.HbFont.new]. + * + * Returns: the size of @font + */ +int +pango_hb_font_get_size (PangoHbFont *font) +{ + g_return_val_if_fail (PANGO_IS_HB_FONT (font), 0); + + return font->size; +} + /* }}} */ /* vim:set foldmethod=marker expandtab: */ diff --git a/pango/pango-hbfont.h b/pango/pango-hbfont.h index 1c747d97..cd2cabc9 100644 --- a/pango/pango-hbfont.h +++ b/pango/pango-hbfont.h @@ -48,3 +48,6 @@ PangoHbFont * pango_hb_font_new_for_description (PangoHbFace float dpi, const PangoMatrix *matrix); G_END_DECLS + +PANGO_AVAILABLE_IN_1_52 +int pango_hb_font_get_size (PangoHbFont *font); diff --git a/pango/pango-hbfontmap.c b/pango/pango-hbfontmap.c index cfe486bc..db7bd8a8 100644 --- a/pango/pango-hbfontmap.c +++ b/pango/pango-hbfontmap.c @@ -28,6 +28,8 @@ #include "pango-generic-family-private.h" #include "pango-hbface-private.h" #include "pango-hbfont-private.h" +#include "pango-userface-private.h" +#include "pango-userfont-private.h" #include "pango-fontset.h" #include "pango-trace-private.h" #include "pango-context.h" @@ -153,6 +155,18 @@ pango_fontset_cached_finalize (GObject *object) } static PangoFont * +font_new_for_description (PangoFontFace *face, + const PangoFontDescription *description, + float dpi, + const PangoMatrix *matrix) +{ + if (PANGO_IS_HB_FACE (face)) + return PANGO_FONT (pango_hb_font_new_for_description (PANGO_HB_FACE (face), description, dpi, matrix)); + else + return PANGO_FONT (pango_user_font_new_for_description (PANGO_USER_FACE (face), description, dpi, matrix)); +} + +static PangoFont * pango_fontset_cached_get_font (PangoFontset *fontset, guint wc) { @@ -168,7 +182,7 @@ pango_fontset_cached_get_font (PangoFontset *fontset, { gpointer item = g_ptr_array_index (self->items, i); - if (PANGO_IS_HB_FONT (item)) + if (PANGO_IS_FONT (item)) { PangoFont *font = PANGO_FONT (item); if (pango_font_has_char (font, wc)) @@ -180,7 +194,7 @@ pango_fontset_cached_get_font (PangoFontset *fontset, else if (PANGO_IS_GENERIC_FAMILY (item)) { PangoGenericFamily *family = PANGO_GENERIC_FAMILY (item); - PangoHbFace *face; + PangoFontFace *face; /* Here is where we implement delayed picking for generic families. * If a face does not cover the character and its family is generic, @@ -192,10 +206,10 @@ pango_fontset_cached_get_font (PangoFontset *fontset, wc); if (face) { - retval = PANGO_FONT (pango_hb_font_new_for_description (face, - self->description, - self->dpi, - self->matrix)); + retval = font_new_for_description (face, + self->description, + self->dpi, + self->matrix); break; } } @@ -214,12 +228,12 @@ pango_fontset_cached_get_first_font (PangoFontsetCached *self) item = g_ptr_array_index (self->items, 0); - if (PANGO_IS_HB_FONT (item)) + if (PANGO_IS_FONT (item)) return g_object_ref (PANGO_FONT (item)); else if (PANGO_IS_GENERIC_FAMILY (item)) { - PangoHbFace *face = pango_generic_family_find_face (PANGO_GENERIC_FAMILY (item), self->description, self->language, 0); - return PANGO_FONT (pango_hb_font_new_for_description (face, self->description, self->dpi, self->matrix)); + PangoFontFace *face = pango_generic_family_find_face (PANGO_GENERIC_FAMILY (item), self->description, self->language, 0); + return font_new_for_description (face, self->description, self->dpi, self->matrix); } return NULL; @@ -265,12 +279,14 @@ pango_fontset_cached_foreach (PangoFontset *fontset, gpointer item = g_ptr_array_index (self->items, i); PangoFont *font = NULL; - if (PANGO_IS_HB_FONT (item)) - font = g_object_ref (PANGO_FONT (item)); + if (PANGO_IS_FONT (item)) + { + font = g_object_ref (PANGO_FONT (item)); + } else if (PANGO_IS_GENERIC_FAMILY (item)) { - PangoHbFace *face = pango_generic_family_find_face (PANGO_GENERIC_FAMILY (item), self->description, self->language, 0); - font = PANGO_FONT (pango_hb_font_new_for_description (face, self->description, self->dpi, self->matrix)); + PangoFontFace *face = pango_generic_family_find_face (PANGO_GENERIC_FAMILY (item), self->description, self->language, 0); + font = font_new_for_description (face, self->description, self->dpi, self->matrix); } if ((*func) (fontset, font, data)) @@ -315,13 +331,20 @@ pango_fontset_cached_new (const PangoFontDescription *description, static void pango_fontset_cached_add_face (PangoFontsetCached *self, - PangoHbFace *face) + PangoFontFace *face) { - g_ptr_array_add (self->items, - pango_hb_font_new_for_description (face, - self->description, - self->dpi, - self->matrix)); + if (PANGO_IS_HB_FACE (face)) + g_ptr_array_add (self->items, + pango_hb_font_new_for_description (PANGO_HB_FACE (face), + self->description, + self->dpi, + self->matrix)); + else + g_ptr_array_add (self->items, + pango_user_font_new_for_description (PANGO_USER_FACE (face), + self->description, + self->dpi, + self->matrix)); } static void @@ -446,17 +469,18 @@ add_style_variation (PangoHbFamily *family, { PangoMatrix italic_matrix = { 1, 0.2, 0, 1, 0, 0 }; PangoFontDescription *desc; + PangoHbFace *variation; desc = pango_font_description_new (); pango_font_description_set_style (desc, style); pango_font_description_set_weight (desc, weight); - pango_hb_family_add_face (family, - pango_hb_face_new_synthetic (face, - style == PANGO_STYLE_ITALIC ? &italic_matrix : NULL, - weight == PANGO_WEIGHT_BOLD, - NULL, - desc)); + variation = pango_hb_face_new_synthetic (face, + style == PANGO_STYLE_ITALIC ? &italic_matrix : NULL, + weight == PANGO_WEIGHT_BOLD, + NULL, + desc); + pango_hb_family_add_face (family, PANGO_FONT_FACE (variation)); pango_font_description_free (desc); } @@ -481,6 +505,9 @@ synthesize_bold_and_italic_faces (PangoHbFontMap *map) PangoStyle style; int dist; + if (!PANGO_IS_HB_FACE (face)) + continue; + weight = pango_font_description_get_weight (face->description); style = pango_font_description_get_style (face->description); @@ -528,7 +555,7 @@ synthesize_bold_and_italic_faces (PangoHbFontMap *map) } } - /* }}} */ +/* }}} */ /* {{{ PangoFontMap implementation */ G_DEFINE_TYPE_WITH_CODE (PangoHbFontMap, pango_hb_font_map, PANGO_TYPE_FONT_MAP, @@ -609,7 +636,7 @@ pango_hb_font_map_load_fontset (PangoFontMap *map, char **families; PangoFontDescription *copy; PangoFontFamily *family; - PangoHbFace *face; + PangoFontFace *face; gboolean has_generic = FALSE; gint64 before G_GNUC_UNUSED; @@ -798,7 +825,7 @@ pango_hb_font_map_repopulate (PangoHbFontMap *self, for (int i = 0; i < self->added_faces->len; i++) { - PangoHbFace *face = PANGO_HB_FACE (g_ptr_array_index (self->added_faces, i)); + PangoFontFace *face = g_ptr_array_index (self->added_faces, i); pango_hb_font_map_add_face (self, face); } @@ -837,7 +864,7 @@ pango_hb_font_map_new (void) /** * pango_hb_font_map_add_face: * @self: a `PangoHbFontMap` - * @face: (transfer full): a `PangoHbFace` + * @face: (transfer full): a `PangoFontFace` * * Adds @face to the `PangoHbFontMap`. * @@ -848,20 +875,28 @@ pango_hb_font_map_new (void) */ void pango_hb_font_map_add_face (PangoHbFontMap *self, - PangoHbFace *face) + PangoFontFace *face) { PangoFontMap *map = PANGO_FONT_MAP (self); const char *family_name; PangoHbFamily *family; + const PangoFontDescription *description; + + g_return_if_fail (PANGO_IS_HB_FACE (face) || PANGO_IS_USER_FACE (face)); - if (pango_font_description_get_set_fields (face->description) & + if (PANGO_IS_HB_FACE (face)) + description = PANGO_HB_FACE (face)->description; + else + description = PANGO_USER_FACE (face)->description; + + if (pango_font_description_get_set_fields (description) & (PANGO_FONT_MASK_VARIANT | PANGO_FONT_MASK_GRAVITY)) - g_warning ("Font description for PangoHbFace includes things that it shouldn't"); + g_warning ("Font description for PangoFontFace includes things that it shouldn't"); if (!self->in_populate) g_ptr_array_add (self->added_faces, g_object_ref (face)); - family_name = pango_font_description_get_family (face->description); + family_name = pango_font_description_get_family (description); family = PANGO_HB_FAMILY (pango_font_map_get_family (map, family_name)); if (!family) { @@ -879,7 +914,7 @@ pango_hb_font_map_add_face (PangoHbFontMap *self, /** * pango_hb_font_map_remove_face: * @self: a `PangoHbFontMap` - * @face: a `PangoHbFace` that belongs to @map + * @face: a `PangoFontFace` that belongs to @map * * Removes @face from the `PangoHbFontMap`. * @@ -889,15 +924,17 @@ pango_hb_font_map_add_face (PangoHbFontMap *self, */ void pango_hb_font_map_remove_face (PangoHbFontMap *self, - PangoHbFace *face) + PangoFontFace *face) { PangoHbFamily *family; unsigned int position; + g_return_if_fail (PANGO_IS_HB_FACE (face) || PANGO_IS_USER_FACE (face)); + if (!g_ptr_array_find (self->added_faces, face, &position)) return; - family = PANGO_HB_FAMILY (pango_font_face_get_family (PANGO_FONT_FACE (face))); + family = PANGO_HB_FAMILY (pango_font_face_get_family (face)); pango_hb_family_remove_face (family, face); @@ -930,7 +967,7 @@ pango_hb_font_map_add_file (PangoHbFontMap *self, PangoHbFace *face; face = pango_hb_face_new_from_file (file, 0, -1, NULL, NULL); - pango_hb_font_map_add_face (self, face); + pango_hb_font_map_add_face (self, PANGO_FONT_FACE (face)); } /** diff --git a/pango/pango-hbfontmap.h b/pango/pango-hbfontmap.h index 3ced207d..6fab53a0 100644 --- a/pango/pango-hbfontmap.h +++ b/pango/pango-hbfontmap.h @@ -40,11 +40,11 @@ void pango_hb_font_map_add_file (PangoHbFontMap PANGO_AVAILABLE_IN_1_52 void pango_hb_font_map_add_face (PangoHbFontMap *self, - PangoHbFace *face); + PangoFontFace *face); PANGO_AVAILABLE_IN_1_52 void pango_hb_font_map_remove_face (PangoHbFontMap *self, - PangoHbFace *face); + PangoFontFace *face); PANGO_AVAILABLE_IN_1_52 void pango_hb_font_map_add_family (PangoHbFontMap *self, diff --git a/pango/pango-userface-private.h b/pango/pango-userface-private.h new file mode 100644 index 00000000..8465036e --- /dev/null +++ b/pango/pango-userface-private.h @@ -0,0 +1,54 @@ +/* Pango + * + * Copyright (C) 2022 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "pango-userface.h" +#include "pango-fontmap.h" +#include <hb.h> + +struct _PangoUserFace +{ + PangoFontFace parent_instance; + + PangoFontDescription *description; + char *name; + PangoFontFamily *family; + char *psname; + char *faceid; + + /* up to here shared with PangoHbFace */ + + PangoUserFaceGetFontInfoFunc font_info_func; + PangoUserFaceUnicodeToGlyphFunc glyph_func; + PangoUserFaceGetGlyphInfoFunc glyph_info_func; + PangoUserFaceTextToGlyphFunc shape_func; + PangoUserFaceRenderGlyphFunc render_func; + gpointer user_data; + GDestroyNotify destroy; +}; + +void pango_user_face_set_family (PangoUserFace *self, + PangoFontFamily *family); + +gboolean pango_user_face_has_char (PangoUserFace *self, + gunichar wc); + +const char * pango_user_face_get_faceid (PangoUserFace *self); diff --git a/pango/pango-userface.c b/pango/pango-userface.c new file mode 100644 index 00000000..63b9ac1f --- /dev/null +++ b/pango/pango-userface.c @@ -0,0 +1,484 @@ +/* Pango + * + * Copyright (C) 2022 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "pango-font-private.h" +#include "pango-userface-private.h" +#include "pango-userfont-private.h" +#include "pango-utils.h" +#include "pango-impl-utils.h" + +#include <string.h> +#include <hb-ot.h> + +/** + * PangoUserFace: + * + * `PangoUserFace` is a `PangoFontFace` implementation that uses callbacks. + */ + + /* {{{ Utilities */ + +static void +ensure_psname (PangoUserFace *self) +{ + char *p; + + if (self->psname) + return; + + self->psname = g_strconcat (pango_font_description_get_family (self->description), "_", self->name, NULL); + + /* PostScript name should not contain problematic chars, but just in case, + * make sure we don't have any ' ', '=' or ',' that would give us parsing + * problems. + */ + p = self->psname; + while ((p = strpbrk (p, " =,")) != NULL) + *p = '?'; +} + +static const char * +style_from_font_description (const PangoFontDescription *desc) +{ + PangoStyle style = pango_font_description_get_style (desc); + PangoWeight weight = pango_font_description_get_weight (desc); + + switch (style) + { + case PANGO_STYLE_ITALIC: + if (weight == PANGO_WEIGHT_BOLD) + return "Bold Italic"; + else + return "Italic"; + break; + case PANGO_STYLE_OBLIQUE: + if (weight == PANGO_WEIGHT_BOLD) + return "Bold Oblique"; + else + return "Oblique"; + break; + case PANGO_STYLE_NORMAL: + if (weight == PANGO_WEIGHT_BOLD) + return "Bold"; + else + return "Regular"; + break; + default: ; + } + + return NULL; +} + +static gboolean +default_shape_func (PangoUserFace *face, + int size, + const char *text, + int length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs, + PangoShapeFlags flags, + gpointer user_data) +{ + int n_chars; + const char *p; + int cluster = 0; + int i; + int last_cluster; + gboolean is_color; + hb_glyph_extents_t ext; + hb_position_t dummy; + + n_chars = g_utf8_strlen (text, length); + + pango_glyph_string_set_size (glyphs, n_chars); + + last_cluster = -1; + + p = text; + for (i = 0; i < n_chars; i++) + { + gunichar wc; + PangoGlyph glyph; + PangoRectangle logical_rect; + + wc = g_utf8_get_char (p); + + if (g_unichar_type (wc) != G_UNICODE_NON_SPACING_MARK) + cluster = p - text; + + if (pango_is_zero_width (wc)) + glyph = PANGO_GLYPH_EMPTY; + else if (!face->glyph_func (face, wc, &glyph, face->user_data)) + glyph = PANGO_GET_UNKNOWN_GLYPH (wc); + + face->glyph_info_func (face, size, glyph, &ext, &dummy, &dummy, &is_color, face->user_data); + pango_font_get_glyph_extents (analysis->font, glyph, NULL, &logical_rect); + + glyphs->glyphs[i].glyph = glyph; + + glyphs->glyphs[i].attr.is_cluster_start = cluster != last_cluster; + glyphs->glyphs[i].attr.is_color = is_color; + + glyphs->glyphs[i].geometry.x_offset = 0; + glyphs->glyphs[i].geometry.y_offset = 0; + glyphs->glyphs[i].geometry.width = logical_rect.width; + + glyphs->log_clusters[i] = cluster; + last_cluster = cluster; + + p = g_utf8_next_char (p); + } + + if (analysis->level & 1) + pango_glyph_string_reverse_range (glyphs, 0, glyphs->num_glyphs); + + return TRUE; +} + +static gboolean +default_render_func (PangoUserFace *face, + int size, + hb_codepoint_t glyph, + gpointer user_data, + const char *backend_id, + gpointer backend_data) +{ + /* Draw nothing... not very exciting */ + return TRUE; +} + +/* }}} */ +/* {{{ PangoFontFace implementation */ + +struct _PangoUserFaceClass +{ + PangoFontFaceClass parent_class; +}; + +G_DEFINE_TYPE (PangoUserFace, pango_user_face, PANGO_TYPE_FONT_FACE) + +static void +pango_user_face_init (PangoUserFace *self) +{ +} + +static void +pango_user_face_finalize (GObject *object) +{ + PangoUserFace *self = PANGO_USER_FACE (object); + + pango_font_description_free (self->description); + g_free (self->name); + g_free (self->faceid); + if (self->destroy) + self->destroy (self->user_data); + + G_OBJECT_CLASS (pango_user_face_parent_class)->finalize (object); +} + +static const char * +pango_user_face_get_face_name (PangoFontFace *face) +{ + PangoUserFace *self = PANGO_USER_FACE (face); + + return self->name; +} + +static PangoFontDescription * +pango_user_face_describe (PangoFontFace *face) +{ + PangoUserFace *self = PANGO_USER_FACE (face); + + if ((pango_font_description_get_set_fields (self->description) & PANGO_FONT_MASK_FACEID) == 0) + pango_font_description_set_faceid (self->description, pango_user_face_get_faceid (self)); + + return pango_font_description_copy (self->description); +} + +static PangoFontFamily * +pango_user_face_get_family (PangoFontFace *face) +{ + PangoUserFace *self = PANGO_USER_FACE (face); + + return self->family; +} + +static gboolean +pango_user_face_is_synthesized (PangoFontFace *face) +{ + return TRUE; +} + +static gboolean +pango_user_face_is_monospace (PangoFontFace *face) +{ + return FALSE; +} + +static gboolean +pango_user_face_is_variable (PangoFontFace *face) +{ + return FALSE; +} + +static void +pango_user_face_class_init (PangoUserFaceClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + PangoFontFaceClass *face_class = PANGO_FONT_FACE_CLASS (class); + + object_class->finalize = pango_user_face_finalize; + + face_class->get_face_name = pango_user_face_get_face_name; + face_class->describe = pango_user_face_describe; + face_class->list_sizes = NULL; + face_class->is_synthesized = pango_user_face_is_synthesized; + face_class->get_family = pango_user_face_get_family; + face_class->is_monospace = pango_user_face_is_monospace; + face_class->is_variable = pango_user_face_is_variable; +} + +/* }}} */ +/* {{{ Private API */ + +/*< private > + * pango_user_face_set_family: + * @self: a `PangoUserFace` + * @family: a `PangoFontFamily` + * + * Sets the font family of a `PangoUserFace`. + * + * This should only be called by fontmap implementations. + */ +void +pango_user_face_set_family (PangoUserFace *self, + PangoFontFamily *family) +{ + self->family = family; +} + +/*< private > + * pango_user_face_has_char: + * @self: a `PangoUserFace` + * @wc: a Unicode character + * + * Returns whether the face provides a glyph for this character. + * + * Returns: `TRUE` if @font can render @wc + */ +gboolean +pango_user_face_has_char (PangoUserFace *self, + gunichar wc) +{ + hb_codepoint_t glyph; + + return self->glyph_func (self, wc, &glyph, self->user_data); +} + +/*< private > + * pango_user_face_get_faceid: + * @self: a `PangoUserFace` + * + * Returns the faceid of the face. + * + * Returns: (transfer none): the faceid + */ +const char * +pango_user_face_get_faceid (PangoUserFace *self) +{ + if (!self->faceid) + { + ensure_psname (self); + self->faceid = g_strconcat ("user:", self->psname, NULL); + } + + return self->faceid; +} + +/* }}} */ + /* {{{ Public API */ + +/** + * PangoUserFaceGetFontInfoFunc: + * @face: the `PangoUserFace` + * @size: the size of the font that is being created + * @extents: (out caller-allocates): return location for font extents + * user_data: user data that was pased to [ctor@Pango.UserFace.new] + * + * The type of the function that is called to obtain font extents for user fonts. + * + * Returns: `TRUE` on success + */ + +/** + * PangoUserFaceUnicodeToGlyphFunc: + * @face: the `PangoUserFace` + * @unicode: the Unicode character + * @glyph: (out caller-allocates): return location for the glyph that + * user_data: user data that was pased to [ctor@Pango.UserFace.new] + * + * The type of the function that is called to determine if a user + * font can render a character, and what glyph it will use. + * + * Returns: `TRUE` on success + */ + +/** + * PangoUserFaceGetGlyphInfoFunc: + * @face: the `PangoUserFace` + * @size: the size of the font that is queried + * @glyph: the glyph that is being queried + * @extents: (out caller-allocates): return location for the glyphs ink rectangle + * @h_advance: (out caller-allocates): return location for the h advance + * @v_advance: (out caller-allocates): return location for the v advance + * @is_color_glyph: (out caller-allocates): return location for information about + * whether @glyph has color + * user_data: user data that was pased to [ctor@Pango.UserFace.new] + * + * The type of the function that is called to query information about + * a glyph in a user font. + * + * Returns: `TRUE` on success + */ + +/** + * PangoUserFaceTextToGlyphFunc: + * @face: the `PangoUserFace` + * @size: the size of the font that is used + * @text: the text to shape + * @length: the length of @text + * @analysis: `PangoAnalysis` for @text + * @glyphs: (out caller-allocates): the `PangoGlyphString` to populate + * @flags: `PangoShapeFlags` to use + * user_data: user data that was pased to [ctor@Pango.UserFace.new] + * + * The type of the function that is used to shape a segment of text + * with a user font. + * + * This callback is optional when creating a user font. If it isn't + * provided, Pango will rely on the `PangoUserFaceUnicodeToGlyphFunc` + * and the `PangoUserFaceGetGlyphInfo` callback to translate Unicode + * characters to glyphs 1-1, and position the glyphs according to their + * advance widths. + * + * If this callback is provided, it replaces all of Pango's own shaping. + * The function can implement ligatures, reordering, and other features + * that turn the text-to-glyph mapping into an m-n relationship. The + * function is responsible for filling not just the glyphs and their + * positions, but also cluster information and glyph attributes in + * [struct@Pango.VisAttr]. + * + * Returns: `TRUE` on success + */ + +/** + * PangoUserFaceRenderGlyphFunc: + * @face: the `PangoUserFace` + * @size: the size of the font that is used + * @glyph: the glyph that is being queried + * @user_data: user data that was pased to [ctor@Pango.UserFace.new] + * @backend_id: a string identifying the [class@Pango.Renderer] in use + * @backend_data: backend-specific data + * + * The type of the function that is called to render a glyph with a + * user font. + * + * This callback is optional when creating a user font. IF it isn't + * provided, the font will not produce any visible output. + * + * The @backend_id identifies the [class@Pango.Renderer] in use. + * Implementations should return `FALSE` for unsupported backends. + * + * The cairo backend uses the string "cairo" as @backend_id, and + * provides a `cairo_t` as @backend_data. The context is set up + * to render in `font space`, i.e. The transformation is set up + * to map the unit square to @size x @size. If supported, Pango + * uses `cairo_user_font_face_set_render_color_glyph_func` to + * allow glyphs to be rendered with colors. For more information, + * see the cairo documentation about user fonts. + * + * Returns: `TRUE` on success + */ + +/** + * pango_user_face_new: + * @font_info_func: a `PangoUserFaceGetFontInfoFunc` + * @glyph_func: a `PangoUserFaceUnicodeToGlyphFunc` + * @glyph_info_func: a `PangoUserFaceGetGlyphInfoFunc` + * @shape_func: (nullable): a `PangoUserFaceTextToGlyphFunc` + * @render_func: (nullable): a `PangoUserFaceRenderGlyphFunc` + * @user_data: user data that will be assed to the callbacks + * @destroy: destroy notify for @user_data + * @name: name for the face + * @description: (nullable): `PangoFontDescription` for the font + * + * Creates a new user font face. + * + * A user font face does not rely on font data from a font file, + * but instead uses callbacks to determine glyph extents, positions + * and rendering. + * + * If @shape_func is `NULL`, Pango will rely on @glyph_func and + * @glyph_info_func to find and position a glyph for each character. + * + * If @render_func is `NULL`, the font will not produce any visible + * glyphs. + * + * Returns: (transfer full): a newly created `PangoUserFace` + * + * Since: 1.52 + */ +PangoUserFace * +pango_user_face_new (PangoUserFaceGetFontInfoFunc font_info_func, + PangoUserFaceUnicodeToGlyphFunc glyph_func, + PangoUserFaceGetGlyphInfoFunc glyph_info_func, + PangoUserFaceTextToGlyphFunc shape_func, + PangoUserFaceRenderGlyphFunc render_func, + gpointer user_data, + GDestroyNotify destroy, + const char *name, + const PangoFontDescription *description) +{ + PangoUserFace *self; + + self = g_object_new (PANGO_TYPE_USER_FACE, NULL); + + self->font_info_func = font_info_func; + self->glyph_func = glyph_func; + self->glyph_info_func = glyph_info_func; + self->shape_func = shape_func ? shape_func : default_shape_func; + self->render_func = render_func ? render_func : default_render_func; + self->user_data = user_data; + self->destroy = destroy; + + if (!name) + name = style_from_font_description (description); + + self->name = g_strdup (name); + self->description = pango_font_description_copy (description); + + return self; +} + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ diff --git a/pango/pango-userface.h b/pango/pango-userface.h new file mode 100644 index 00000000..af6c33bd --- /dev/null +++ b/pango/pango-userface.h @@ -0,0 +1,82 @@ +/* Pango + * + * Copyright (C) 2022 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include <pango/pango-types.h> +#include <pango/pango-glyph.h> +#include <pango/pango-font.h> + +G_BEGIN_DECLS + +typedef struct _PangoUserFont PangoUserFont; + +#define PANGO_TYPE_USER_FACE (pango_user_face_get_type ()) + +PANGO_AVAILABLE_IN_1_52 +G_DECLARE_FINAL_TYPE (PangoUserFace, pango_user_face, PANGO, USER_FACE, PangoFontFace) + +typedef gboolean (* PangoUserFaceGetFontInfoFunc) (PangoUserFace *face, + int size, + hb_font_extents_t *extents, + gpointer user_data); + +typedef gboolean (* PangoUserFaceUnicodeToGlyphFunc) (PangoUserFace *face, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + gpointer user_data); + +typedef gboolean (* PangoUserFaceGetGlyphInfoFunc) (PangoUserFace *face, + int size, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + hb_position_t *h_advance, + hb_position_t *v_advance, + gboolean *is_color_glyph, + gpointer user_data); + +typedef gboolean (* PangoUserFaceTextToGlyphFunc) (PangoUserFace *face, + int size, + const char *text, + int length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs, + PangoShapeFlags flags, + gpointer user_data); + +typedef gboolean (* PangoUserFaceRenderGlyphFunc) (PangoUserFace *face, + int size, + hb_codepoint_t glyph, + gpointer user_data, + const char *backend_id, + gpointer backend_data); + +PANGO_AVAILABLE_IN_1_52 +PangoUserFace * pango_user_face_new (PangoUserFaceGetFontInfoFunc font_info_func, + PangoUserFaceUnicodeToGlyphFunc glyph_func, + PangoUserFaceGetGlyphInfoFunc glyph_info_func, + PangoUserFaceTextToGlyphFunc shape_func, + PangoUserFaceRenderGlyphFunc render_func, + gpointer user_data, + GDestroyNotify destroy, + const char *name, + const PangoFontDescription *description); + +G_END_DECLS diff --git a/pango/pango-userfont-private.h b/pango/pango-userfont-private.h new file mode 100644 index 00000000..316807d6 --- /dev/null +++ b/pango/pango-userfont-private.h @@ -0,0 +1,39 @@ +/* Pango + * + * Copyright (C) 2022 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include "pango-userfont.h" +#include "pango-userface.h" +#include <hb.h> + +struct _PangoUserFont +{ + PangoFont parent_instance; + + int size; /* point size, scaled by PANGO_SCALE */ + float dpi; + PangoGravity gravity; + PangoMatrix matrix; + + /* up to here shared with PangoHbFont */ + + PangoUserFace *face; +}; diff --git a/pango/pango-userfont.c b/pango/pango-userfont.c new file mode 100644 index 00000000..d0860cca --- /dev/null +++ b/pango/pango-userfont.c @@ -0,0 +1,483 @@ +/* Pango + * + * Copyright (C) 2021 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "pango-userfont-private.h" + +#include "pango-font-private.h" +#include "pango-coverage-private.h" +#include "pango-userface-private.h" +#include "pango-hbfamily-private.h" +#include "pango-impl-utils.h" +#include "pango-language-set-private.h" + +#include <hb-ot.h> + +/** + * PangoUserFont: + * + * `PangoUserFont` is a `PangoFont` implementation that uses callbacks. + */ + +/* {{{ PangoFont implementation */ + +struct _PangoUserFontClass +{ + PangoFontClass parent_class; +}; + +G_DEFINE_TYPE (PangoUserFont, pango_user_font, PANGO_TYPE_FONT) + +static void +pango_user_font_init (PangoUserFont *self) +{ + self->gravity = PANGO_GRAVITY_AUTO; + self->matrix = (PangoMatrix) PANGO_MATRIX_INIT; +} + +static void +pango_user_font_finalize (GObject *object) +{ + PangoUserFont *self = PANGO_USER_FONT (object); + + g_object_unref (self->face); + + G_OBJECT_CLASS (pango_user_font_parent_class)->finalize (object); +} + +static PangoFontDescription * +pango_user_font_describe (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + PangoFontDescription *desc; + + desc = pango_font_face_describe (PANGO_FONT_FACE (self->face)); + pango_font_description_set_gravity (desc, self->gravity); + pango_font_description_set_size (desc, self->size); + + return desc; +} + +static PangoFontDescription * +pango_user_font_describe_absolute (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + PangoFontDescription *desc; + + desc = pango_user_font_describe (font); + pango_font_description_set_absolute_size (desc, self->size * self->dpi / 72.); + + return desc; +} + +static PangoCoverage * +pango_user_font_get_coverage (PangoFont *font, + PangoLanguage *language G_GNUC_UNUSED) +{ + /* FIXME */ + return pango_coverage_new (); +} + +static void +pango_user_font_get_glyph_extents (PangoFont *font, + PangoGlyph glyph, + PangoRectangle *ink_rect, + PangoRectangle *logical_rect) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + hb_font_t *hb_font = pango_font_get_hb_font (font); + hb_glyph_extents_t extents; + hb_direction_t direction; + hb_font_extents_t font_extents; + + direction = PANGO_GRAVITY_IS_VERTICAL (self->gravity) + ? HB_DIRECTION_TTB + : HB_DIRECTION_LTR; + + hb_font_get_extents_for_direction (hb_font, direction, &font_extents); + + if (glyph == PANGO_GLYPH_EMPTY || (glyph & PANGO_GLYPH_UNKNOWN_FLAG)) + { + if (ink_rect) + ink_rect->x = ink_rect->y = ink_rect->width = ink_rect->height = 0; + + if (logical_rect) + { + logical_rect->x = logical_rect->width = 0; + logical_rect->y = - font_extents.ascender; + logical_rect->height = font_extents.ascender - font_extents.descender; + } + + return; + } + + hb_font_get_glyph_extents (hb_font, glyph, &extents); + + if (ink_rect) + { + PangoRectangle r; + + r.x = extents.x_bearing; + r.y = - extents.y_bearing; + r.width = extents.width; + r.height = - extents.height; + + switch (self->gravity) + { + case PANGO_GRAVITY_AUTO: + case PANGO_GRAVITY_SOUTH: + ink_rect->x = r.x; + ink_rect->y = r.y; + ink_rect->width = r.width; + ink_rect->height = r.height; + break; + case PANGO_GRAVITY_NORTH: + ink_rect->x = - r.x; + ink_rect->y = - r.y; + ink_rect->width = - r.width; + ink_rect->height = - r.height; + break; + case PANGO_GRAVITY_EAST: + ink_rect->x = r.y; + ink_rect->y = - r.x - r.width; + ink_rect->width = r.height; + ink_rect->height = r.width; + break; + case PANGO_GRAVITY_WEST: + ink_rect->x = - r.y - r.height; + ink_rect->y = r.x; + ink_rect->width = r.height; + ink_rect->height = r.width; + break; + default: + g_assert_not_reached (); + } + + if (PANGO_GRAVITY_IS_IMPROPER (self->gravity)) + { + PangoMatrix matrix = (PangoMatrix) PANGO_MATRIX_INIT; + pango_matrix_scale (&matrix, -1, -1); + pango_matrix_transform_rectangle (&matrix, ink_rect); + } + } + + if (logical_rect) + { + hb_position_t h_advance; + hb_font_extents_t extents; + + h_advance = hb_font_get_glyph_h_advance (hb_font, glyph); + hb_font_get_h_extents (hb_font, &extents); + + logical_rect->x = 0; + logical_rect->y = - extents.ascender; + + switch (self->gravity) + { + case PANGO_GRAVITY_AUTO: + case PANGO_GRAVITY_SOUTH: + logical_rect->y = - extents.ascender; + logical_rect->width = h_advance; + break; + case PANGO_GRAVITY_NORTH: + logical_rect->y = extents.descender; + logical_rect->width = h_advance; + break; + case PANGO_GRAVITY_EAST: + logical_rect->y = - logical_rect->height / 2; + logical_rect->width = logical_rect->height; + break; + case PANGO_GRAVITY_WEST: + logical_rect->y = - logical_rect->height / 2; + logical_rect->width = - logical_rect->height; + break; + default: + g_assert_not_reached (); + } + + if (PANGO_GRAVITY_IS_IMPROPER (self->gravity)) + { + logical_rect->height = - logical_rect->height; + logical_rect->y = - logical_rect->y; + } + } +} + +static PangoFontMetrics * +pango_user_font_get_metrics (PangoFont *font, + PangoLanguage *language) +{ + hb_font_t *hb_font = pango_font_get_hb_font (font); + PangoFontMetrics *metrics; + hb_font_extents_t extents; + + metrics = pango_font_metrics_new (); + + hb_font_get_extents_for_direction (hb_font, HB_DIRECTION_LTR, &extents); + + metrics->descent = - extents.descender; + metrics->ascent = extents.ascender; + metrics->height = extents.ascender - extents.descender + extents.line_gap; + + metrics->underline_thickness = PANGO_SCALE; + metrics->underline_position = - PANGO_SCALE; + metrics->strikethrough_thickness = PANGO_SCALE; + metrics->strikethrough_position = metrics->ascent / 2; + metrics->approximate_char_width = 0; /* FIXME */ + metrics->approximate_digit_width = 0; + + return metrics; +} + +static PangoFontMap * +pango_user_font_get_font_map (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + PangoHbFamily *family = PANGO_HB_FAMILY (self->face->family); + + return family->map; +} + +static hb_bool_t +nominal_glyph_func (hb_font_t *font, void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t *glyph, + void *user_data) +{ + PangoUserFont *self = font_data; + + return self->face->glyph_func (self->face, unicode, glyph, self->face->user_data); +} + +static hb_position_t +glyph_h_advance_func (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + void *user_data) +{ + PangoUserFont *self = font_data; + int size = self->size * self->dpi / 72.; + hb_position_t h_advance, v_advance; + hb_glyph_extents_t glyph_extents; + gboolean is_color; + + self->face->glyph_info_func (self->face, size, glyph, + &glyph_extents, + &h_advance, &v_advance, + &is_color, + self->face->user_data); + + return h_advance; +} + +static hb_bool_t +glyph_extents_func (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + void *user_data) +{ + PangoUserFont *self = font_data; + int size = self->size * self->dpi / 72.; + hb_position_t h_advance, v_advance; + gboolean is_color; + + return self->face->glyph_info_func (self->face, size, glyph, + extents, + &h_advance, &v_advance, + &is_color, + self->face->user_data); +} + +static hb_bool_t +font_extents_func (hb_font_t *font, void *font_data, + hb_font_extents_t *extents, + void *user_data) +{ + PangoUserFont *self = font_data; + int size = self->size * self->dpi / 72.; + + return self->face->font_info_func (self->face, size, extents, self->face->user_data); +} + +static hb_font_t * +pango_user_font_create_hb_font (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + hb_font_t *hb_font; + double x_scale, y_scale; + int size; + hb_blob_t *blob; + hb_face_t *face; + hb_font_funcs_t *funcs; + + blob = hb_blob_create ("", 0, HB_MEMORY_MODE_READONLY, NULL, NULL); + face = hb_face_create (blob, 0); + hb_font = hb_font_create (face); + + funcs = hb_font_funcs_create (); + + hb_font_funcs_set_nominal_glyph_func (funcs, nominal_glyph_func, NULL, NULL); + hb_font_funcs_set_glyph_h_advance_func (funcs, glyph_h_advance_func, NULL, NULL); + hb_font_funcs_set_glyph_extents_func (funcs, glyph_extents_func, NULL, NULL); + hb_font_funcs_set_font_h_extents_func (funcs, font_extents_func, NULL, NULL); + + hb_font_set_funcs (hb_font, funcs, self, NULL); + + hb_font_funcs_destroy (funcs); + hb_face_destroy (face); + hb_blob_destroy (blob); + + size = self->size * self->dpi / 72.f; + x_scale = y_scale = 1; + + if (PANGO_GRAVITY_IS_IMPROPER (self->gravity)) + { + x_scale = - x_scale; + y_scale = - y_scale; + } + + hb_font_set_scale (hb_font, size * x_scale, size * y_scale); + hb_font_set_ptem (hb_font, self->size / PANGO_SCALE); + + return hb_font; +} + +static gboolean +pango_user_font_has_char (PangoFont *font, + gunichar wc) +{ + hb_font_t *user_font = pango_font_get_hb_font (font); + hb_codepoint_t glyph; + + return hb_font_get_nominal_glyph (user_font, wc, &glyph); +} + +static PangoFontFace * +pango_user_font_get_face (PangoFont *font) +{ + PangoUserFont *self = PANGO_USER_FONT (font); + + return PANGO_FONT_FACE (self->face); +} + +static void +pango_user_font_class_init (PangoUserFontClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + PangoFontClass *font_class = PANGO_FONT_CLASS (class); + PangoFontClassPrivate *pclass; + + object_class->finalize = pango_user_font_finalize; + + font_class->describe = pango_user_font_describe; + font_class->describe_absolute = pango_user_font_describe_absolute; + font_class->get_coverage = pango_user_font_get_coverage; + font_class->get_glyph_extents = pango_user_font_get_glyph_extents; + font_class->get_metrics = pango_user_font_get_metrics; + font_class->get_font_map = pango_user_font_get_font_map; + font_class->create_hb_font = pango_user_font_create_hb_font; + + pclass = g_type_class_get_private ((GTypeClass *) class, PANGO_TYPE_FONT); + + pclass->has_char = pango_user_font_has_char; + pclass->get_face = pango_user_font_get_face; +} + +/* }}} */ + /* {{{ Public API */ + +/** + * pango_user_font_new: + * @face: the `PangoUserFace` to use + * @size: the desired size in points, scaled by `PANGO_SCALE` + * @gravity: the gravity to use when rendering + * @dpi: the dpi used when rendering + * @matrix: (nullable): transformation matrix to use when rendering + * + * Creates a new `PangoUserFont`. + * + * Returns: a newly created `PangoUserFont` + * + * Since: 1.52 + */ +PangoUserFont * +pango_user_font_new (PangoUserFace *face, + int size, + PangoGravity gravity, + float dpi, + const PangoMatrix *matrix) +{ + PangoUserFont *self; + + self = g_object_new (PANGO_TYPE_USER_FONT, NULL); + + self->face = g_object_ref (face); + + self->size = size; + self->dpi = dpi; + if (gravity != PANGO_GRAVITY_AUTO) + self->gravity = gravity; + if (matrix) + self->matrix = *matrix; + + return self; +} + +/** + * pango_user_font_new_for_description: + * @face: the `PangoUserFace` to use + * @description: a `PangoFontDescription` + * @dpi: the dpi used when rendering + * @matrix: (nullable): transformation matrix to use when rendering + * + * Creates a new `PangoUserFont` with size and gravity taken + * from a font description. + * + * Returns: a newly created `PangoHbFont` + * + * Since: 1.52 + */ + +PangoUserFont * +pango_user_font_new_for_description (PangoUserFace *face, + const PangoFontDescription *description, + float dpi, + const PangoMatrix *matrix) +{ + int size; + PangoGravity gravity; + + if (pango_font_description_get_size_is_absolute (description)) + size = pango_font_description_get_size (description) * 72. / dpi; + else + size = pango_font_description_get_size (description); + + if ((pango_font_description_get_set_fields (description) & PANGO_FONT_MASK_GRAVITY) != 0 && + pango_font_description_get_gravity (description) != PANGO_GRAVITY_SOUTH) + gravity = pango_font_description_get_gravity (description); + else + gravity = PANGO_GRAVITY_AUTO; + + return pango_user_font_new (face, size, gravity, dpi, matrix); +} + +/* }}} */ + +/* vim:set foldmethod=marker expandtab: */ diff --git a/pango/pango-userfont.h b/pango/pango-userfont.h new file mode 100644 index 00000000..6b351573 --- /dev/null +++ b/pango/pango-userfont.h @@ -0,0 +1,47 @@ +/* Pango + * + * Copyright (C) 2022 Matthias Clasen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include <pango/pango-types.h> +#include <pango/pango-userface.h> +#include <hb.h> + +G_BEGIN_DECLS + +#define PANGO_TYPE_USER_FONT (pango_user_font_get_type ()) + +PANGO_AVAILABLE_IN_1_52 +G_DECLARE_FINAL_TYPE (PangoUserFont, pango_user_font, PANGO, USER_FONT, PangoFont) + +PANGO_AVAILABLE_IN_1_52 +PangoUserFont * pango_user_font_new (PangoUserFace *face, + int size, + PangoGravity gravity, + float dpi, + const PangoMatrix *matrix); + +PANGO_AVAILABLE_IN_1_52 +PangoUserFont * pango_user_font_new_for_description (PangoUserFace *face, + const PangoFontDescription *description, + float dpi, + const PangoMatrix *matrix); + +G_END_DECLS diff --git a/pango/pango.h b/pango/pango.h index 9d95b5e5..aa0b7975 100644 --- a/pango/pango.h +++ b/pango/pango.h @@ -52,6 +52,8 @@ #include <pango/pango-script.h> #include <pango/pango-tabs.h> #include <pango/pango-types.h> +#include <pango/pango-userface.h> +#include <pango/pango-userfont.h> #include <pango/pango-utils.h> #include <pango/pango-version-macros.h> diff --git a/pango/pangocairo-font.c b/pango/pangocairo-font.c index e265e540..ca503666 100644 --- a/pango/pangocairo-font.c +++ b/pango/pangocairo-font.c @@ -30,6 +30,8 @@ #include "pango-impl-utils.h" #include "pango-hbfont-private.h" #include "pango-hbface-private.h" +#include "pango-userfont-private.h" +#include "pango-userface-private.h" #include "pangocairo-fc.h" #pragma GCC diagnostic push @@ -73,6 +75,76 @@ _pango_cairo_font_private_scaled_font_data_destroy (PangoCairoFontPrivateScaledF static FT_Library ft_library; +static cairo_user_data_key_t cairo_user_data; + +static cairo_status_t +render_func (cairo_scaled_font_t *scaled_font, + unsigned long glyph, + cairo_t *cr, + cairo_text_extents_t *extents) +{ + cairo_font_face_t *font_face; + PangoUserFont *font; + hb_glyph_extents_t glyph_extents; + hb_position_t h_advance; + hb_position_t v_advance; + gboolean is_color; + + font_face = cairo_scaled_font_get_font_face (scaled_font); + font = cairo_font_face_get_user_data (font_face, &cairo_user_data); + + extents->x_bearing = 0; + extents->y_bearing = 0; + extents->width = 0; + extents->height = 0; + extents->x_advance = 0; + extents->y_advance = 0; + + if (!font->face->glyph_info_func (font->face, 1024, + (hb_codepoint_t)glyph, + &glyph_extents, + &h_advance, &v_advance, + &is_color, + font->face->user_data)) + { + return CAIRO_STATUS_USER_FONT_ERROR; + } + + extents->x_bearing = glyph_extents.x_bearing / (double) 1024; + extents->y_bearing = glyph_extents.y_bearing / (double) 1024; + extents->width = glyph_extents.width / (double) 1024; + extents->height = glyph_extents.height / (double) 1024; + extents->x_advance = h_advance / (double) 1024; + extents->y_advance = v_advance / (double) 1024; + + if (!font->face->render_func (font->face, font->size, + (hb_codepoint_t)glyph, + font->face->user_data, + "cairo", + cr)) + { + return CAIRO_STATUS_USER_FONT_ERROR; + } + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_font_face_t * +create_font_face_for_user_font (PangoUserFont *font) +{ + cairo_font_face_t *cairo_face; + + cairo_face = cairo_user_font_face_create (); + cairo_font_face_set_user_data (cairo_face, &cairo_user_data, font, NULL); +#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC + cairo_user_font_face_set_render_color_glyph_func (cairo_face, render_func); +#else + cairo_user_font_face_set_render_glyph_func (cairo_face, render_func); +#endif + + return cairo_face; +} + static cairo_font_face_t * create_font_face_for_hb_font (PangoHbFont *font) { @@ -144,8 +216,10 @@ _pango_cairo_font_private_get_scaled_font (PangoCairoFontPrivate *cf_priv) if (PANGO_IS_CAIRO_FONT (cf_priv->cfont)) font_face = (* PANGO_CAIRO_FONT_GET_IFACE (cf_priv->cfont)->create_font_face) (cf_priv->cfont); - else + else if (PANGO_IS_HB_FONT (cf_priv->cfont)) font_face = create_font_face_for_hb_font (PANGO_HB_FONT (cf_priv->cfont)); + else if (PANGO_IS_USER_FONT (cf_priv->cfont)) + font_face = create_font_face_for_user_font (PANGO_USER_FONT (cf_priv->cfont)); if (G_UNLIKELY (font_face == NULL)) goto done; @@ -688,26 +762,35 @@ _pango_font_get_cairo_font_private (PangoFont *font) cf_priv = g_object_get_data (G_OBJECT (font), "pango-hb-font-cairo_private"); if (!cf_priv) { - PangoHbFont *hbfont = PANGO_HB_FONT (font); + CommonFont *cf = (CommonFont *)font; cairo_font_options_t *font_options; cairo_matrix_t font_matrix; + double x_scale, y_scale; int size; - if (hbfont->face->matrix) - cairo_matrix_init (&font_matrix, - hbfont->face->matrix->xx, - - hbfont->face->matrix->yx, - - hbfont->face->matrix->xy, - hbfont->face->matrix->yy, - 0., 0.); - else - cairo_matrix_init (&font_matrix, 1., 0., 0., 1., 0., 0.); + cairo_matrix_init (&font_matrix, 1., 0., 0., 1., 0., 0.); + x_scale = y_scale = 1; + + if (PANGO_IS_HB_FONT (font)) + { + PangoHbFont *hbfont = PANGO_HB_FONT (font); + if (hbfont->face->matrix) + cairo_matrix_init (&font_matrix, + hbfont->face->matrix->xx, + - hbfont->face->matrix->yx, + - hbfont->face->matrix->xy, + hbfont->face->matrix->yy, + 0., 0.); + + x_scale = hbfont->face->x_scale; + y_scale = hbfont->face->y_scale; + } - size = hbfont->size * hbfont->dpi / 72.; + size = cf->size * cf->dpi / 72.; cairo_matrix_scale (&font_matrix, - hbfont->face->x_scale * size / (double)PANGO_SCALE, - hbfont->face->y_scale * size / (double)PANGO_SCALE); + x_scale * size / (double)PANGO_SCALE, + y_scale * size / (double)PANGO_SCALE); font_options = cairo_font_options_create (); cairo_font_options_set_hint_style (font_options, CAIRO_HINT_STYLE_NONE); @@ -716,9 +799,9 @@ _pango_font_get_cairo_font_private (PangoFont *font) cf_priv = g_new0 (PangoCairoFontPrivate, 1); _pango_cairo_font_private_initialize (cf_priv, (PangoCairoFont *)font, - hbfont->gravity, + cf->gravity, font_options, - &hbfont->matrix, + &cf->matrix, &font_matrix); cairo_font_options_destroy (font_options); diff --git a/pango/pangofc-hbfontmap.c b/pango/pangofc-hbfontmap.c index ceda2cbc..2f005059 100644 --- a/pango/pangofc-hbfontmap.c +++ b/pango/pangofc-hbfontmap.c @@ -346,7 +346,7 @@ pango_fc_hb_font_map_populate (PangoHbFontMap *map) if (!face) continue; - pango_hb_font_map_add_face (PANGO_HB_FONT_MAP (self), face); + pango_hb_font_map_add_face (PANGO_HB_FONT_MAP (self), PANGO_FONT_FACE (face)); } g_hash_table_unref (lang_hash); diff --git a/pango/shape.c b/pango/shape.c index 30bceb80..1a03ec1e 100644 --- a/pango/shape.c +++ b/pango/shape.c @@ -30,6 +30,8 @@ #include "pango-item-private.h" #include "pango-font-private.h" +#include "pango-userfont-private.h" +#include "pango-userface-private.h" #include <hb-ot.h> @@ -531,6 +533,25 @@ pango_hb_shape (const char *item_text, } /* }}} */ +/* {{{ User shaping */ + +static void +pango_user_shape (const char *text, + unsigned int length, + const PangoAnalysis *analysis, + PangoGlyphString *glyphs, + PangoShapeFlags flags) +{ + PangoUserFont *font = PANGO_USER_FONT (analysis->font); + + font->face->shape_func (font->face, font->size, + text, length, + analysis, + glyphs, flags, + font->face->user_data); +} + +/* }}} */ /* {{{ Fallback shaping */ /* This is not meant to produce reasonable results */ @@ -617,47 +638,47 @@ pango_shape_internal (const char *item_text, g_return_if_fail (paragraph_text <= item_text); g_return_if_fail (paragraph_text + paragraph_length >= item_text + item_length); - if (analysis->font) + if (PANGO_IS_HB_FONT (analysis->font)) + pango_hb_shape (item_text, item_length, + paragraph_text, paragraph_length, + analysis, + log_attrs, num_chars, + glyphs, flags); + else if (PANGO_IS_USER_FONT (analysis->font)) + pango_user_shape (item_text, item_length, analysis, glyphs, flags); + else + glyphs->num_glyphs = 0; + + if (analysis->font && glyphs->num_glyphs == 0) { - pango_hb_shape (item_text, item_length, - paragraph_text, paragraph_length, - analysis, - log_attrs, num_chars, - glyphs, flags); + /* If a font has been correctly chosen, but no glyphs are output, + * there's probably something wrong with the font. + * + * Trying to be informative, we print out the font description, + * and the text, but to not flood the terminal with + * zillions of the message, we set a flag to only err once per + * font. + */ + GQuark warned_quark = g_quark_from_static_string ("pango-shape-fail-warned"); - if (G_UNLIKELY (glyphs->num_glyphs == 0)) + if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark)) { - /* If a font has been correctly chosen, but no glyphs are output, - * there's probably something wrong with the font. - * - * Trying to be informative, we print out the font description, - * and the text, but to not flood the terminal with - * zillions of the message, we set a flag to only err once per - * font. - */ - GQuark warned_quark = g_quark_from_static_string ("pango-shape-fail-warned"); + PangoFontDescription *desc; + char *font_name; - if (!g_object_get_qdata (G_OBJECT (analysis->font), warned_quark)) - { - PangoFontDescription *desc; - char *font_name; + desc = pango_font_describe (analysis->font); + font_name = pango_font_description_to_string (desc); + pango_font_description_free (desc); - desc = pango_font_describe (analysis->font); - font_name = pango_font_description_to_string (desc); - pango_font_description_free (desc); + g_warning ("shaping failure, expect ugly output. font='%s', text='%.*s'", + font_name, item_length, item_text); - g_warning ("shaping failure, expect ugly output. font='%s', text='%.*s'", - font_name, item_length, item_text); + g_free (font_name); - g_free (font_name); - - g_object_set_qdata (G_OBJECT (analysis->font), warned_quark, - GINT_TO_POINTER (1)); - } + g_object_set_qdata (G_OBJECT (analysis->font), warned_quark, + GINT_TO_POINTER (1)); } } - else - glyphs->num_glyphs = 0; if (G_UNLIKELY (!glyphs->num_glyphs)) { |