summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-01-09 18:44:40 -0500
committerMatthias Clasen <mclasen@redhat.com>2022-01-28 09:03:03 -0500
commit7f4b1306810fb50a08c857ba6e8070573e785b89 (patch)
treeeb8a50b0747eb28664c7d8f8a247c10dce695d5d
parentf836b0cad86df2cdbfd917476f405eb72388e2a8 (diff)
downloadpango-7f4b1306810fb50a08c857ba6e8070573e785b89.tar.gz
Add PangoFcHbFontMap tests
-rw-r--r--tests/testhbfont.c423
1 files changed, 423 insertions, 0 deletions
diff --git a/tests/testhbfont.c b/tests/testhbfont.c
index 90bc0a11..d3e446e6 100644
--- a/tests/testhbfont.c
+++ b/tests/testhbfont.c
@@ -21,7 +21,11 @@
#include "config.h"
#include <glib.h>
+#include <gio/gio.h>
#include <pango/pangocairo.h>
+#include <pango/pangofc-hbfontmap.h>
+#include <pango/pangofc-fontmap.h>
+#include <pango/pangofc-font.h>
#include <hb-ot.h>
@@ -429,6 +433,399 @@ test_hbfont_load (void)
g_object_unref (map);
}
+/* Test font -> description -> font roundtrips with variations */
+static void
+test_hbfont_load_variation (void)
+{
+ PangoHbFontMap *map;
+ PangoContext *context;
+ char *path;
+ PangoFontDescription *desc;
+ PangoHbFace *face_fat, *face_wild;
+ char *s;
+ PangoFont *font;
+ hb_variation_t v;
+ hb_font_t *hb_font;
+ const float *coords;
+ unsigned int length;
+
+ /* Make a Cat family, with the two faces Fat and Wild */
+ map = pango_hb_font_map_new ();
+ context = pango_font_map_create_context (PANGO_FONT_MAP (map));
+
+ path = g_test_build_filename (G_TEST_DIST, "fonts", "Cantarell-VF.otf", NULL);
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, "Cat");
+ face_fat = pango_hb_face_new_from_file (path, 0, -1, "Fat", desc);
+ pango_font_description_free (desc);
+ g_free (path);
+
+ pango_hb_font_map_add_face (map, face_fat);
+
+ desc = pango_font_description_new ();
+ pango_font_description_set_family (desc, "Cat");
+ v.tag = HB_OT_TAG_VAR_AXIS_WEIGHT;
+ v.value = 624.;
+ face_wild = pango_hb_face_new_instance (face_fat, &v, 1, "Wild", desc);
+ pango_font_description_free (desc);
+
+ pango_hb_font_map_add_face (map, face_wild);
+
+ desc = pango_font_face_describe (PANGO_FONT_FACE (face_wild));
+
+ g_assert_cmpstr (pango_font_description_get_variations (desc), ==, "wght=624");
+
+ pango_font_description_set_size (desc, 12 * PANGO_SCALE);
+
+ s = pango_font_description_to_string (desc);
+ g_assert_cmpstr (s, ==, "Cat 12 @faceid=hb:Cantarell-Regular:0:-1:0:1:1:0:wght_624,wght=624");
+ g_free (s);
+
+ font = pango_font_map_load_font (PANGO_FONT_MAP (map), context, desc);
+ g_assert_true (pango_font_get_face (font) == PANGO_FONT_FACE (face_wild));
+
+ hb_font = pango_font_get_hb_font (font);
+ coords = hb_font_get_var_coords_design (hb_font, &length);
+ g_assert_cmpint (length, ==, 1);
+ g_assert_cmphex (coords[0], ==, 624.);
+
+ g_object_unref (font);
+
+ pango_font_description_free (desc);
+
+ g_object_unref (context);
+ g_object_unref (map);
+}
+
+/* Verify that pango_fontmap_load_fontset produces a non-empty result
+ * even if the language isn't covered - our itemization code relies
+ * on this.
+ */
+static gboolean
+get_font (PangoFontset *fontset,
+ PangoFont *font,
+ gpointer data)
+{
+ gboolean *found = data;
+
+ *found = TRUE;
+
+ return TRUE;
+}
+
+static void
+test_hbfontmap_language (void)
+{
+ PangoFontMap *map;
+ PangoContext *context;
+ PangoFontDescription *desc;
+ PangoFontset *fonts;
+ gboolean found;
+
+ map = PANGO_FONT_MAP (pango_fc_hb_font_map_new ());
+ context = pango_font_map_create_context (map);
+ desc = pango_font_description_from_string ("serif 11");
+
+ /* zz isn't assigned, so there should not be any fonts claiming to support
+ * this language. We are expecting to get a nonempty fontset regardless.
+ */
+ fonts = pango_font_map_load_fontset (map, context, desc, pango_language_from_string ("zz"));
+ g_assert_true (PANGO_IS_FONTSET (fonts));
+
+ found = FALSE;
+ pango_fontset_foreach (fonts, get_font, &found);
+ g_assert_true (found);
+
+ g_object_unref (fonts);
+ pango_font_description_free (desc);
+}
+
+static const char *
+get_font_file (PangoFont *font)
+{
+ if (PANGO_IS_HB_FONT (font))
+ {
+ PangoFontFace *face = pango_font_get_face (font);
+
+ return pango_hb_face_get_file (PANGO_HB_FACE (face));
+ }
+ else if (PANGO_IS_FC_FONT (font))
+ {
+ FcPattern *pattern = pango_fc_font_get_pattern (PANGO_FC_FONT (font));
+ const char *file;
+
+ FcPatternGetString (pattern, FC_FILE, 0, (FcChar8 **)&file);
+
+ return file;
+ }
+ else
+ return "Unknown";
+}
+
+typedef struct
+{
+ FcConfig *config;
+ PangoFontMap *fcfontmap;
+ PangoFontMap *hbfontmap;
+} FontMapCompareFixture;
+
+static void
+fontmap_compare_fixture_set_up (FontMapCompareFixture *fixture,
+ gconstpointer data)
+{
+ char *path, *conf;
+ FcConfig *config;
+ PangoFontMap *fcfontmap, *hbfontmap;
+
+ path = g_test_build_filename (G_TEST_DIST, "fonts", NULL);
+ if (!g_path_is_absolute (path))
+ {
+ char *dir = g_build_filename (g_get_current_dir (), path, NULL);
+ g_free (path);
+ path = dir;
+ }
+
+ config = FcConfigCreate ();
+
+ conf = g_build_filename (path, "fonts.conf", NULL);
+ if (!FcConfigParseAndLoad (config, (const FcChar8 *) conf, TRUE))
+ g_error ("Failed to parse fontconfig configuration from %s", conf);
+
+ FcConfigAppFontAddDir (config, (const FcChar8 *) path);
+
+ fcfontmap = pango_cairo_font_map_new_for_font_type (CAIRO_FONT_TYPE_FT);
+ pango_fc_font_map_set_config (PANGO_FC_FONT_MAP (fcfontmap), config);
+
+ hbfontmap = PANGO_FONT_MAP (pango_fc_hb_font_map_new ());
+ pango_fc_hb_font_map_set_config (PANGO_FC_HB_FONT_MAP (hbfontmap), config);
+
+ g_free (conf);
+ g_free (path);
+
+ fixture->config = config;
+ fixture->fcfontmap = fcfontmap;
+ fixture->hbfontmap = hbfontmap;
+}
+
+static void
+fontmap_compare_fixture_tear_down (FontMapCompareFixture *fixture,
+ gconstpointer data)
+{
+ g_object_unref (fixture->hbfontmap);
+ g_object_unref (fixture->fcfontmap);
+ FcConfigDestroy (fixture->config);
+}
+
+/* Check that we have the same families (we know
+ * generics are different, so skip those)
+ */
+
+static int
+compare_family_name (gconstpointer a,
+ gconstpointer b)
+{
+ return g_ascii_strcasecmp (*(const char **)a, *(const char **)b);
+}
+
+static gboolean
+is_generic_family (PangoFontMap *map,
+ const char *family)
+{
+ if (PANGO_IS_FC_HB_FONT_MAP (map))
+ return g_strv_contains ((const char *[]){ "sans-serif", "serif", "monospace", "system-ui", "cursive", "fantasy", "emoji", NULL}, family);
+ else
+ return g_strv_contains ((const char *[]){ "Sans", "Serif", "Monospace", "System-ui", NULL}, family);
+}
+
+static const char * const *
+collect_nongeneric_families (PangoFontMap *map)
+{
+ GPtrArray *array = g_ptr_array_new ();
+
+ for (int i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (map)); i++)
+ {
+ PangoFontFamily *fam = g_list_model_get_item (G_LIST_MODEL (map), i);
+ const char *name = pango_font_family_get_name (fam);
+
+ if (!is_generic_family (map, name))
+ g_ptr_array_add (array, (gpointer)name);
+
+ g_object_unref (fam);
+ }
+
+ g_ptr_array_sort (array, compare_family_name);
+
+ g_ptr_array_add (array, NULL);
+
+ return (const char * const *)g_ptr_array_free (array, FALSE);
+}
+
+static void
+test_hbfontmap_compare_families (FontMapCompareFixture *fixture,
+ gconstpointer data)
+{
+ const char * const *fcfamilies;
+ const char * const *hbfamilies;
+
+ fcfamilies = collect_nongeneric_families (fixture->fcfontmap);
+ hbfamilies = collect_nongeneric_families (fixture->hbfontmap);
+ g_assert_true (g_strv_equal (fcfamilies, hbfamilies));
+ g_free ((gpointer)fcfamilies);
+ g_free ((gpointer)hbfamilies);
+}
+
+static gboolean
+languages_equal (PangoLanguage **l1,
+ PangoLanguage **l2)
+{
+ int i;
+
+ if (!l1 || !l2)
+ return l1 == l2;
+
+ for (i = 0; l1[i] && l2[i]; i++)
+ if (l1[i] != l2[i])
+ return FALSE;
+
+ if (l1[i] || l2[i])
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+test_hbfontmap_compare_languages (FontMapCompareFixture *fixture,
+ gconstpointer data)
+{
+ const char *family_name = data;
+ PangoContext *context;
+ PangoFontDescription *description;
+ PangoFont *fcfont, *hbfont;
+ PangoLanguage **fclanguages;
+ PangoLanguage **hblanguages;
+
+ context = pango_font_map_create_context (fixture->fcfontmap);
+
+ description = pango_font_description_new ();
+ pango_font_description_set_family (description, family_name);
+ pango_font_description_set_size (description, 12 * PANGO_SCALE);
+
+ fcfont = pango_font_map_load_font (fixture->fcfontmap, context, description);
+ hbfont = pango_font_map_load_font (fixture->hbfontmap, context, description);
+
+ fclanguages = pango_font_get_languages (fcfont);
+ hblanguages = pango_font_get_languages (hbfont);
+
+ g_assert_nonnull (fclanguages);
+ g_assert_nonnull (hblanguages);
+ g_assert_true (languages_equal (fclanguages, hblanguages));
+
+ g_object_unref (hbfont);
+ g_object_unref (fcfont);
+
+ pango_font_description_free (description);
+
+ g_object_unref (context);
+}
+
+/* Compare the faces we get. We already know that hbfontmap adds
+ * the variable font as an extra family, so skip those.
+ */
+static int
+compare_face_name (gconstpointer a,
+ gconstpointer b)
+{
+ return strcmp (*(const char **)a, *(const char **)b);
+}
+
+static const char * const *
+collect_nonvariable_faces (PangoFontFamily *fam)
+{
+ GPtrArray *array = g_ptr_array_new ();
+
+ for (int i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (fam)); i++)
+ {
+ PangoFontFace *face = g_list_model_get_item (G_LIST_MODEL (fam), i);
+ const char *name = pango_font_face_get_face_name (face);
+
+ if (!pango_font_face_is_variable (face))
+ g_ptr_array_add (array, (gpointer)name);
+
+ g_object_unref (face);
+ }
+
+ g_ptr_array_sort (array, compare_face_name);
+
+ g_ptr_array_add (array, NULL);
+
+ return (const char * const *)g_ptr_array_free (array, FALSE);
+}
+
+static void
+test_hbfontmap_compare_faces (FontMapCompareFixture *fixture,
+ gconstpointer data)
+{
+ const char *family_name = data;
+ PangoFontFamily *fcfamily, *hbfamily;
+ const char * const *fcfaces;
+ const char * const *hbfaces;
+
+ fcfamily = pango_font_map_get_family (fixture->fcfontmap, family_name);
+ hbfamily = pango_font_map_get_family (fixture->hbfontmap, family_name);
+
+ fcfaces = collect_nonvariable_faces (fcfamily);
+ hbfaces = collect_nonvariable_faces (hbfamily);
+ if (!g_strv_equal (fcfaces, hbfaces))
+ g_print ("%s\n%s\n", g_strjoinv (", ", (char **)fcfaces), g_strjoinv (", ", (char **)hbfaces));
+ g_assert_true (g_strv_equal (fcfaces, hbfaces));
+ g_free ((gpointer)fcfaces);
+ g_free ((gpointer)hbfaces);
+}
+
+static void
+test_hbfontmap_compare_match (FontMapCompareFixture *fixture,
+ gconstpointer data)
+{
+ PangoContext *context;
+ const char *tests[] = {
+ "Amiri Bold 12",
+ "Cantarell 12",
+ "Sans 11",
+ "sans-serif 11",
+ "emoji 12",
+ "emoji 12",
+ "Cantarell Italic 11",
+ "Sans Bold 11",
+ };
+
+ context = pango_font_map_create_context (fixture->fcfontmap);
+ pango_context_set_language (context, pango_language_from_string ("en"));
+
+
+ for (int i = 0; i < G_N_ELEMENTS (tests); i++)
+ {
+ PangoFontDescription *description;
+ PangoFont *fcfont, *hbfont;
+
+ description = pango_font_description_from_string (tests[i]);
+
+ fcfont = pango_font_map_load_font (fixture->fcfontmap, context, description);
+ hbfont = pango_font_map_load_font (fixture->hbfontmap, context, description);
+
+ if (strcmp (get_font_file (fcfont), get_font_file (hbfont)) != 0)
+ g_print ("test %s\n", tests[i]);
+
+ g_assert_cmpstr (get_font_file (fcfont), ==, get_font_file (hbfont));
+
+ g_object_unref (hbfont);
+ g_object_unref (fcfont);
+
+ pango_font_description_free (description);
+ }
+
+ g_object_unref (context);
+}
+
int
main (int argc, char *argv[])
{
@@ -441,6 +838,32 @@ main (int argc, char *argv[])
g_test_add_func ("/hbfont/describe/variation", test_hbfont_describe_variation);
g_test_add_func ("/hbfont/faceid", test_hbfont_faceid);
g_test_add_func ("/hbfont/load", test_hbfont_load);
+ g_test_add_func ("/hbfont/load/variation", test_hbfont_load_variation);
+ g_test_add_func ("/hbfontmap/language", test_hbfontmap_language);
+ g_test_add ("/hbfontmap/families", FontMapCompareFixture, NULL,
+ fontmap_compare_fixture_set_up,
+ test_hbfontmap_compare_families,
+ fontmap_compare_fixture_tear_down);
+ g_test_add ("/hbfontmap/faces/Amiri", FontMapCompareFixture, "Amiri",
+ fontmap_compare_fixture_set_up,
+ test_hbfontmap_compare_faces,
+ fontmap_compare_fixture_tear_down);
+ g_test_add ("/hbfontmap/faces/Cantarell", FontMapCompareFixture, "Cantarell",
+ fontmap_compare_fixture_set_up,
+ test_hbfontmap_compare_faces,
+ fontmap_compare_fixture_tear_down);
+ g_test_add ("/hbfontmap/languages/Amiri", FontMapCompareFixture, "Amiri",
+ fontmap_compare_fixture_set_up,
+ test_hbfontmap_compare_languages,
+ fontmap_compare_fixture_tear_down);
+ g_test_add ("/hbfontmap/languages/Cantarell", FontMapCompareFixture, "Cantarell",
+ fontmap_compare_fixture_set_up,
+ test_hbfontmap_compare_languages,
+ fontmap_compare_fixture_tear_down);
+ g_test_add ("/hbfontmap/compare/match", FontMapCompareFixture, NULL,
+ fontmap_compare_fixture_set_up,
+ test_hbfontmap_compare_match,
+ fontmap_compare_fixture_tear_down);
return g_test_run ();
}