diff options
author | Matthias Clasen <mclasen@redhat.com> | 2022-06-14 21:17:57 -0400 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2022-06-22 13:57:26 -0400 |
commit | 031c610eb1ef240cc7a165416a02b48cff1070d7 (patch) | |
tree | ec9baf59e3eba5de0359048d088b4df83e5bafc0 /tests/test-common.c | |
parent | aee6b79e1ecb061616fed1dfe539d802a2b681f6 (diff) | |
download | pango-031c610eb1ef240cc7a165416a02b48cff1070d7.tar.gz |
tests: Unify font loading code
We want full control over what gets
loaded here, so avoid using fontconfig.
Diffstat (limited to 'tests/test-common.c')
-rw-r--r-- | tests/test-common.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/tests/test-common.c b/tests/test-common.c index 99733d3b..861a06d6 100644 --- a/tests/test-common.c +++ b/tests/test-common.c @@ -34,6 +34,8 @@ #include <pango/pangocairo.h> #include "test-common.h" +#include <hb-ot.h> + char * diff_with_file (const char *file, char *text, @@ -234,3 +236,281 @@ get_script_name (GUnicodeScript s) return nick; } +static void +add_file (PangoFontMap *map, + const char *path, + const char *name) +{ + char *fullname; + hb_blob_t *blob; + hb_face_t *hbface; + PangoHbFace *face; + + fullname = g_build_filename (path, name, NULL); + + blob = hb_blob_create_from_file_or_fail (fullname); + if (!blob) + g_error ("No font data in %s", fullname); + + g_free (fullname); + + hbface = hb_face_create (blob, 0); + hb_face_make_immutable (hbface); + + if (hb_ot_var_get_axis_count (hbface) == 0) + { + /* Add the default instance */ + face = pango_hb_face_new_from_hb_face (hbface, -1, NULL, NULL); + pango_font_map_add_face (map, PANGO_FONT_FACE (face)); + return; + } + + /* Add the variable face */ + face = pango_hb_face_new_from_hb_face (hbface, -2, "Variable", NULL); + pango_font_map_add_face (map, PANGO_FONT_FACE (face)); + + if (hb_ot_var_get_named_instance_count (hbface) > 0) + { + /* Add named instances */ + for (int i = 0; i < hb_ot_var_get_named_instance_count (hbface); i++) + { + face = pango_hb_face_new_from_hb_face (hbface, i, NULL, NULL); + pango_font_map_add_face (map, PANGO_FONT_FACE (face)); + } + } + + hb_face_destroy (hbface); +} + +static void +add_generic_family (PangoFontMap *map, + const char *path, + const char *name) +{ + char *fullname; + char *contents; + gsize length; + char *basename; + char **families; + GError *error = NULL; + PangoGenericFamily *generic; + + g_assert (g_str_has_suffix (name, ".generic")); + + fullname = g_build_filename (path, name, NULL); + + if (!g_file_get_contents (fullname, &contents, &length, &error)) + g_error ("Failed to load %s: %s", fullname, error->message); + + g_free (fullname); + + basename = g_strdup (name); + basename[strlen (name) - strlen (".generic")] = '\0'; + + generic = pango_generic_family_new (basename); + + families = g_strsplit (contents, "\n", -1); + for (int i = 0; families[i]; i++) + { + const char *name = families[i]; + PangoFontFamily *family; + + if (name[0] == '\0') + continue; + + family = pango_font_map_get_family (map, name); + if (!family) + { + g_warning ("no such family: %s", name); + continue; + } + + pango_generic_family_add_family (generic, family); + } + + pango_font_map_add_family (map, PANGO_FONT_FAMILY (generic)); + + g_strfreev (families); + g_free (basename); + g_free (contents); +} + +static void +add_synthetic_faces (PangoFontMap *map, + const char *path, + const char *name) +{ + char *fullname; + char *contents; + GError *error = NULL; + gsize length; + char *basename; + PangoFontFamily *family; + gboolean make_italic; + PangoMatrix italic_matrix = { 1, 0.2, 0, 1, 0, 0 }; + PangoHbFace *newface; + GSList *newfaces, *l; + + g_assert (g_str_has_suffix (name, ".synthetic")); + + fullname = g_build_filename (path, name, NULL); + + if (!g_file_get_contents (fullname, &contents, &length, &error)) + g_error ("Failed to load %s: %s", fullname, error->message); + + g_free (fullname); + + basename = g_strdup (name); + basename[strlen (name) - strlen (".synthetic")] = '\0'; + + family = pango_font_map_get_family (map, basename); + if (!family) + g_error ("Family %s not found", basename); + + make_italic = strstr (contents, "Italic") != NULL; + + newfaces = NULL; + + + for (int i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (family)); i++) + { + PangoHbFace *face = g_list_model_get_item (G_LIST_MODEL (family), i); + + if (make_italic) + { + char *name; + PangoFontDescription *desc; + + name = g_strconcat (pango_font_face_get_name (PANGO_FONT_FACE (face)), + " Italic", + NULL); + desc = pango_font_face_describe (PANGO_FONT_FACE (face)); + pango_font_description_set_style (desc, PANGO_STYLE_ITALIC); + pango_font_description_unset_fields (desc, ~(PANGO_FONT_MASK_FAMILY| + PANGO_FONT_MASK_STYLE| + PANGO_FONT_MASK_STRETCH| + PANGO_FONT_MASK_WEIGHT)); + newface = pango_hb_face_new_synthetic (face, &italic_matrix, FALSE, name, desc); + newfaces = g_slist_prepend (newfaces, newface); + + g_free (name); + pango_font_description_free (desc); + } + + g_object_unref (face); + } + + + for (l = newfaces; l; l = l->next) + { + newface = l->data; + pango_font_map_add_face (map, PANGO_FONT_FACE (newface)); + } + + g_slist_free (newfaces); + + g_free (basename); + g_free (contents); +} + +void +install_fonts (const char *path) +{ + PangoFontMap *map; + GDir *dir; + GError *error = NULL; + const char *name; + GPtrArray *generic; + GPtrArray *synthetic; + char *testpath = NULL; + + map = pango_font_map_new (); + + if (!path) + path = testpath = g_test_build_filename (G_TEST_DIST, "fonts", NULL); + + dir = g_dir_open (path, 0, &error); + + if (!dir) + g_error ("Failed to install fonts: %s", error->message); + + generic = g_ptr_array_new (); + synthetic = g_ptr_array_new (); + + while (TRUE) + { + name = g_dir_read_name (dir); + if (name == NULL) + break; + + if (g_str_has_suffix (name, ".ttf") || + g_str_has_suffix (name, ".otf")) + add_file (map, path, name); + else if (g_str_has_suffix (name, ".generic")) + g_ptr_array_add (generic, (gpointer) name); + else if (g_str_has_suffix (name, ".synthetic")) + g_ptr_array_add (synthetic, (gpointer) name); + } + + /* Add generics and synthetics in a second path, + * so all families are already added. + */ + for (int i = 0; i < generic->len; i++) + { + name = g_ptr_array_index (generic, i); + add_generic_family (map, path, name); + } + g_ptr_array_free (generic, TRUE); + + for (int i = 0; i < synthetic->len; i++) + { + name = g_ptr_array_index (synthetic, i); + add_synthetic_faces (map, path, name); + } + g_ptr_array_free (synthetic, TRUE); + + + pango_font_map_set_default (map); + + g_object_unref (map); + g_dir_close (dir); + + g_free (testpath); +} + +void +dump_fonts (void) +{ + PangoFontMap *map; + + map = pango_font_map_get_default (); + + for (int i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (map)); i++) + { + PangoFontFamily *family = g_list_model_get_item (G_LIST_MODEL (map), i); + + if (PANGO_IS_GENERIC_FAMILY (family)) + { + g_print ("%s (generic)\n", pango_font_family_get_name (family)); + } + else + { + g_print ("%s\n", pango_font_family_get_name (family)); + + for (int j = 0; j < g_list_model_get_n_items (G_LIST_MODEL (family)); j++) + { + PangoFontFace *face = g_list_model_get_item (G_LIST_MODEL (family), j); + + g_print ("\t%s %s%s\n", + pango_font_family_get_name (family), + pango_font_face_get_name (face), + pango_font_face_is_variable (face) ? " (variable)" : ""); + + g_object_unref (face); + } + } + + g_object_unref (family); + } +} + |