diff options
-rw-r--r-- | docs/pango-sections.txt | 3 | ||||
-rw-r--r-- | pango-view/test-font-variations.markup | 9 | ||||
-rw-r--r-- | pango/fonts.c | 172 | ||||
-rw-r--r-- | pango/pango-font.h | 13 | ||||
-rw-r--r-- | pango/pangocairo-fcfont.c | 8 | ||||
-rw-r--r-- | pango/pangofc-fontmap.c | 48 | ||||
-rw-r--r-- | pango/pangofc-fontmap.h | 13 | ||||
-rw-r--r-- | pango/pangofc-shape.c | 45 | ||||
-rw-r--r-- | tests/markup-parse.c | 68 | ||||
-rw-r--r-- | tests/markups/valid-1.expected | 8 | ||||
-rw-r--r-- | tests/markups/valid-10.expected | 24 | ||||
-rw-r--r-- | tests/markups/valid-10.markup | 11 | ||||
-rw-r--r-- | tests/markups/valid-11.expected | 50 | ||||
-rw-r--r-- | tests/markups/valid-11.markup | 11 | ||||
-rw-r--r-- | tests/markups/valid-2.expected | 8 | ||||
-rw-r--r-- | tests/markups/valid-3.expected | 6 | ||||
-rw-r--r-- | tests/markups/valid-4.expected | 18 | ||||
-rw-r--r-- | tests/markups/valid-5.expected | 12 | ||||
-rw-r--r-- | tests/markups/valid-6.expected | 12 | ||||
-rw-r--r-- | tests/markups/valid-7.expected | 8 | ||||
-rw-r--r-- | tests/markups/valid-8.expected | 12 | ||||
-rw-r--r-- | tests/markups/valid-9.expected | 6 | ||||
-rw-r--r-- | tests/test-font.c | 38 |
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 (); } |