[pango/pango2: 37/115] Add a faceid field to font descriptions
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [pango/pango2: 37/115] Add a faceid field to font descriptions
- Date: Thu, 9 Jun 2022 11:24:42 +0000 (UTC)
commit 64022b51f1070c145d34511ad64c334880caf4aa
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Feb 17 17:24:09 2022 -0600
Add a faceid field to font descriptions
The faceid will be used in future commits
to improve font -> description -> font roundtrip
accuracy.
Update affected tests.
Minimal test included.
pango/pango-font-description.c | 182 +++++++++++++++++++++++++++++++++++++++--
pango/pango-font-description.h | 26 ++++--
tests/test-font.c | 72 +++++++++++++---
3 files changed, 253 insertions(+), 27 deletions(-)
---
diff --git a/pango/pango-font-description.c b/pango/pango-font-description.c
index c18882ef..89de07c9 100644
--- a/pango/pango-font-description.c
+++ b/pango/pango-font-description.c
@@ -36,14 +36,16 @@ struct _PangoFontDescription
PangoStretch stretch;
PangoGravity gravity;
+ int size;
+
char *variations;
+ char *faceid;
guint16 mask;
guint static_family : 1;
guint static_variations : 1;
+ guint static_faceid : 1;
guint size_is_absolute : 1;
-
- int size;
};
G_DEFINE_BOXED_TYPE (PangoFontDescription, pango_font_description,
@@ -58,14 +60,15 @@ static const PangoFontDescription pfd_defaults = {
PANGO_WEIGHT_NORMAL, /* weight */
PANGO_STRETCH_NORMAL, /* stretch */
PANGO_GRAVITY_SOUTH, /* gravity */
+ 0, /* size */
NULL, /* variations */
+ NULL, /* faceid */
0, /* mask */
0, /* static_family */
- 0, /* static_variations*/
+ 0, /* static_variations */
+ 0, /* static_faceid */
0, /* size_is_absolute */
-
- 0, /* size */
};
/**
@@ -662,6 +665,7 @@ pango_font_description_merge (PangoFontDescription *desc,
{
gboolean family_merged;
gboolean variations_merged;
+ gboolean faceid_merged;
g_return_if_fail (desc != NULL);
@@ -670,6 +674,7 @@ pango_font_description_merge (PangoFontDescription *desc,
family_merged = desc_to_merge->family_name && (replace_existing || !desc->family_name);
variations_merged = desc_to_merge->variations && (replace_existing || !desc->variations);
+ faceid_merged = desc_to_merge->faceid && (replace_existing || !desc->faceid);
pango_font_description_merge_static (desc, desc_to_merge, replace_existing);
@@ -684,6 +689,12 @@ pango_font_description_merge (PangoFontDescription *desc,
desc->variations = g_strdup (desc->variations);
desc->static_variations = FALSE;
}
+
+ if (faceid_merged)
+ {
+ desc->faceid = g_strdup (desc->faceid);
+ desc->static_faceid = FALSE;
+ }
}
/**
@@ -736,6 +747,8 @@ pango_font_description_merge_static (PangoFontDescription *desc,
desc->gravity = desc_to_merge->gravity;
if (new_mask & PANGO_FONT_MASK_VARIATIONS)
pango_font_description_set_variations_static (desc, desc_to_merge->variations);
+ if (new_mask & PANGO_FONT_MASK_FACEID)
+ pango_font_description_set_faceid_static (desc, desc_to_merge->faceid);
desc->mask |= new_mask;
}
@@ -839,6 +852,9 @@ pango_font_description_copy (const PangoFontDescription *desc)
result->variations = g_strdup (result->variations);
result->static_variations = FALSE;
+ result->faceid = g_strdup (result->faceid);
+ result->static_faceid = FALSE;
+
return result;
}
@@ -872,10 +888,12 @@ pango_font_description_copy_static (const PangoFontDescription *desc)
if (result->family_name)
result->static_family = TRUE;
-
if (result->variations)
result->static_variations = TRUE;
+ if (result->faceid)
+ result->static_faceid = TRUE;
+
return result;
}
@@ -910,7 +928,8 @@ pango_font_description_equal (const PangoFontDescription *desc1,
desc1->gravity == desc2->gravity &&
(desc1->family_name == desc2->family_name ||
(desc1->family_name && desc2->family_name && g_ascii_strcasecmp (desc1->family_name,
desc2->family_name) == 0)) &&
- (g_strcmp0 (desc1->variations, desc2->variations) == 0);
+ (g_strcmp0 (desc1->variations, desc2->variations) == 0) &&
+ (g_strcmp0 (desc1->faceid, desc2->faceid) == 0);
}
#define TOLOWER(c) \
@@ -953,6 +972,8 @@ pango_font_description_hash (const PangoFontDescription *desc)
hash = case_insensitive_hash (desc->family_name);
if (desc->variations)
hash ^= g_str_hash (desc->variations);
+ if (desc->faceid)
+ hash ^= g_str_hash (desc->faceid);
hash ^= desc->size;
hash ^= desc->size_is_absolute ? 0xc33ca55a : 0;
hash ^= desc->style << 16;
@@ -982,6 +1003,9 @@ pango_font_description_free (PangoFontDescription *desc)
if (desc->variations && !desc->static_variations)
g_free (desc->variations);
+ if (desc->faceid && !desc->static_faceid)
+ g_free (desc->faceid);
+
g_slice_free (PangoFontDescription, desc);
}
@@ -1229,6 +1253,40 @@ parse_variations (const char *word,
return TRUE;
}
+static void
+faceid_from_variations (PangoFontDescription *desc)
+{
+ const char *p, *q;
+
+ p = desc->variations;
+
+ if (g_str_has_prefix (p, "faceid="))
+ {
+ p += strlen ("faceid=");
+ q = strchr (p, ',');
+ if (q)
+ {
+ desc->faceid = g_strndup (p, q - p);
+ p = q + 1;
+ }
+ else
+ {
+ desc->faceid = g_strdup (p);
+ p = NULL;
+ }
+ desc->mask |= PANGO_FONT_MASK_FACEID;
+ }
+
+ if (p != desc->variations)
+ {
+ char *variations = g_strdup (p);
+ g_free (desc->variations);
+ desc->variations = variations;
+ if (variations == NULL || *variations == '\0')
+ desc->mask &= ~PANGO_FONT_MASK_VARIATIONS;
+ }
+}
+
/**
* pango_font_description_from_string:
* @str: string representation of a font description.
@@ -1306,6 +1364,8 @@ pango_font_description_from_string (const char *str)
{
desc->mask |= PANGO_FONT_MASK_VARIATIONS;
last = p;
+
+ faceid_from_variations (desc);
}
}
@@ -1416,6 +1476,7 @@ char *
pango_font_description_to_string (const PangoFontDescription *desc)
{
GString *result;
+ gboolean in_variations = FALSE;
g_return_val_if_fail (desc != NULL, NULL);
@@ -1473,10 +1534,20 @@ pango_font_description_to_string (const PangoFontDescription *desc)
g_string_append (result, "px");
}
+ if (desc->mask & PANGO_FONT_MASK_FACEID)
+ {
+ in_variations = TRUE;
+ g_string_append (result, " @");
+ g_string_append_printf (result, "faceid=%s", desc->faceid);
+ }
+
if ((desc->variations && desc->mask & PANGO_FONT_MASK_VARIATIONS) &&
desc->variations[0] != '\0')
{
- g_string_append (result, " @");
+ if (!in_variations)
+ g_string_append (result, " @");
+ else
+ g_string_append (result, ",");
g_string_append (result, desc->variations);
}
@@ -1667,3 +1738,98 @@ pango_parse_stretch (const char *str,
{
return FIELD (stretch, PANGO_FONT_MASK_STRETCH);
}
+
+/**
+ * pango_font_description_set_faceid_static:
+ * @desc: a `PangoFontDescription`
+ * @faceid: the faceid string
+ *
+ * Sets the faceid field of a font description.
+ *
+ * This is like [method@Pango.FontDescription.set_faceid], except
+ * that no copy of @faceid is made. The caller must make sure that
+ * the string passed in stays around until @desc has been freed
+ * or the name is set again. This function can be used if
+ * @faceid is a static string such as a C string literal,
+ * or if @desc is only needed temporarily.
+ *
+ * Since: 1.52
+ */
+void
+pango_font_description_set_faceid_static (PangoFontDescription *desc,
+ const char *faceid)
+{
+ g_return_if_fail (desc != NULL);
+
+ if (desc->faceid == faceid)
+ return;
+
+ if (desc->faceid && !desc->static_faceid)
+ g_free (desc->faceid);
+
+ if (faceid)
+ {
+ desc->faceid = (char *)faceid;
+ desc->static_faceid = TRUE;
+ desc->mask |= PANGO_FONT_MASK_FACEID;
+ }
+ else
+ {
+ desc->faceid = pfd_defaults.faceid;
+ desc->static_faceid = pfd_defaults.static_faceid;
+ desc->mask &= ~PANGO_FONT_MASK_FACEID;
+ }
+}
+
+/**
+ * pango_font_description_set_faceid:
+ * @desc: a `PangoFontDescription`.
+ * @faceid: (nullable): the faceid string
+ *
+ * Sets the faceid field of a font description.
+ *
+ * The faceid is mainly for internal use by Pango, to ensure
+ * that font -> description -> font roundtrips end up with
+ * the same font they started with, if possible.
+ *
+ * Font descriptions originating from [method@Pango.FontFace.describe]
+ * should ideally include a faceid. Pango takes the faceid
+ * into account when looking for the best matching face while
+ * loading a fontset or font.
+ *
+ * The format of this string is not guaranteed.
+ *
+ * Since: 1.52
+ */
+void
+pango_font_description_set_faceid (PangoFontDescription *desc,
+ const char *faceid)
+{
+ g_return_if_fail (desc != NULL);
+
+ pango_font_description_set_faceid_static (desc, g_strdup (faceid));
+ if (faceid)
+ desc->static_faceid = FALSE;
+}
+
+/**
+ * pango_font_description_get_faceid:
+ * @desc: a `PangoFontDescription`
+ *
+ * Gets the faceid field of a font description.
+ *
+ * See [method@Pango.FontDescription.set_faceid].
+ *
+ * Return value: (nullable): the faceid field for the font
+ * description, or %NULL if not previously set. This has the same
+ * life-time as the font description itself and should not be freed.
+ *
+ * Since: 1.52
+ */
+const char *
+pango_font_description_get_faceid (const PangoFontDescription *desc)
+{
+ g_return_val_if_fail (desc != NULL, NULL);
+
+ return desc->faceid;
+}
diff --git a/pango/pango-font-description.h b/pango/pango-font-description.h
index 31c5b4a4..21989e69 100644
--- a/pango/pango-font-description.h
+++ b/pango/pango-font-description.h
@@ -153,19 +153,21 @@ typedef enum {
* @PANGO_FONT_MASK_SIZE: the font size is specified.
* @PANGO_FONT_MASK_GRAVITY: the font gravity is specified (Since: 1.16.)
* @PANGO_FONT_MASK_VARIATIONS: OpenType font variations are specified (Since: 1.42)
+ * @PANGO_FONT_MASK_FACEID: the face ID is specified
*
* The bits in a `PangoFontMask` correspond to the set fields in a
* `PangoFontDescription`.
*/
typedef enum {
- PANGO_FONT_MASK_FAMILY = 1 << 0,
- PANGO_FONT_MASK_STYLE = 1 << 1,
- PANGO_FONT_MASK_VARIANT = 1 << 2,
- PANGO_FONT_MASK_WEIGHT = 1 << 3,
- PANGO_FONT_MASK_STRETCH = 1 << 4,
- PANGO_FONT_MASK_SIZE = 1 << 5,
- PANGO_FONT_MASK_GRAVITY = 1 << 6,
+ PANGO_FONT_MASK_FAMILY = 1 << 0,
+ PANGO_FONT_MASK_STYLE = 1 << 1,
+ PANGO_FONT_MASK_VARIANT = 1 << 2,
+ PANGO_FONT_MASK_WEIGHT = 1 << 3,
+ PANGO_FONT_MASK_STRETCH = 1 << 4,
+ PANGO_FONT_MASK_SIZE = 1 << 5,
+ PANGO_FONT_MASK_GRAVITY = 1 << 6,
PANGO_FONT_MASK_VARIATIONS = 1 << 7,
+ PANGO_FONT_MASK_FACEID = 1 << 8,
} PangoFontMask;
/* CSS scale factors (1.2 factor between each size) */
@@ -284,6 +286,15 @@ void pango_font_description_set_variations (PangoFontDescr
PANGO_AVAILABLE_IN_1_42
const char * pango_font_description_get_variations (const PangoFontDescription *desc)
G_GNUC_PURE;
+PANGO_AVAILABLE_IN_ALL
+void pango_font_description_set_faceid (PangoFontDescription *desc,
+ const char *faceid);
+PANGO_AVAILABLE_IN_ALL
+void pango_font_description_set_faceid_static (PangoFontDescription *desc,
+ const char *faceid);
+PANGO_AVAILABLE_IN_ALL
+const char * pango_font_description_get_faceid (const PangoFontDescription *desc)
G_GNUC_PURE;
+
PANGO_AVAILABLE_IN_ALL
PangoFontMask pango_font_description_get_set_fields (const PangoFontDescription *desc)
G_GNUC_PURE;
PANGO_AVAILABLE_IN_ALL
@@ -304,6 +315,7 @@ gboolean pango_font_description_better_match (const PangoFon
const PangoFontDescription *old_match,
const PangoFontDescription *new_match)
G_GNUC_PURE;
+
PANGO_AVAILABLE_IN_ALL
PangoFontDescription * pango_font_description_from_string (const char *str);
PANGO_AVAILABLE_IN_ALL
diff --git a/tests/test-font.c b/tests/test-font.c
index 4aa2fc58..0c28f0cb 100644
--- a/tests/test-font.c
+++ b/tests/test-font.c
@@ -90,30 +90,34 @@ test_variations (void)
gchar *str;
desc1 = pango_font_description_from_string ("Cantarell 14");
- g_assert (desc1 != NULL);
- g_assert ((pango_font_description_get_set_fields (desc1) & PANGO_FONT_MASK_VARIATIONS) == 0);
- g_assert (pango_font_description_get_variations (desc1) == NULL);
+ g_assert_nonnull (desc1);
+ g_assert_cmpint ((pango_font_description_get_set_fields (desc1) & PANGO_FONT_MASK_VARIATIONS), ==, 0);
+ g_assert_cmpstr (pango_font_description_get_family (desc1), ==, "Cantarell");
+ g_assert_cmpint (pango_font_description_get_size (desc1), ==, 14 * PANGO_SCALE);
+ g_assert_null (pango_font_description_get_variations (desc1));
str = pango_font_description_to_string (desc1);
g_assert_cmpstr (str, ==, "Cantarell 14");
g_free (str);
desc2 = pango_font_description_from_string ("Cantarell 14 @wght=100,wdth=235");
- g_assert (desc2 != NULL);
- g_assert ((pango_font_description_get_set_fields (desc2) & PANGO_FONT_MASK_VARIATIONS) != 0);
+ g_assert_nonnull (desc2);
+ g_assert_cmpint ((pango_font_description_get_set_fields (desc2) & PANGO_FONT_MASK_VARIATIONS), ==,
PANGO_FONT_MASK_VARIATIONS);
+ g_assert_cmpstr (pango_font_description_get_family (desc2), ==, "Cantarell");
+ g_assert_cmpint (pango_font_description_get_size (desc2), ==, 14 * PANGO_SCALE);
g_assert_cmpstr (pango_font_description_get_variations (desc2), ==, "wght=100,wdth=235");
str = pango_font_description_to_string (desc2);
g_assert_cmpstr (str, ==, "Cantarell 14 @wght=100,wdth=235");
g_free (str);
- g_assert (!pango_font_description_equal (desc1, desc2));
+ g_assert_false (pango_font_description_equal (desc1, desc2));
pango_font_description_set_variations (desc1, "wght=100,wdth=235");
- g_assert ((pango_font_description_get_set_fields (desc1) & PANGO_FONT_MASK_VARIATIONS) != 0);
+ g_assert_cmpint ((pango_font_description_get_set_fields (desc1) & PANGO_FONT_MASK_VARIATIONS), ==,
PANGO_FONT_MASK_VARIATIONS);
g_assert_cmpstr (pango_font_description_get_variations (desc1), ==, "wght=100,wdth=235");
- g_assert (pango_font_description_equal (desc1, desc2));
+ g_assert_true (pango_font_description_equal (desc1, desc2));
pango_font_description_free (desc1);
pango_font_description_free (desc2);
@@ -284,8 +288,8 @@ test_roundtrip_plain (void)
{
PangoFontMap *fontmap;
PangoContext *context;
- PangoFontDescription *desc, *desc2;
- PangoFont *font;
+ PangoFontDescription *desc, *desc2, *desc3;
+ PangoFont *font, *font2;
#ifdef HAVE_CARBON
desc = pango_font_description_from_string ("Helvetica 11");
@@ -300,9 +304,15 @@ test_roundtrip_plain (void)
font = pango_context_load_font (context, desc);
desc2 = pango_font_describe (font);
- g_assert_true (pango_font_description_equal (desc2, desc));
+ font2 = pango_context_load_font (context, desc2);
+ desc3 = pango_font_describe (font2);
+
+ g_assert_true (pango_font_description_equal (desc2, desc3));
+ //g_assert_true (font == font2);
pango_font_description_free (desc2);
+ g_object_unref (font2);
+ pango_font_description_free (desc3);
g_object_unref (font);
pango_font_description_free (desc);
g_object_unref (context);
@@ -339,6 +349,8 @@ test_roundtrip_small_caps (void)
g_assert_true (features[0].tag == HB_TAG ('s', 'm', 'c', 'p'));
g_assert_true (features[0].value == 1);
g_assert_true (pango_font_description_get_variant (desc2) == PANGO_VARIANT_SMALL_CAPS);
+ /* We need to unset faceid since desc doesn't have one */
+ pango_font_description_unset_fields (desc2, PANGO_FONT_MASK_FACEID);
g_assert_true (pango_font_description_equal (desc2, desc));
pango_font_description_free (desc2);
@@ -359,6 +371,7 @@ test_roundtrip_small_caps (void)
g_assert_true (features[1].tag == HB_TAG ('c', '2', 's', 'c'));
g_assert_true (features[1].value == 1);
g_assert_true (pango_font_description_get_variant (desc2) == PANGO_VARIANT_ALL_SMALL_CAPS);
+ pango_font_description_unset_fields (desc2, PANGO_FONT_MASK_FACEID);
g_assert_true (pango_font_description_equal (desc2, desc));
pango_font_description_free (desc2);
@@ -377,6 +390,7 @@ test_roundtrip_small_caps (void)
g_assert_true (features[0].tag == HB_TAG ('u', 'n', 'i', 'c'));
g_assert_true (features[0].value == 1);
g_assert_true (pango_font_description_get_variant (desc2) == PANGO_VARIANT_UNICASE);
+ pango_font_description_unset_fields (desc2, PANGO_FONT_MASK_FACEID);
g_assert_true (pango_font_description_equal (desc2, desc));
pango_font_description_free (desc2);
@@ -406,9 +420,10 @@ test_roundtrip_emoji (void)
/* We can't expect the family name to match, since we go in with
* a generic family
+ * And we need to unset faceid, since desc doesn't have one.
*/
pango_font_description_unset_fields (desc, PANGO_FONT_MASK_FAMILY);
- pango_font_description_unset_fields (desc2, PANGO_FONT_MASK_FAMILY);
+ pango_font_description_unset_fields (desc2, PANGO_FONT_MASK_FAMILY|PANGO_FONT_MASK_FACEID);
g_assert_true (pango_font_description_equal (desc2, desc));
pango_font_description_free (desc2);
@@ -555,6 +570,38 @@ test_match (void)
pango_font_description_free (desc2);
}
+static void
+test_faceid (void)
+{
+ const char *test = "Cantarell Bold Italic 32 @faceid=Cantarell-Regular:0:-1:0,wght=600";
+ PangoFontDescription *desc;
+ char *s;
+
+ desc = pango_font_description_from_string (test);
+ g_assert_cmpint (pango_font_description_get_set_fields (desc), ==, PANGO_FONT_MASK_FAMILY|
+ PANGO_FONT_MASK_STYLE|
+ PANGO_FONT_MASK_WEIGHT|
+ PANGO_FONT_MASK_VARIANT|
+ PANGO_FONT_MASK_STRETCH|
+ PANGO_FONT_MASK_SIZE|
+ PANGO_FONT_MASK_FACEID|
+ PANGO_FONT_MASK_VARIATIONS);
+ g_assert_cmpstr (pango_font_description_get_family (desc), ==, "Cantarell");
+ g_assert_cmpint (pango_font_description_get_size (desc), ==, 32 * PANGO_SCALE);
+ g_assert_cmpint (pango_font_description_get_style (desc), ==, PANGO_STYLE_ITALIC);
+ g_assert_cmpint (pango_font_description_get_variant (desc), ==, PANGO_VARIANT_NORMAL);
+ g_assert_cmpint (pango_font_description_get_weight (desc), ==, PANGO_WEIGHT_BOLD);
+ g_assert_cmpint (pango_font_description_get_stretch (desc), ==, PANGO_STRETCH_NORMAL);
+ g_assert_cmpstr (pango_font_description_get_faceid (desc), ==, "Cantarell-Regular:0:-1:0");
+ g_assert_cmpstr (pango_font_description_get_variations (desc), ==, "wght=600");
+
+ s = pango_font_description_to_string (desc);
+ g_assert_cmpstr (s, ==, test);
+ g_free (s);
+
+ pango_font_description_free (desc);
+}
+
int
main (int argc, char *argv[])
{
@@ -572,6 +619,7 @@ main (int argc, char *argv[])
g_test_add_func ("/pango/fontdescription/to-filename", test_to_filename);
g_test_add_func ("/pango/fontdescription/set-gravity", test_set_gravity);
g_test_add_func ("/pango/fontdescription/match", test_match);
+ g_test_add_func ("/pango/fontdescription/faceid", test_faceid);
g_test_add_func ("/pango/font/extents", test_extents);
g_test_add_func ("/pango/font/enumerate", test_enumerate);
g_test_add_func ("/pango/font/roundtrip/plain", test_roundtrip_plain);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]