summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2018-01-03 14:10:44 +0000
committerBehdad Esfahbod <behdad@behdad.org>2018-01-03 14:10:44 +0000
commitb97089825723294cb6d4cc75c6e100c195b84369 (patch)
treeab18fc6ce18af185e3ce1878649b940f695ae0cb
parent4a90fcce32238c3122003355b44b692a629427e2 (diff)
parentcb84dd0d9c65725247304263a28b1876a4eeafe8 (diff)
downloadpango-b97089825723294cb6d4cc75c6e100c195b84369.tar.gz
Merge branch 'font-variations'
-rw-r--r--docs/pango-sections.txt3
-rw-r--r--pango-view/test-font-variations.markup9
-rw-r--r--pango/fonts.c172
-rw-r--r--pango/pango-font.h13
-rw-r--r--pango/pangocairo-fcfont.c8
-rw-r--r--pango/pangofc-fontmap.c48
-rw-r--r--pango/pangofc-fontmap.h13
-rw-r--r--pango/pangofc-shape.c45
-rw-r--r--tests/markup-parse.c68
-rw-r--r--tests/markups/valid-1.expected8
-rw-r--r--tests/markups/valid-10.expected24
-rw-r--r--tests/markups/valid-10.markup11
-rw-r--r--tests/markups/valid-11.expected50
-rw-r--r--tests/markups/valid-11.markup11
-rw-r--r--tests/markups/valid-2.expected8
-rw-r--r--tests/markups/valid-3.expected6
-rw-r--r--tests/markups/valid-4.expected18
-rw-r--r--tests/markups/valid-5.expected12
-rw-r--r--tests/markups/valid-6.expected12
-rw-r--r--tests/markups/valid-7.expected8
-rw-r--r--tests/markups/valid-8.expected12
-rw-r--r--tests/markups/valid-9.expected6
-rw-r--r--tests/test-font.c38
23 files changed, 584 insertions, 19 deletions
diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt
index 3573fb61..42e2581b 100644
--- a/docs/pango-sections.txt
+++ b/docs/pango-sections.txt
@@ -199,6 +199,9 @@ pango_font_description_set_absolute_size
pango_font_description_get_size_is_absolute
pango_font_description_set_gravity
pango_font_description_get_gravity
+pango_font_description_set_variations
+pango_font_description_set_variations_static
+pango_font_description_get_variations
pango_font_description_get_set_fields
pango_font_description_unset_fields
pango_font_description_merge
diff --git a/pango-view/test-font-variations.markup b/pango-view/test-font-variations.markup
new file mode 100644
index 00000000..ae277e35
--- /dev/null
+++ b/pango-view/test-font-variations.markup
@@ -0,0 +1,9 @@
+Rendering Text using weight variations.
+This works with fonts that have OpenType
+font variations.
+<span font_desc="@wght=700">Weight: 700</span>
+<span font_desc="@wght=600">Weight: 600</span>
+<span font_desc="@wght=300">Weight: 300</span>
+<span font_desc="@wght=500">Weight: 500</span>
+<span font_desc="@wght=400">Weight: 400</span>
+<span font_desc="@wght=2000">Weight: 2000</span>
diff --git a/pango/fonts.c b/pango/fonts.c
index 49e035b8..d9a07c0b 100644
--- a/pango/fonts.c
+++ b/pango/fonts.c
@@ -52,8 +52,11 @@ struct _PangoFontDescription
PangoStretch stretch;
PangoGravity gravity;
+ char *variations;
+
guint16 mask;
guint static_family : 1;
+ guint static_variations : 1;
guint size_is_absolute : 1;
int size;
@@ -71,10 +74,12 @@ static const PangoFontDescription pfd_defaults = {
PANGO_WEIGHT_NORMAL, /* weight */
PANGO_STRETCH_NORMAL, /* stretch */
PANGO_GRAVITY_SOUTH, /* gravity */
+ NULL, /* variations */
0, /* mask */
0, /* static_family */
- FALSE, /* size_is_absolute */
+ 0, /* static_variations*/
+ 0, /* size_is_absolute */
0, /* size */
};
@@ -480,6 +485,98 @@ pango_font_description_get_gravity (const PangoFontDescription *desc)
}
/**
+ * pango_font_description_set_variations_static:
+ * @desc: a #PangoFontDescription
+ * @variations: a string representing the variations
+ *
+ * Like pango_font_description_set_variations(), except that no
+ * copy of @variations 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
+ * @variations is a static string such as a C string literal, or
+ * if @desc is only needed temporarily.
+ *
+ * Since: 1.42
+ **/
+void
+pango_font_description_set_variations_static (PangoFontDescription *desc,
+ const char *variations)
+{
+ g_return_if_fail (desc != NULL);
+
+ if (desc->variations == variations)
+ return;
+
+ if (desc->variations && !desc->static_variations)
+ g_free (desc->variations);
+
+ if (variations)
+ {
+ desc->variations = (char *)variations;
+ desc->static_variations = TRUE;
+ desc->mask |= PANGO_FONT_MASK_VARIATIONS;
+ }
+ else
+ {
+ desc->variations = pfd_defaults.variations;
+ desc->static_variations = pfd_defaults.static_variations;
+ desc->mask &= ~PANGO_FONT_MASK_VARIATIONS;
+ }
+}
+
+/**
+ * pango_font_description_set_variations:
+ * @desc: a #PangoFontDescription.
+ * @variations: a string representing the variations
+ *
+ * Sets the variations field of a font description. OpenType
+ * font variations allow to select a font instance by specifying
+ * values for a number of axes, such as width or weight.
+ *
+ * The format of the variations string is AXIS1=VALUE,AXIS2=VALUE...,
+ * with each AXIS a 4 character tag that identifies a font axis,
+ * and each VALUE a floating point number. Unknown axes are ignored,
+ * and values are clamped to their allowed range.
+ *
+ * Pango does not currently have a way to find supported axes of
+ * a font. Both harfbuzz or freetype have API for this.
+ *
+ * Since: 1.42
+ **/
+void
+pango_font_description_set_variations (PangoFontDescription *desc,
+ const char *variations)
+{
+ g_return_if_fail (desc != NULL);
+
+ pango_font_description_set_variations_static (desc, g_strdup (variations));
+ if (variations)
+ desc->static_variations = FALSE;
+}
+
+/**
+ * pango_font_description_get_variations:
+ * @desc: a #PangoFontDescription
+ *
+ * Gets the variations field of a font description. See
+ * pango_font_description_set_variations().
+ *
+ * Return value: (nullable): the varitions 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.42
+ **/
+const char *
+pango_font_description_get_variations (const PangoFontDescription *desc)
+{
+ g_return_val_if_fail (desc != NULL, NULL);
+
+ return desc->variations;
+}
+
+/**
* pango_font_description_get_set_fields:
* @desc: a #PangoFontDescription
*
@@ -541,6 +638,7 @@ pango_font_description_merge (PangoFontDescription *desc,
gboolean replace_existing)
{
gboolean family_merged;
+ gboolean variations_merged;
g_return_if_fail (desc != NULL);
@@ -548,6 +646,7 @@ pango_font_description_merge (PangoFontDescription *desc,
return;
family_merged = desc_to_merge->family_name && (replace_existing || !desc->family_name);
+ variations_merged = desc_to_merge->variations && (replace_existing || !desc->variations);
pango_font_description_merge_static (desc, desc_to_merge, replace_existing);
@@ -556,6 +655,12 @@ pango_font_description_merge (PangoFontDescription *desc,
desc->family_name = g_strdup (desc->family_name);
desc->static_family = FALSE;
}
+
+ if (variations_merged)
+ {
+ desc->variations = g_strdup (desc->variations);
+ desc->static_variations = FALSE;
+ }
}
/**
@@ -603,6 +708,8 @@ pango_font_description_merge_static (PangoFontDescription *desc,
}
if (new_mask & PANGO_FONT_MASK_GRAVITY)
desc->gravity = desc_to_merge->gravity;
+ if (new_mask & PANGO_FONT_MASK_VARIATIONS)
+ pango_font_description_set_variations_static (desc, desc_to_merge->variations);
desc->mask |= new_mask;
}
@@ -697,6 +804,9 @@ pango_font_description_copy (const PangoFontDescription *desc)
result->static_family = FALSE;
}
+ result->variations = g_strdup (result->variations);
+ result->static_variations = FALSE;
+
return result;
}
@@ -728,6 +838,10 @@ pango_font_description_copy_static (const PangoFontDescription *desc)
if (result->family_name)
result->static_family = TRUE;
+
+ if (result->variations)
+ result->static_variations = TRUE;
+
return result;
}
@@ -760,7 +874,8 @@ pango_font_description_equal (const PangoFontDescription *desc1,
desc1->size_is_absolute == desc2->size_is_absolute &&
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));
+ (desc1->family_name && desc2->family_name && g_ascii_strcasecmp (desc1->family_name, desc2->family_name) == 0)) &&
+ (g_strcmp0 (desc1->variations, desc2->variations) == 0);
}
#define TOLOWER(c) \
@@ -800,6 +915,8 @@ pango_font_description_hash (const PangoFontDescription *desc)
if (desc->family_name)
hash = case_insensitive_hash (desc->family_name);
+ if (desc->variations)
+ hash ^= g_str_hash (desc->variations);
hash ^= desc->size;
hash ^= desc->size_is_absolute ? 0xc33ca55a : 0;
hash ^= desc->style << 16;
@@ -826,6 +943,9 @@ pango_font_description_free (PangoFontDescription *desc)
if (desc->family_name && !desc->static_family)
g_free (desc->family_name);
+ if (desc->variations && !desc->static_variations)
+ g_free (desc->variations);
+
g_slice_free (PangoFontDescription, desc);
}
@@ -1031,7 +1151,7 @@ find_field_any (const char *str, int len, PangoFontDescription *desc)
}
static const char *
-getword (const char *str, const char *last, size_t *wordlen)
+getword (const char *str, const char *last, size_t *wordlen, const char *stop)
{
const char *result;
@@ -1039,7 +1159,7 @@ getword (const char *str, const char *last, size_t *wordlen)
last--;
result = last;
- while (result > str && !g_ascii_isspace (*(result - 1)) && *(result - 1) != ',')
+ while (result > str && !g_ascii_isspace (*(result - 1)) && !strchr (stop, *(result - 1)))
result--;
*wordlen = last - result;
@@ -1073,6 +1193,23 @@ parse_size (const char *word,
return FALSE;
}
+static gboolean
+parse_variations (const char *word,
+ size_t wordlen,
+ char **variations)
+{
+ if (word[0] != '@')
+ {
+ *variations = NULL;
+ return FALSE;
+ }
+
+ /* XXX: actually validate here */
+ *variations = g_strndup (word + 1, wordlen - 1);
+
+ return TRUE;
+}
+
/**
* pango_font_description_from_string:
* @str: string representation of a font description.
@@ -1110,10 +1247,19 @@ pango_font_description_from_string (const char *str)
len = strlen (str);
last = str + len;
- p = getword (str, last, &wordlen);
+ p = getword (str, last, &wordlen, "");
+ /* Look for variations at the end of the string */
+ if (wordlen != 0)
+ {
+ if (parse_variations (p, wordlen, &desc->variations))
+ {
+ desc->mask |= PANGO_FONT_MASK_VARIATIONS;
+ last = p;
+ }
+ }
- /* Look for a size at the end of the string
- */
+ p = getword (str, last, &wordlen, ",");
+ /* Look for a size */
if (wordlen != 0)
{
gboolean size_is_absolute;
@@ -1127,7 +1273,7 @@ pango_font_description_from_string (const char *str)
/* Now parse style words
*/
- p = getword (str, last, &wordlen);
+ p = getword (str, last, &wordlen, ",");
while (wordlen != 0)
{
if (!find_field_any (p, wordlen, desc))
@@ -1135,7 +1281,7 @@ pango_font_description_from_string (const char *str)
else
{
last = p;
- p = getword (str, last, &wordlen);
+ p = getword (str, last, &wordlen, ",");
}
}
@@ -1234,7 +1380,7 @@ pango_font_description_to_string (const PangoFontDescription *desc)
* in a keyword like "Bold", or if the family name ends in
* a number and no keywords will be added.
*/
- p = getword (desc->family_name, desc->family_name + strlen(desc->family_name), &wordlen);
+ p = getword (desc->family_name, desc->family_name + strlen(desc->family_name), &wordlen, ",");
if (wordlen != 0 &&
(find_field_any (p, wordlen, NULL) ||
(parse_size (p, wordlen, NULL, NULL) &&
@@ -1275,6 +1421,12 @@ pango_font_description_to_string (const PangoFontDescription *desc)
g_string_append (result, "px");
}
+ if (desc->variations && desc->mask & PANGO_FONT_MASK_VARIATIONS)
+ {
+ g_string_append (result, " @");
+ g_string_append (result, desc->variations);
+ }
+
return g_string_free (result, FALSE);
}
diff --git a/pango/pango-font.h b/pango/pango-font.h
index a9702954..4af31a95 100644
--- a/pango/pango-font.h
+++ b/pango/pango-font.h
@@ -145,6 +145,7 @@ typedef enum {
* @PANGO_FONT_MASK_STRETCH: the font stretch is specified.
* @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)
*
* The bits in a #PangoFontMask correspond to fields in a
* #PangoFontDescription that have been set.
@@ -156,7 +157,8 @@ typedef enum {
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_GRAVITY = 1 << 6,
+ PANGO_FONT_MASK_VARIATIONS = 1 << 7,
} PangoFontMask;
/* CSS scale factors (1.2 factor between each size) */
@@ -277,6 +279,15 @@ void pango_font_description_set_gravity (PangoFontDescript
PANGO_AVAILABLE_IN_1_16
PangoGravity pango_font_description_get_gravity (const PangoFontDescription *desc) G_GNUC_PURE;
+PANGO_AVAILABLE_IN_1_42
+void pango_font_description_set_variations_static (PangoFontDescription *desc,
+ const char *settings);
+PANGO_AVAILABLE_IN_1_42
+void pango_font_description_set_variations (PangoFontDescription *desc,
+ const char *settings);
+PANGO_AVAILABLE_IN_1_42
+const char *pango_font_description_get_variations (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/pango/pangocairo-fcfont.c b/pango/pangocairo-fcfont.c
index 30ecde4d..e153c13e 100644
--- a/pango/pangocairo-fcfont.c
+++ b/pango/pangocairo-fcfont.c
@@ -33,6 +33,9 @@
#include "pangofc-private.h"
#include "pango-impl-utils.h"
+#include <hb-ot.h>
+#include <freetype/ftmm.h>
+
#define PANGO_TYPE_CAIRO_FC_FONT (pango_cairo_fc_font_get_type ())
#define PANGO_CAIRO_FC_FONT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), PANGO_TYPE_CAIRO_FC_FONT, PangoCairoFcFont))
#define PANGO_CAIRO_FC_FONT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_CAIRO_FC_FONT, PangoCairoFcFontClass))
@@ -222,6 +225,7 @@ _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap,
FcMatrix fc_matrix, *fc_matrix_val;
double size;
int i;
+ cairo_font_options_t *options;
g_return_val_if_fail (PANGO_IS_CAIRO_FC_FONT_MAP (cffontmap), NULL);
g_return_val_if_fail (pattern != NULL, NULL);
@@ -247,10 +251,12 @@ _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap,
cairo_matrix_scale (&font_matrix, size, size);
+ options = pango_fc_font_key_get_context_key (key);
+
_pango_cairo_font_private_initialize (&cffont->cf_priv,
(PangoCairoFont *) cffont,
get_gravity (pattern),
- pango_fc_font_key_get_context_key (key),
+ options,
pango_fc_font_key_get_matrix (key),
&font_matrix);
diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
index 70e9ee7e..4e7d74bb 100644
--- a/pango/pangofc-fontmap.c
+++ b/pango/pangofc-fontmap.c
@@ -357,6 +357,7 @@ struct _PangoFcFontsetKey {
int pixelsize;
double resolution;
gpointer context_key;
+ char *variations;
};
struct _PangoFcFontKey {
@@ -364,6 +365,7 @@ struct _PangoFcFontKey {
FcPattern *pattern;
PangoMatrix matrix;
gpointer context_key;
+ char *variations;
};
static void
@@ -381,8 +383,9 @@ pango_fc_fontset_key_init (PangoFcFontsetKey *key,
key->pixelsize = get_scaled_size (fcfontmap, context, desc);
key->resolution = pango_fc_font_map_get_resolution (fcfontmap, context);
key->language = language;
+ key->variations = g_strdup (pango_font_description_get_variations (desc));
key->desc = pango_font_description_copy_static (desc);
- pango_font_description_unset_fields (key->desc, PANGO_FONT_MASK_SIZE);
+ pango_font_description_unset_fields (key->desc, PANGO_FONT_MASK_SIZE | PANGO_FONT_MASK_VARIATIONS);
if (context && PANGO_FC_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get)
key->context_key = (gpointer)PANGO_FC_FONT_MAP_GET_CLASS (fcfontmap)->context_key_get (fcfontmap, context);
@@ -397,6 +400,8 @@ pango_fc_fontset_key_equal (const PangoFcFontsetKey *key_a,
if (key_a->language == key_b->language &&
key_a->pixelsize == key_b->pixelsize &&
key_a->resolution == key_b->resolution &&
+ ((key_a->variations == NULL && key_b->variations == NULL) ||
+ (key_a->variations && key_b->variations && (strcmp (key_a->variations, key_b->variations) == 0))) &&
pango_font_description_equal (key_a->desc, key_b->desc) &&
0 == memcmp (&key_a->matrix, &key_b->matrix, 4 * sizeof (double)))
{
@@ -422,6 +427,9 @@ pango_fc_fontset_key_hash (const PangoFcFontsetKey *key)
hash ^= key->pixelsize;
+ if (key->variations)
+ hash ^= g_str_hash (key->variations);
+
if (key->context_key)
hash ^= PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
key->context_key);
@@ -435,6 +443,7 @@ static void
pango_fc_fontset_key_free (PangoFcFontsetKey *key)
{
pango_font_description_free (key->desc);
+ g_free (key->variations);
if (key->context_key)
PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
@@ -454,6 +463,8 @@ pango_fc_fontset_key_copy (const PangoFcFontsetKey *old)
key->matrix = old->matrix;
key->pixelsize = old->pixelsize;
key->resolution = old->resolution;
+ key->variations = g_strdup (old->variations);
+
if (old->context_key)
key->context_key = PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap,
old->context_key);
@@ -569,6 +580,8 @@ pango_fc_font_key_equal (const PangoFcFontKey *key_a,
const PangoFcFontKey *key_b)
{
if (key_a->pattern == key_b->pattern &&
+ ((key_a->variations == NULL && key_b->variations == NULL) ||
+ (key_a->variations && key_b->variations && (strcmp (key_a->variations, key_b->variations) == 0))) &&
0 == memcmp (&key_a->matrix, &key_b->matrix, 4 * sizeof (double)))
{
if (key_a->context_key && key_b->context_key)
@@ -590,6 +603,9 @@ pango_fc_font_key_hash (const PangoFcFontKey *key)
/* We do a bytewise hash on the doubles */
hash = hash_bytes_fnv ((unsigned char *)(&key->matrix), sizeof (double) * 4, hash);
+ if (key->variations)
+ hash ^= g_str_hash (key->variations);
+
if (key->context_key)
hash ^= PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_hash (key->fontmap,
key->context_key);
@@ -607,6 +623,8 @@ pango_fc_font_key_free (PangoFcFontKey *key)
PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_free (key->fontmap,
key->context_key);
+ g_free (key->variations);
+
g_slice_free (PangoFcFontKey, key);
}
@@ -619,6 +637,7 @@ pango_fc_font_key_copy (const PangoFcFontKey *old)
FcPatternReference (old->pattern);
key->pattern = old->pattern;
key->matrix = old->matrix;
+ key->variations = g_strdup (old->variations);
if (old->context_key)
key->context_key = PANGO_FC_FONT_MAP_GET_CLASS (key->fontmap)->context_key_copy (key->fontmap,
old->context_key);
@@ -637,6 +656,7 @@ pango_fc_font_key_init (PangoFcFontKey *key,
key->fontmap = fcfontmap;
key->pattern = pattern;
key->matrix = *pango_fc_fontset_key_get_matrix (fontset_key);
+ key->variations = g_strdup (fontset_key->variations);
key->context_key = pango_fc_fontset_key_get_context_key (fontset_key);
}
@@ -690,6 +710,11 @@ pango_fc_font_key_get_context_key (const PangoFcFontKey *key)
return key->context_key;
}
+const char *
+pango_fc_font_key_get_variations (const PangoFcFontKey *key)
+{
+ return key->variations;
+}
/*
* PangoFcPatterns
@@ -1445,7 +1470,8 @@ static FcPattern *
pango_fc_make_pattern (const PangoFontDescription *description,
PangoLanguage *language,
int pixel_size,
- double dpi)
+ double dpi,
+ const char *variations)
{
FcPattern *pattern;
const char *prgname;
@@ -1487,11 +1513,17 @@ pango_fc_make_pattern (const PangoFontDescription *description,
#ifdef FC_VERTICAL_LAYOUT
FC_VERTICAL_LAYOUT, FcTypeBool, vertical,
#endif
+#ifdef FC_VARIABLE
+ FC_VARIABLE, FcTypeBool, FcDontCare,
+#endif
FC_DPI, FcTypeDouble, dpi,
FC_SIZE, FcTypeDouble, pixel_size * (72. / 1024. / dpi),
FC_PIXEL_SIZE, FcTypeDouble, pixel_size / 1024.,
NULL);
+ if (variations)
+ FcPatternAddString (pattern, PANGO_FC_FONT_VARIATIONS, (FcChar8*) variations);
+
if (pango_font_description_get_family (description))
{
families = g_strsplit (pango_font_description_get_family (description), ",", -1);
@@ -1655,7 +1687,8 @@ pango_fc_fontset_key_make_pattern (PangoFcFontsetKey *key)
return pango_fc_make_pattern (key->desc,
key->language,
key->pixelsize,
- key->resolution);
+ key->resolution,
+ key->variations);
}
static PangoFcPatterns *
@@ -1739,12 +1772,14 @@ pango_fc_fontset_cache (PangoFcFontset *fontset,
{
/* Add to cache initially
*/
+#if 1
if (cache->length == FONTSET_CACHE_SIZE)
{
PangoFcFontset *tmp_fontset = g_queue_pop_tail (cache);
tmp_fontset->cache_link = NULL;
g_hash_table_remove (priv->fontset_hash, tmp_fontset->key);
}
+#endif
fontset->cache_link = g_list_prepend (NULL, fontset);
}
@@ -1783,6 +1818,7 @@ pango_fc_font_map_load_fontset (PangoFontMap *fontmap,
pango_fc_fontset_cache (fontset, fcfontmap);
pango_font_description_free (key.desc);
+ g_free (key.variations);
return g_object_ref (fontset);
}
@@ -2287,6 +2323,12 @@ pango_fc_font_description_from_pattern (FcPattern *pattern, gboolean include_siz
pango_font_description_set_gravity (desc, gravity);
}
+ if (include_size && FcPatternGetString (pattern, PANGO_FC_FONT_VARIATIONS, 0, (FcChar8 **)&s) == FcResultMatch)
+ {
+ if (s && *s)
+ pango_font_description_set_variations (desc, (char *)s);
+ }
+
return desc;
}
diff --git a/pango/pangofc-fontmap.h b/pango/pangofc-fontmap.h
index 4dab0839..bff288b6 100644
--- a/pango/pangofc-fontmap.h
+++ b/pango/pangofc-fontmap.h
@@ -71,6 +71,8 @@ PANGO_AVAILABLE_IN_1_24
const PangoMatrix *pango_fc_font_key_get_matrix (const PangoFcFontKey *key);
PANGO_AVAILABLE_IN_1_24
gpointer pango_fc_font_key_get_context_key (const PangoFcFontKey *key);
+PANGO_AVAILABLE_IN_1_40
+const char *pango_fc_font_key_get_variations (const PangoFcFontKey *key);
#endif
@@ -311,6 +313,17 @@ PangoFontDescription *pango_fc_font_description_from_pattern (FcPattern *pattern
*/
#define PANGO_FC_FONT_FEATURES "fontfeatures"
+/**
+ * PANGO_FC_FONT_VARIATIONS:
+ *
+ * String representing a fontconfig property name that Pango reads from font
+ * patterns to populate list of OpenType font variations to be used for a font.
+ *
+ * The property will have a string elements, each of which a comma-separated
+ * list of OpenType axis setting of the form AXIS=VALUE.
+ */
+#define PANGO_FC_FONT_VARIATIONS "fontvariations"
+
G_END_DECLS
#endif /* __PANGO_FC_FONT_MAP_H__ */
diff --git a/pango/pangofc-shape.c b/pango/pangofc-shape.c
index 57f70000..a59ca67c 100644
--- a/pango/pangofc-shape.c
+++ b/pango/pangofc-shape.c
@@ -278,6 +278,38 @@ pango_fc_get_hb_font_funcs (void)
return funcs;
}
+static void
+parse_variations (const char *variations,
+ hb_variation_t **hb_variations,
+ guint *n_variations)
+{
+ guint n;
+ hb_variation_t *var;
+ int i;
+ const char *p;
+
+ n = 1;
+ for (i = 0; variations[i]; i++)
+ {
+ if (variations[i] == ',')
+ n++;
+ }
+
+ var = g_new (hb_variation_t, n);
+
+ p = variations;
+ n = 0;
+ while (p && *p)
+ {
+ char *end = strchr (p, ',');
+ if (hb_variation_from_string (p, end ? end - p: -1, &var[n]))
+ n++;
+ p = end ? end + 1 : NULL;
+ }
+
+ *hb_variations = var;
+ *n_variations = n;
+}
void
_pango_fc_shape (PangoFont *font,
@@ -306,6 +338,7 @@ _pango_fc_shape (PangoFont *font,
unsigned int num_features = 0;
double x_scale_inv, y_scale_inv;
PangoGlyphInfo *infos;
+ const char *variations;
g_return_if_fail (font != NULL);
g_return_if_fail (analysis != NULL);
@@ -347,6 +380,18 @@ _pango_fc_shape (PangoFont *font,
fc_font->is_hinted ? ft_face->size->metrics.x_ppem : 0,
fc_font->is_hinted ? ft_face->size->metrics.y_ppem : 0);
+ variations = pango_fc_font_key_get_variations (key);
+ if (variations)
+ {
+ guint n_variations;
+ hb_variation_t *hb_variations;
+
+ parse_variations (variations, &hb_variations, &n_variations);
+ hb_font_set_variations (hb_font, hb_variations, n_variations);
+
+ g_free (hb_variations);
+ }
+
hb_buffer = acquire_buffer (&free_buffer);
hb_direction = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity) ? HB_DIRECTION_TTB : HB_DIRECTION_LTR;
diff --git a/tests/markup-parse.c b/tests/markup-parse.c
index 60288d8f..e82c6db5 100644
--- a/tests/markup-parse.c
+++ b/tests/markup-parse.c
@@ -21,6 +21,7 @@
#include <glib.h>
#include <string.h>
+#include <unistd.h>
#include <locale.h>
#include <pango/pangocairo.h>
@@ -144,7 +145,12 @@ test_file (const gchar *filename, GString *string)
GError *error = NULL;
gchar *text;
PangoAttrList *attrs;
+ PangoAttrIterator *iter;
+ PangoFontDescription *desc;
+ PangoLanguage *lang;
gboolean ret;
+ char *str;
+ int start, end;
if (!g_file_get_contents (filename, &contents, &length, &error))
{
@@ -162,7 +168,19 @@ test_file (const gchar *filename, GString *string)
g_string_append (string, text);
g_string_append (string, "\n\n---\n\n");
attr_list_dump (attrs, string);
+ g_string_append (string, "\n\n---\n\n");
+ desc = pango_font_description_new ();
+ iter = pango_attr_list_get_iterator (attrs);
+ do {
+ pango_attr_iterator_range (iter, &start, &end);
+ pango_attr_iterator_get_font (iter, desc, &lang, NULL);
+ str = pango_font_description_to_string (desc);
+ g_string_append_printf (string, "[%d:%d] %s %s\n", start, end, (char *)lang, str);
+ g_free (str);
+ } while (pango_attr_iterator_next (iter));
+ pango_attr_iterator_destroy (iter);
pango_attr_list_unref (attrs);
+ pango_font_description_free (desc);
g_free (text);
}
else
@@ -188,14 +206,51 @@ get_expected_filename (const gchar *filename)
return expected;
}
+static char *
+diff_with_file (const char *file1,
+ GString *string,
+ GError **error)
+{
+ const char *command[] = { "diff", "-u", file1, NULL, NULL };
+ char *diff, *tmpfile;
+ int fd;
+
+ diff = NULL;
+
+ /* write the text buffer to a temporary file */
+ fd = g_file_open_tmp (NULL, &tmpfile, error);
+ if (fd < 0)
+ return NULL;
+
+ if (write (fd, string->str, string->len) != (int) string->len)
+ {
+ close (fd);
+ g_set_error (error,
+ G_FILE_ERROR, G_FILE_ERROR_FAILED,
+ "Could not write data to temporary file '%s'", tmpfile);
+ goto done;
+ }
+ close (fd);
+ command[3] = tmpfile;
+
+ /* run diff command */
+ g_spawn_sync (NULL, (char **)command, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &diff, NULL, NULL, error);
+
+done:
+ unlink (tmpfile);
+ g_free (tmpfile);
+
+ return diff;
+}
+
static void
test_parse (gconstpointer d)
{
const gchar *filename = d;
gchar *expected_file;
- gchar *expected;
GError *error = NULL;
GString *string;
+ char *diff;
expected_file = get_expected_filename (filename);
@@ -203,10 +258,15 @@ test_parse (gconstpointer d)
test_file (filename, string);
- g_file_get_contents (expected_file, &expected, NULL, &error);
+ diff = diff_with_file (expected_file, string, &error);
g_assert_no_error (error);
- g_assert_cmpstr (string->str, ==, expected);
- g_free (expected);
+
+ if (diff && diff[0])
+ {
+ g_test_message ("Resulting output doesn't match reference:\n%s", diff);
+ g_test_fail ();
+ }
+ g_free (diff);
g_string_free (string, TRUE);
diff --git a/tests/markups/valid-1.expected b/tests/markups/valid-1.expected
index acd5f1b6..09546763 100644
--- a/tests/markups/valid-1.expected
+++ b/tests/markups/valid-1.expected
@@ -10,3 +10,11 @@ range 9 13
range 13 17
[13 17] style 2
range 17 2147483647
+
+
+---
+
+[0:9] (null) Normal 0
+[9:13] (null) Normal 0
+[13:17] (null) Italic 0
+[17:2147483647] (null) Italic 0
diff --git a/tests/markups/valid-10.expected b/tests/markups/valid-10.expected
new file mode 100644
index 00000000..1479696c
--- /dev/null
+++ b/tests/markups/valid-10.expected
@@ -0,0 +1,24 @@
+Lots of attrs
+
+
+---
+
+range 0 13
+[0 13] font Sans Italic 12 @wdth=100,wght=200
+[0 13] foreground #0000ffff0000
+[0 13] background #f0f0f0f0f0f0
+[0 13] underline 2
+[0 13] underline-color #ffff00000000
+[0 13] gravity 0
+[0 13] gravity-hint 1
+[0 13] strikethrough 1
+[0 13] strikethrough-color #00000000ffff
+[0 13] fallback 0
+[0 13] language de
+range 13 2147483647
+
+
+---
+
+[0:13] de Sans Italic 12 @wdth=100,wght=200
+[13:2147483647] (null) Sans Italic 12 @wdth=100,wght=200
diff --git a/tests/markups/valid-10.markup b/tests/markups/valid-10.markup
new file mode 100644
index 00000000..b4540749
--- /dev/null
+++ b/tests/markups/valid-10.markup
@@ -0,0 +1,11 @@
+<span font="Sans Italic 12 @wdth=100,wght=200"
+ foreground="#00ff00"
+ background="#f0f0f0"
+ underline="double"
+ underline_color="red"
+ strikethrough="true"
+ strikethrough_color="blue"
+ fallback="false"
+ lang="de"
+ gravity="south"
+ gravity_hint="strong">Lots of attrs</span>
diff --git a/tests/markups/valid-11.expected b/tests/markups/valid-11.expected
new file mode 100644
index 00000000..a41b65b8
--- /dev/null
+++ b/tests/markups/valid-11.expected
@@ -0,0 +1,50 @@
+Lots of attrs
+
+
+---
+
+range 0 5
+[0 13] font Sans Italic 12 @wdth=100,wght=200
+[0 13] foreground #0000ffff0000
+[0 13] background #f0f0f0f0f0f0
+[0 13] underline 2
+[0 13] underline-color #ffff00000000
+[0 13] gravity 0
+[0 13] gravity-hint 1
+[0 13] strikethrough 1
+[0 13] strikethrough-color #00000000ffff
+[0 13] fallback 0
+[0 13] language de
+range 5 7
+[0 13] foreground #0000ffff0000
+[0 13] background #f0f0f0f0f0f0
+[0 13] underline 2
+[0 13] underline-color #ffff00000000
+[0 13] gravity 0
+[0 13] gravity-hint 1
+[0 13] strikethrough 1
+[0 13] strikethrough-color #00000000ffff
+[0 13] fallback 0
+[0 13] language de
+[5 7] font Bold
+range 7 13
+[0 13] font Sans Italic 12 @wdth=100,wght=200
+[0 13] foreground #0000ffff0000
+[0 13] background #f0f0f0f0f0f0
+[0 13] underline 2
+[0 13] underline-color #ffff00000000
+[0 13] gravity 0
+[0 13] gravity-hint 1
+[0 13] strikethrough 1
+[0 13] strikethrough-color #00000000ffff
+[0 13] fallback 0
+[0 13] language de
+range 13 2147483647
+
+
+---
+
+[0:5] de Sans Italic 12 @wdth=100,wght=200
+[5:7] de Sans Bold 12 @wdth=100,wght=200
+[7:13] de Sans Italic 12 @wdth=100,wght=200
+[13:2147483647] (null) Sans Italic 12 @wdth=100,wght=200
diff --git a/tests/markups/valid-11.markup b/tests/markups/valid-11.markup
new file mode 100644
index 00000000..e7ae8388
--- /dev/null
+++ b/tests/markups/valid-11.markup
@@ -0,0 +1,11 @@
+<span font="Sans Italic 12 @wdth=100,wght=200"
+ foreground="#00ff00"
+ background="#f0f0f0"
+ underline="double"
+ underline_color="red"
+ strikethrough="true"
+ strikethrough_color="blue"
+ fallback="false"
+ lang="de"
+ gravity="south"
+ gravity_hint="strong">Lots <span font="bold">of</span> attrs</span>
diff --git a/tests/markups/valid-2.expected b/tests/markups/valid-2.expected
index acd5f1b6..09546763 100644
--- a/tests/markups/valid-2.expected
+++ b/tests/markups/valid-2.expected
@@ -10,3 +10,11 @@ range 9 13
range 13 17
[13 17] style 2
range 17 2147483647
+
+
+---
+
+[0:9] (null) Normal 0
+[9:13] (null) Normal 0
+[13:17] (null) Italic 0
+[17:2147483647] (null) Italic 0
diff --git a/tests/markups/valid-3.expected b/tests/markups/valid-3.expected
index f1030ea7..1943fc37 100644
--- a/tests/markups/valid-3.expected
+++ b/tests/markups/valid-3.expected
@@ -16,3 +16,9 @@ range 0 13
[0 13] fallback 0
[0 13] language de
range 13 2147483647
+
+
+---
+
+[0:13] de Sans Italic 12
+[13:2147483647] (null) Sans Italic 12
diff --git a/tests/markups/valid-4.expected b/tests/markups/valid-4.expected
index eb46086e..171e84e1 100644
--- a/tests/markups/valid-4.expected
+++ b/tests/markups/valid-4.expected
@@ -36,3 +36,21 @@ range 45 54
[42 54] family Monospace
[45 54] underline 1
range 54 2147483647
+
+
+---
+
+[0:5] (null) Bold
+[5:8] (null) Bold 0
+[8:9] (null) Bold 0
+[9:15] (null) Bold Italic 0
+[15:16] (null) Bold Italic 0
+[16:29] (null) Bold Italic 0
+[29:32] (null) Bold Italic 0
+[32:33] (null) Bold Italic 0
+[33:38] (null) Bold Italic 0
+[38:41] (null) Bold Italic 0
+[41:42] (null) Bold Italic 0
+[42:45] (null) Monospace Bold Italic 0
+[45:54] (null) Monospace Bold Italic 0
+[54:2147483647] (null) Monospace Bold Italic 0
diff --git a/tests/markups/valid-5.expected b/tests/markups/valid-5.expected
index d693523c..ee3ae71e 100644
--- a/tests/markups/valid-5.expected
+++ b/tests/markups/valid-5.expected
@@ -18,3 +18,15 @@ range 14 15
range 15 19
[15 19] foreground #222233334444
range 19 2147483647
+
+
+---
+
+[0:4] (null) Normal
+[4:5] (null) Normal
+[5:9] (null) Normal
+[9:10] (null) Normal
+[10:14] (null) Normal
+[14:15] (null) Normal
+[15:19] (null) Normal
+[19:2147483647] (null) Normal
diff --git a/tests/markups/valid-6.expected b/tests/markups/valid-6.expected
index 1886eb68..d5d6ea45 100644
--- a/tests/markups/valid-6.expected
+++ b/tests/markups/valid-6.expected
@@ -21,3 +21,15 @@ range 15 19
[15 19] foreground #222233334444
[15 19] foreground-alpha 5555
range 19 2147483647
+
+
+---
+
+[0:4] (null) Normal
+[4:5] (null) Normal
+[5:9] (null) Normal
+[9:10] (null) Normal
+[10:14] (null) Normal
+[14:15] (null) Normal
+[15:19] (null) Normal
+[19:2147483647] (null) Normal
diff --git a/tests/markups/valid-7.expected b/tests/markups/valid-7.expected
index b9d8acf6..d30d165d 100644
--- a/tests/markups/valid-7.expected
+++ b/tests/markups/valid-7.expected
@@ -10,3 +10,11 @@ range 4 5
range 5 9
[5 9] strikethrough-color #222233334444
range 9 2147483647
+
+
+---
+
+[0:4] (null) Normal
+[4:5] (null) Normal
+[5:9] (null) Normal
+[9:2147483647] (null) Normal
diff --git a/tests/markups/valid-8.expected b/tests/markups/valid-8.expected
index d78b7201..de8eb6b8 100644
--- a/tests/markups/valid-8.expected
+++ b/tests/markups/valid-8.expected
@@ -22,3 +22,15 @@ range 15 19
[15 19] background #00000000ffff
[15 19] background-alpha 547a
range 19 2147483647
+
+
+---
+
+[0:4] (null) Normal
+[4:5] (null) Normal
+[5:9] (null) Normal
+[9:10] (null) Normal
+[10:14] (null) Normal
+[14:15] (null) Normal
+[15:19] (null) Normal
+[19:2147483647] (null) Normal
diff --git a/tests/markups/valid-9.expected b/tests/markups/valid-9.expected
index 06936f9f..7931e705 100644
--- a/tests/markups/valid-9.expected
+++ b/tests/markups/valid-9.expected
@@ -6,3 +6,9 @@ Blue text
range 0 9
[0 9] font-features kern 0, dlig, lnum 1, -pnum
range 9 2147483647
+
+
+---
+
+[0:9] (null) Normal
+[9:2147483647] (null) Normal
diff --git a/tests/test-font.c b/tests/test-font.c
index 5603a59f..76d00420 100644
--- a/tests/test-font.c
+++ b/tests/test-font.c
@@ -77,6 +77,43 @@ test_roundtrip (void)
g_free (str);
}
+static void
+test_variation (void)
+{
+ PangoFontDescription *desc1;
+ PangoFontDescription *desc2;
+ 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);
+
+ 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_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));
+
+ 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_cmpstr (pango_font_description_get_variations (desc1), ==, "wght=100,wdth=235");
+
+ g_assert (pango_font_description_equal (desc1, desc2));
+
+ pango_font_description_free (desc1);
+ pango_font_description_free (desc2);
+}
+
int
main (int argc, char *argv[])
{
@@ -87,6 +124,7 @@ main (int argc, char *argv[])
g_test_add_func ("/pango/fontdescription/parse", test_parse);
g_test_add_func ("/pango/fontdescription/roundtrip", test_roundtrip);
+ g_test_add_func ("/pango/fontdescription/variation", test_variation);
return g_test_run ();
}