[pango/wip/matthiasc/font-variations: 1/2] Add initial support for OpenType font variations



commit fc91478ec892a41694703316bb7583c234e65abe
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Sep 5 07:37:31 2017 -0400

    Add initial support for OpenType font variations
    
    This commit lets PangoFontDescription carry font variation
    information as a string. Only pangocairo has been updated
    to make use of this information. We pass it to harfbuzz
    for shaping, and we pass it to cairo when creating scaled
    fonts.

 docs/pango-sections.txt   |    3 +
 pango/fonts.c             |  172 ++++++++++++++++++++++++++++++++++++++++++---
 pango/pango-font.h        |   13 +++-
 pango/pangocairo-fcfont.c |   17 ++++-
 pango/pangofc-fontmap.c   |   43 +++++++++++-
 pango/pangofc-fontmap.h   |   13 ++++
 pango/pangofc-shape.c     |   45 ++++++++++++
 7 files changed, 291 insertions(+), 15 deletions(-)
---
diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt
index 3573fb6..42e2581 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/fonts.c b/pango/fonts.c
index 49e035b..d9a07c0 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 cdc07cd..44705ed 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 30ecde4..ef4273e 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,8 @@ _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap,
   FcMatrix fc_matrix, *fc_matrix_val;
   double size;
   int i;
+  cairo_font_options_t *options;
+  const char *variations;
 
   g_return_val_if_fail (PANGO_IS_CAIRO_FC_FONT_MAP (cffontmap), NULL);
   g_return_val_if_fail (pattern != NULL, NULL);
@@ -247,13 +252,23 @@ _pango_cairo_fc_font_new (PangoCairoFcFontMap *cffontmap,
 
   cairo_matrix_scale (&font_matrix, size, size);
 
+  options = pango_fc_font_key_get_context_key (key);
+  variations = pango_fc_font_key_get_variations (key);
+  if (variations) {
+    options = cairo_font_options_copy (options);
+    cairo_font_options_set_variations (options, variations);
+  }
+
   _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);
 
+  if (variations)
+    cairo_font_options_destroy (options);
+
   ((PangoFcFont *)(cffont))->is_hinted = _pango_cairo_font_private_is_metrics_hinted (&cffont->cf_priv);
 
   return (PangoFcFont *) cffont;
diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c
index 70e9ee7..c5e95c4 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;
@@ -1490,6 +1516,7 @@ pango_fc_make_pattern (const  PangoFontDescription *description,
                            FC_DPI, FcTypeDouble, dpi,
                            FC_SIZE,  FcTypeDouble,  pixel_size * (72. / 1024. / dpi),
                            FC_PIXEL_SIZE,  FcTypeDouble,  pixel_size / 1024.,
+                            PANGO_FC_FONT_VARIATIONS, FcTypeString, variations ? variations : "",
                            NULL);
 
   if (pango_font_description_get_family (description))
@@ -1655,7 +1682,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 +1767,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 +1813,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 +2318,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 4dab083..63452a8 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 number of string elements, each of which is the
+ * 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 60f829f..cd6fd30 100644
--- a/pango/pangofc-shape.c
+++ b/pango/pangofc-shape.c
@@ -282,6 +282,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,
@@ -310,6 +342,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);
@@ -351,6 +384,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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]