summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2022-01-03 22:10:29 -0500
committerMatthias Clasen <mclasen@redhat.com>2022-01-28 09:03:03 -0500
commit23cf33a37efb324e633845353e584730e6ef385c (patch)
treec2020db1666eec6ac21481417aca92ebeecd3c43
parent41d718553a1358661e58ca7915b59f958e780600 (diff)
downloadpango-23cf33a37efb324e633845353e584730e6ef385c.tar.gz
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.
-rw-r--r--pango/fonts.c185
-rw-r--r--pango/pango-font.h11
-rw-r--r--tests/test-font.c76
3 files changed, 250 insertions, 22 deletions
diff --git a/pango/fonts.c b/pango/fonts.c
index 0f566a79..89607683 100644
--- a/pango/fonts.c
+++ b/pango/fonts.c
@@ -41,14 +41,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,
@@ -63,14 +65,16 @@ 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 */
};
/**
@@ -601,6 +605,101 @@ pango_font_description_get_variations (const PangoFontDescription *desc)
}
/**
+ * 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;
+}
+
+/**
* pango_font_description_get_set_fields:
* @desc: a `PangoFontDescription`
*
@@ -667,6 +766,7 @@ pango_font_description_merge (PangoFontDescription *desc,
{
gboolean family_merged;
gboolean variations_merged;
+ gboolean faceid_merged;
g_return_if_fail (desc != NULL);
@@ -675,6 +775,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);
@@ -689,6 +790,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;
+ }
}
/**
@@ -741,6 +848,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;
}
@@ -844,6 +953,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;
}
@@ -877,10 +989,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;
}
@@ -915,7 +1029,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) \
@@ -958,6 +1073,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;
@@ -987,6 +1104,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);
}
@@ -1256,6 +1376,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.
@@ -1333,6 +1487,8 @@ pango_font_description_from_string (const char *str)
{
desc->mask |= PANGO_FONT_MASK_VARIATIONS;
last = p;
+
+ faceid_from_variations (desc);
}
}
@@ -1421,7 +1577,7 @@ append_field (GString *str, const char *what, const FieldMap *map, int n_element
return;
}
- if (G_LIKELY (str->len > 0 || str->str[str->len -1] != ' '))
+ if (G_LIKELY (str->len > 0 && str->str[str->len - 1] != ' '))
g_string_append_c (str, ' ');
g_string_append_printf (str, "%s=%d", what, val);
}
@@ -1443,6 +1599,7 @@ char *
pango_font_description_to_string (const PangoFontDescription *desc)
{
GString *result;
+ gboolean in_variations = FALSE;
g_return_val_if_fail (desc != NULL, NULL);
@@ -1500,10 +1657,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);
}
diff --git a/pango/pango-font.h b/pango/pango-font.h
index 1ba02b06..f4824c80 100644
--- a/pango/pango-font.h
+++ b/pango/pango-font.h
@@ -179,6 +179,7 @@ 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 (Since: 1.52)
*
* The bits in a `PangoFontMask` correspond to the set fields in a
* `PangoFontDescription`.
@@ -192,6 +193,7 @@ typedef enum {
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) */
@@ -316,6 +318,15 @@ void pango_font_description_set_variations (PangoFontDescript
PANGO_AVAILABLE_IN_1_42
const char *pango_font_description_get_variations (const PangoFontDescription *desc) G_GNUC_PURE;
+PANGO_AVAILABLE_IN_1_52
+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_1_52
+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
diff --git a/tests/test-font.c b/tests/test-font.c
index 8dd540f4..8a8230fd 100644
--- a/tests/test-font.c
+++ b/tests/test-font.c
@@ -89,30 +89,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);
@@ -280,8 +284,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");
@@ -296,9 +300,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);
@@ -335,6 +345,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);
@@ -355,6 +367,8 @@ 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);
@@ -373,6 +387,8 @@ 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);
@@ -401,10 +417,11 @@ test_roundtrip_emoji (void)
desc2 = pango_font_describe (font);
/* We can't expect the family name to match, since we go in with
- * a generic family
+ * 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);
@@ -600,6 +617,38 @@ test_font_languages (void)
g_object_unref (context);
}
+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[])
{
@@ -617,6 +666,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);