[gtk+] css: Use enums instead of idents for font-variant properties



commit 6859f0a6d13ccb3bbe78e34dade0c588a2d6ed2a
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Sep 18 18:38:16 2017 -0400

    css: Use enums instead of idents for font-variant properties
    
    As Benjamin says, ident should only be used if any value
    is valid, which is not the case here. So use enums instead,
    which should also be more efficient. To handle the more
    complicated cases like font-variant-ligatures, we have to
    introduce flags-like values.

 gtk/gtkcssenumvalue.c             |  567 +++++++++++++++++++++++++++++++++++++
 gtk/gtkcssenumvalueprivate.h      |   32 ++
 gtk/gtkcssshorthandpropertyimpl.c |  257 +++++++----------
 gtk/gtkcssstyle.c                 |  241 ++++++++--------
 gtk/gtkcssstylepropertyimpl.c     |  271 +++++--------------
 gtk/gtkcsstypesprivate.h          |   65 +++++
 6 files changed, 958 insertions(+), 475 deletions(-)
---
diff --git a/gtk/gtkcssenumvalue.c b/gtk/gtkcssenumvalue.c
index b4b31da..f5a0aa0 100644
--- a/gtk/gtkcssenumvalue.c
+++ b/gtk/gtkcssenumvalue.c
@@ -936,3 +936,570 @@ _gtk_css_icon_style_value_get (const GtkCssValue *value)
 
   return value->value;
 }
+
+/* GtkCssFontKerning */
+
+static const GtkCssValueClass GTK_CSS_VALUE_FONT_KERNING = {
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_enum_equal,
+  gtk_css_value_enum_transition,
+  gtk_css_value_enum_print
+};
+
+static GtkCssValue font_kerning_values[] = {
+  { &GTK_CSS_VALUE_FONT_KERNING, 1, GTK_CSS_FONT_KERNING_AUTO, "auto" },
+  { &GTK_CSS_VALUE_FONT_KERNING, 1, GTK_CSS_FONT_KERNING_NORMAL, "normal" },
+  { &GTK_CSS_VALUE_FONT_KERNING, 1, GTK_CSS_FONT_KERNING_NONE, "none" }
+};
+
+GtkCssValue *
+_gtk_css_font_kerning_value_new (GtkCssFontKerning kerning)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (font_kerning_values); i++)
+    {
+      if (font_kerning_values[i].value == kerning)
+        return _gtk_css_value_ref (&font_kerning_values[i]);
+    }
+
+  g_return_val_if_reached (NULL);
+}
+
+GtkCssValue *
+_gtk_css_font_kerning_value_try_parse (GtkCssParser *parser)
+{
+  guint i;
+
+  g_return_val_if_fail (parser != NULL, NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (font_kerning_values); i++)
+    {
+      if (_gtk_css_parser_try (parser, font_kerning_values[i].name, TRUE))
+        return _gtk_css_value_ref (&font_kerning_values[i]);
+    }
+
+  return NULL;
+}
+
+GtkCssFontKerning
+_gtk_css_font_kerning_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_KERNING, GTK_CSS_FONT_KERNING_AUTO);
+
+  return value->value;
+}
+
+/* GtkCssFontVariantPos */
+
+static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_POSITION = {
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_enum_equal,
+  gtk_css_value_enum_transition,
+  gtk_css_value_enum_print
+};
+
+static GtkCssValue font_variant_position_values[] = {
+  { &GTK_CSS_VALUE_FONT_VARIANT_POSITION, 1, GTK_CSS_FONT_VARIANT_POSITION_NORMAL, "normal" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_POSITION, 1, GTK_CSS_FONT_VARIANT_POSITION_SUB, "sub" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_POSITION, 1, GTK_CSS_FONT_VARIANT_POSITION_SUPER, "super" }
+};
+
+GtkCssValue *
+_gtk_css_font_variant_position_value_new (GtkCssFontVariantPosition position)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_position_values); i++)
+    {
+      if (font_variant_position_values[i].value == position)
+        return _gtk_css_value_ref (&font_variant_position_values[i]);
+    }
+
+  g_return_val_if_reached (NULL);
+}
+
+GtkCssValue *
+_gtk_css_font_variant_position_value_try_parse (GtkCssParser *parser)
+{
+  guint i;
+
+  g_return_val_if_fail (parser != NULL, NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_position_values); i++)
+    {
+      if (_gtk_css_parser_try (parser, font_variant_position_values[i].name, TRUE))
+        return _gtk_css_value_ref (&font_variant_position_values[i]);
+    }
+
+  return NULL;
+}
+
+GtkCssFontVariantPosition
+_gtk_css_font_variant_position_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_POSITION, 
GTK_CSS_FONT_VARIANT_POSITION_NORMAL);
+
+  return value->value;
+}
+
+/* GtkCssFontVariantCaps */
+
+static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_CAPS = {
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_enum_equal,
+  gtk_css_value_enum_transition,
+  gtk_css_value_enum_print
+};
+
+static GtkCssValue font_variant_caps_values[] = {
+  { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, GTK_CSS_FONT_VARIANT_CAPS_NORMAL, "normal" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, GTK_CSS_FONT_VARIANT_CAPS_SMALL_CAPS, "small-caps" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, GTK_CSS_FONT_VARIANT_CAPS_ALL_SMALL_CAPS, "all-small-caps" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, GTK_CSS_FONT_VARIANT_CAPS_PETITE_CAPS, "petite-caps" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, GTK_CSS_FONT_VARIANT_CAPS_ALL_PETITE_CAPS, "all-petite-caps" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, GTK_CSS_FONT_VARIANT_CAPS_UNICASE, "unicase" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_CAPS, 1, GTK_CSS_FONT_VARIANT_CAPS_TITLING_CAPS, "titling-caps" }
+};
+
+GtkCssValue *
+_gtk_css_font_variant_caps_value_new (GtkCssFontVariantCaps caps)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_caps_values); i++)
+    {
+      if (font_variant_caps_values[i].value == caps)
+        return _gtk_css_value_ref (&font_variant_caps_values[i]);
+    }
+
+  g_return_val_if_reached (NULL);
+}
+
+GtkCssValue *
+_gtk_css_font_variant_caps_value_try_parse (GtkCssParser *parser)
+{
+  guint i;
+
+  g_return_val_if_fail (parser != NULL, NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_caps_values); i++)
+    {
+      if (_gtk_css_parser_try (parser, font_variant_caps_values[i].name, TRUE))
+        return _gtk_css_value_ref (&font_variant_caps_values[i]);
+    }
+
+  return NULL;
+}
+
+GtkCssFontVariantCaps
+_gtk_css_font_variant_caps_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_CAPS, GTK_CSS_FONT_VARIANT_CAPS_NORMAL);
+
+  return value->value;
+}
+
+/* GtkCssFontVariantAlternate */
+
+static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE = {
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_enum_equal,
+  gtk_css_value_enum_transition,
+  gtk_css_value_enum_print
+};
+
+static GtkCssValue font_variant_alternate_values[] = {
+  { &GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE, 1, GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL, "normal" },
+  { &GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE, 1, GTK_CSS_FONT_VARIANT_ALTERNATE_HISTORICAL_FORMS, 
"historical-forms" }
+};
+
+GtkCssValue *
+_gtk_css_font_variant_alternate_value_new (GtkCssFontVariantAlternate alternate)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_alternate_values); i++)
+    {
+      if (font_variant_alternate_values[i].value == alternate)
+        return _gtk_css_value_ref (&font_variant_alternate_values[i]);
+    }
+
+  g_return_val_if_reached (NULL);
+}
+
+GtkCssValue *
+_gtk_css_font_variant_alternate_value_try_parse (GtkCssParser *parser)
+{
+  guint i;
+
+  g_return_val_if_fail (parser != NULL, NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_alternate_values); i++)
+    {
+      if (_gtk_css_parser_try (parser, font_variant_alternate_values[i].name, TRUE))
+        return _gtk_css_value_ref (&font_variant_alternate_values[i]);
+    }
+
+  return NULL;
+}
+
+GtkCssFontVariantAlternate
+_gtk_css_font_variant_alternate_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_ALTERNATE, 
GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL);
+
+  return value->value;
+}
+
+/* below are flags, which are handle a bit differently. We allocate values dynamically,
+ * and we parse one bit at a time, while allowing for detection of invalid combinations.
+ */
+
+typedef struct {
+  int value;
+  const char *name;
+} FlagsValue;
+
+static gboolean
+gtk_css_value_flags_equal (const GtkCssValue *enum1,
+                           const GtkCssValue *enum2)
+{
+  return enum1->value == enum2->value;
+}
+
+static void
+gtk_css_value_flags_print (const FlagsValue  *values,
+                           guint              n_values,
+                           const GtkCssValue *value,
+                           GString           *string)
+{
+  guint i;
+  const char *sep = "";
+
+  for (i = 0; i < n_values; i++)
+    {
+      if (value->value & values[i].value)
+        {
+          g_string_append (string, sep);
+          g_string_append (string, values[i].name);
+          sep = " ";
+        }
+    }
+}
+
+/* GtkCssFontVariantLigature */
+
+static FlagsValue font_variant_ligature_values[] = {
+  { GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL, "normal" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_NONE, "none" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_COMMON_LIGATURES, "common-ligatures" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_NO_COMMON_LIGATURES, "no-common-ligatures" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_DISCRETIONARY_LIGATURES, "discretionary-ligatures" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_NO_DISCRETIONARY_LIGATURES, "no-discretionary-ligatures" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_HISTORICAL_LIGATURES, "historical-ligatures" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_NO_HISTORICAL_LIGATURES, "no-historical-ligatures" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_CONTEXTUAL, "contextual" },
+  { GTK_CSS_FONT_VARIANT_LIGATURE_NO_CONTEXTUAL, "no-contextual" }
+};
+
+static void
+gtk_css_font_variant_ligature_value_print (const GtkCssValue *value,
+                                           GString           *string)
+{
+  gtk_css_value_flags_print (font_variant_ligature_values,
+                             G_N_ELEMENTS (font_variant_ligature_values),
+                             value, string);
+}
+
+static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_LIGATURE = {
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_flags_equal,
+  gtk_css_value_enum_transition,
+  gtk_css_font_variant_ligature_value_print
+};
+
+static gboolean
+ligature_value_is_valid (GtkCssFontVariantLigature ligatures)
+{
+  if (((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL) &&
+       (ligatures != GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL)) ||
+      ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NONE) &&
+       (ligatures != GTK_CSS_FONT_VARIANT_LIGATURE_NONE)) ||
+      ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_COMMON_LIGATURES) &&
+       (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_COMMON_LIGATURES)) ||
+      ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_DISCRETIONARY_LIGATURES) &&
+       (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_DISCRETIONARY_LIGATURES)) ||
+      ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_HISTORICAL_LIGATURES) &&
+       (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_HISTORICAL_LIGATURES)) ||
+      ((ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_CONTEXTUAL) &&
+       (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_CONTEXTUAL)))
+    return FALSE;
+
+  return TRUE;
+}
+
+GtkCssValue *
+_gtk_css_font_variant_ligature_value_new (GtkCssFontVariantLigature ligatures)
+{
+  GtkCssValue *value;
+
+  if (!ligature_value_is_valid (ligatures))
+    return NULL;
+
+  value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_FONT_VARIANT_LIGATURE);
+  value->value = ligatures;
+  value->name = NULL;
+
+  return value;
+}
+
+GtkCssFontVariantLigature
+_gtk_css_font_variant_ligature_try_parse_one (GtkCssParser              *parser,
+                                              GtkCssFontVariantLigature  base)
+{
+  guint i;
+  GtkCssFontVariantLigature value = 0;
+
+  g_return_val_if_fail (parser != NULL, 0);
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_ligature_values); i++)
+    {
+      if (_gtk_css_parser_try (parser, font_variant_ligature_values[i].name, TRUE))
+        {
+          value = font_variant_ligature_values[i].value;
+          break;
+        }
+    }
+
+  if (value == 0)
+    return base; /* not parsing this value */
+
+  if ((base | value) == base)
+    return 0; /* repeated value */
+
+  if (!ligature_value_is_valid (base | value))
+    return 0; /* bad combination */
+
+  return base | value;
+}
+
+GtkCssFontVariantLigature
+_gtk_css_font_variant_ligature_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_LIGATURE, 
GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL);
+
+  return value->value;
+}
+
+/* GtkCssFontVariantNumeric */
+
+static FlagsValue font_variant_numeric_values[] = {
+  { GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL, "normal" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS, "lining-nums" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS, "oldstyle-nums" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS, "proportional-nums" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS, "tabular-nums" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS, "diagonal-fractions" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS, "stacked-fractions" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_ORDINAL, "ordinal" },
+  { GTK_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO, "slashed-zero" }
+};
+
+static void
+gtk_css_font_variant_numeric_value_print (const GtkCssValue *value,
+                                          GString           *string)
+{
+  gtk_css_value_flags_print (font_variant_numeric_values,
+                             G_N_ELEMENTS (font_variant_numeric_values),
+                             value, string);
+}
+
+static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_NUMERIC = {
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_flags_equal,
+  gtk_css_value_enum_transition,
+  gtk_css_font_variant_numeric_value_print
+};
+
+static gboolean
+numeric_value_is_valid (GtkCssFontVariantNumeric numeric)
+{
+  if (((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL) &&
+       (numeric != GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL)) ||
+      ((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS) &&
+       (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS)) ||
+      ((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS) &&
+       (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS)) ||
+      ((numeric & GTK_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS) &&
+       (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS)))
+    return FALSE;
+
+  return TRUE;
+}
+
+GtkCssValue *
+_gtk_css_font_variant_numeric_value_new (GtkCssFontVariantNumeric numeric)
+{
+  GtkCssValue *value;
+
+  if (!numeric_value_is_valid (numeric))
+    return NULL;
+
+  value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_FONT_VARIANT_NUMERIC);
+  value->value = numeric;
+  value->name = NULL;
+
+  return value;
+}
+
+GtkCssFontVariantNumeric
+_gtk_css_font_variant_numeric_try_parse_one (GtkCssParser             *parser,
+                                             GtkCssFontVariantNumeric  base)
+{
+  guint i;
+  GtkCssFontVariantNumeric value = 0;
+
+  g_return_val_if_fail (parser != NULL, 0);
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_numeric_values); i++)
+    {
+      if (_gtk_css_parser_try (parser, font_variant_numeric_values[i].name, TRUE))
+        {
+          value = font_variant_numeric_values[i].value;
+          break;
+        }
+    }
+
+  if (value == 0)
+    return base; /* not parsing this value */
+
+  if ((base | value) == base)
+    return 0; /* repeated value */
+
+  if (!numeric_value_is_valid (base | value))
+    return 0; /* bad combination */
+
+  return base | value;
+}
+
+GtkCssFontVariantNumeric
+_gtk_css_font_variant_numeric_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_NUMERIC, 
GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL);
+
+  return value->value;
+}
+
+/* GtkCssFontVariantEastAsian */
+
+static FlagsValue font_variant_east_asian_values[] = {
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL, "normal" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS78, "jis78" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS83, "jis83" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS90, "jis90" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS04, "jis04" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED, "simplified" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL, "traditional" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH, "full-width" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL, "proportional-width" },
+  { GTK_CSS_FONT_VARIANT_EAST_ASIAN_RUBY, "ruby" }
+};
+
+static void
+gtk_css_font_variant_east_asian_value_print (const GtkCssValue *value,
+                                             GString           *string)
+{
+  gtk_css_value_flags_print (font_variant_east_asian_values,
+                             G_N_ELEMENTS (font_variant_east_asian_values),
+                             value, string);
+}
+
+static const GtkCssValueClass GTK_CSS_VALUE_FONT_VARIANT_EAST_ASIAN = {
+  gtk_css_value_enum_free,
+  gtk_css_value_enum_compute,
+  gtk_css_value_flags_equal,
+  gtk_css_value_enum_transition,
+  gtk_css_font_variant_east_asian_value_print
+};
+
+static gboolean
+east_asian_value_is_valid (GtkCssFontVariantEastAsian east_asian)
+{
+  if ((east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL) &&
+      (east_asian != GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL))
+    return FALSE;
+
+  if (__builtin_popcount (east_asian & (GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS78 |
+                                        GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS83 |
+                                        GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS90 |
+                                        GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS04 |
+                                        GTK_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED |
+                                        GTK_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL)) > 1)
+    return FALSE;
+
+  if (__builtin_popcount (east_asian & (GTK_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH |
+                                        GTK_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL)) > 1)
+    return FALSE;
+
+  return TRUE;
+}
+
+GtkCssValue *
+_gtk_css_font_variant_east_asian_value_new (GtkCssFontVariantEastAsian east_asian)
+{
+  GtkCssValue *value;
+
+  if (!east_asian_value_is_valid (east_asian))
+    return NULL;
+
+  value = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_FONT_VARIANT_EAST_ASIAN);
+  value->value = east_asian;
+  value->name = NULL;
+
+  return value;
+}
+
+GtkCssFontVariantEastAsian
+_gtk_css_font_variant_east_asian_try_parse_one (GtkCssParser               *parser,
+                                                GtkCssFontVariantEastAsian  base)
+{
+  guint i;
+  GtkCssFontVariantEastAsian value = 0;
+
+  g_return_val_if_fail (parser != NULL, 0);
+
+  for (i = 0; i < G_N_ELEMENTS (font_variant_east_asian_values); i++)
+    {
+      if (_gtk_css_parser_try (parser, font_variant_east_asian_values[i].name, TRUE))
+        {
+          value = font_variant_east_asian_values[i].value;
+          break;
+        }
+    }
+
+  if (value == 0)
+    return base; /* not parsing this value */
+
+  if ((base | value) == base)
+    return 0; /* repeated value */
+
+  if (!east_asian_value_is_valid (base | value))
+    return 0; /* bad combination */
+
+  return base | value;
+}
+
+GtkCssFontVariantEastAsian
+_gtk_css_font_variant_east_asian_value_get (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_FONT_VARIANT_EAST_ASIAN, 
GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL);
+
+  return value->value;
+}
diff --git a/gtk/gtkcssenumvalueprivate.h b/gtk/gtkcssenumvalueprivate.h
index bdb4d2a..753ec89 100644
--- a/gtk/gtkcssenumvalueprivate.h
+++ b/gtk/gtkcssenumvalueprivate.h
@@ -81,6 +81,38 @@ GtkCssValue *   _gtk_css_icon_style_value_new         (GtkCssIconStyle    icon_s
 GtkCssValue *   _gtk_css_icon_style_value_try_parse   (GtkCssParser      *parser);
 GtkCssIconStyle _gtk_css_icon_style_value_get         (const GtkCssValue *value);
 
+GtkCssValue *     _gtk_css_font_kerning_value_new       (GtkCssFontKerning  kerning);
+GtkCssValue *     _gtk_css_font_kerning_value_try_parse (GtkCssParser      *parser);
+GtkCssFontKerning _gtk_css_font_kerning_value_get       (const GtkCssValue *value);
+
+GtkCssValue *        _gtk_css_font_variant_position_value_new       (GtkCssFontVariantPosition  position);
+GtkCssValue *        _gtk_css_font_variant_position_value_try_parse (GtkCssParser         *parser);
+GtkCssFontVariantPosition _gtk_css_font_variant_position_value_get       (const GtkCssValue    *value);
+
+GtkCssValue *         _gtk_css_font_variant_caps_value_new       (GtkCssFontVariantCaps  caps);
+GtkCssValue *         _gtk_css_font_variant_caps_value_try_parse (GtkCssParser          *parser);
+GtkCssFontVariantCaps _gtk_css_font_variant_caps_value_get       (const GtkCssValue     *value);
+
+GtkCssValue *        _gtk_css_font_variant_alternate_value_new       (GtkCssFontVariantAlternate  
alternates);
+GtkCssValue *        _gtk_css_font_variant_alternate_value_try_parse (GtkCssParser         *parser);
+GtkCssFontVariantAlternate _gtk_css_font_variant_alternate_value_get       (const GtkCssValue    *value);
+
+GtkCssValue *        _gtk_css_font_variant_ligature_value_new          (GtkCssFontVariantLigature  
ligatures);
+GtkCssFontVariantLigature _gtk_css_font_variant_ligature_try_parse_one (GtkCssParser               *parser,
+                                                                        GtkCssFontVariantLigature   base);
+GtkCssFontVariantLigature _gtk_css_font_variant_ligature_value_get     (const GtkCssValue          *value);
+
+GtkCssValue *        _gtk_css_font_variant_numeric_value_new          (GtkCssFontVariantNumeric     numeric);
+GtkCssFontVariantNumeric _gtk_css_font_variant_numeric_try_parse_one (GtkCssParser               *parser,
+                                                                      GtkCssFontVariantNumeric    base);
+GtkCssFontVariantNumeric _gtk_css_font_variant_numeric_value_get     (const GtkCssValue          *value);
+
+
+GtkCssValue *        _gtk_css_font_variant_east_asian_value_new          (GtkCssFontVariantEastAsian 
east_asian);
+GtkCssFontVariantEastAsian _gtk_css_font_variant_east_asian_try_parse_one (GtkCssParser               
*parser,
+                                                                      GtkCssFontVariantEastAsian base);
+GtkCssFontVariantEastAsian _gtk_css_font_variant_east_asian_value_get     (const GtkCssValue          
*value);
+
 G_END_DECLS
 
 #endif /* __GTK_CSS_ENUM_VALUE_PRIVATE_H__ */
diff --git a/gtk/gtkcssshorthandpropertyimpl.c b/gtk/gtkcssshorthandpropertyimpl.c
index 40b96c6..751e6c2 100644
--- a/gtk/gtkcssshorthandpropertyimpl.c
+++ b/gtk/gtkcssshorthandpropertyimpl.c
@@ -878,202 +878,153 @@ parse_font_variant (GtkCssShorthandProperty  *shorthand,
   else if (_gtk_css_parser_try (parser, "none", TRUE))
     {
       /* all initial values, except for font-variant-ligatures */
-      values[0] = _gtk_css_array_value_new (_gtk_css_ident_value_new ("none"));
+      values[0] = _gtk_css_font_variant_ligature_value_new (GTK_CSS_FONT_VARIANT_LIGATURE_NONE);
     }
   else
     {
-      gboolean found;
-      GtkCssValue *lig_values[4] = { NULL, NULL, NULL, NULL };
-      guint n_ligs = 0;
-      gboolean common = FALSE;
-      gboolean discretionary = FALSE;
-      gboolean historical = FALSE;
-      gboolean contextual = FALSE;
-      GtkCssValue *num_values[5] = { NULL, NULL, NULL, NULL };
-      guint n_num = 0;
-      gboolean figure = FALSE;
-      gboolean spacing = FALSE;
-      gboolean fraction = FALSE;
-      gboolean ordinal = FALSE;
-      gboolean zero = FALSE;
-      GtkCssValue *alt_value;
-      GtkCssValue *ea_values[5] = { NULL, NULL, NULL, NULL };
-      guint n_ea = 0;
-      gboolean variant = FALSE;
-      gboolean width = FALSE;
-      gboolean ruby = FALSE;
+      GtkCssFontVariantLigature ligatures;
+      GtkCssFontVariantNumeric numeric;
+      GtkCssFontVariantEastAsian east_asian;
 
+      ligatures = 0;
+      numeric = 0;
+      east_asian = 0;
       do {
-        found = FALSE;
-        if (!common)
-          {
-            lig_values[n_ligs] = _gtk_css_ident_value_try (parser, "common-ligatures",
-                                                                   "no-common-ligatures", NULL);
-            if (lig_values[n_ligs])
-              {
-                n_ligs++;
-                common = TRUE;
-                found = TRUE;
-              }
-          }
-        if (!discretionary)
+        GtkCssFontVariantLigature parsed_ligature;
+        GtkCssFontVariantNumeric parsed_numeric;
+        GtkCssFontVariantEastAsian parsed_east_asian;
+
+        parsed_ligature = _gtk_css_font_variant_ligature_try_parse_one (parser, ligatures);
+        if (parsed_ligature == 0 && ligatures != 0)
           {
-            lig_values[n_ligs] = _gtk_css_ident_value_try (parser, "discretionary-ligatures",
-                                                                   "no-discretionary-ligatures", NULL);
-            if (lig_values[n_ligs])
-              {
-                n_ligs++;
-                discretionary = TRUE;
-                found = TRUE;
-              }
+            _gtk_css_parser_error (parser, "Invalid combination of ligature values");
+            return FALSE;
           }
-        if (!historical)
+        if (parsed_ligature == GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL ||
+            parsed_ligature == GTK_CSS_FONT_VARIANT_LIGATURE_NONE)
           {
-            lig_values[n_ligs] = _gtk_css_ident_value_try (parser, "historical-ligatures",
-                                                                   "no-historical-ligatures", NULL);
-            if (lig_values[n_ligs])
-              {
-                n_ligs++;
-                historical = TRUE;
-                found = TRUE;
-              }
+            _gtk_css_parser_error (parser, "Unexpected ligature value");
+            return FALSE;
           }
-        if (!contextual)
+        if (parsed_ligature != ligatures)
           {
-            lig_values[n_ligs] = _gtk_css_ident_value_try (parser, "contextual",
-                                                                   "no-contextual", NULL);
-            if (lig_values[n_ligs])
-              {
-                n_ligs++;
-                contextual = TRUE;
-                found = TRUE;
-              }
+            ligatures = parsed_ligature;
+            goto found;
           }
 
-        if (!figure)
+        parsed_numeric = _gtk_css_font_variant_numeric_try_parse_one (parser, numeric);
+        if (parsed_numeric == 0 && numeric != 0)
           {
-            num_values[n_num] = _gtk_css_ident_value_try (parser, "lining-nums",
-                                                                  "oldstyle-nums", NULL);
-            if (num_values[n_num])
-              {
-                n_num++;
-                figure = TRUE;
-                found = TRUE;
-              }
+            _gtk_css_parser_error (parser, "Invalid combination of numeric values");
+            return FALSE;
           }
-        if (!spacing)
+        if (parsed_numeric == GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL)
           {
-            num_values[n_num] = _gtk_css_ident_value_try (parser, "proportional-nums",
-                                                                  "tabular-nums", NULL);
-            if (num_values[n_num])
-              {
-                n_num++;
-                spacing = TRUE;
-                found = TRUE;
-              }
+            _gtk_css_parser_error (parser, "Unexpected numeric value");
+            return FALSE;
           }
-        if (!fraction)
+        if (parsed_numeric != numeric)
           {
-            num_values[n_num] = _gtk_css_ident_value_try (parser, "diagonal-fractions",
-                                                                  "stacked-fractions", NULL);
-            if (num_values[n_num])
-              {
-                n_num++;
-                fraction = TRUE;
-                found = TRUE;
-              }
+            numeric = parsed_numeric;
+            goto found;
           }
-        if (!ordinal)
+
+        parsed_east_asian = _gtk_css_font_variant_east_asian_try_parse_one (parser, east_asian);
+        if (parsed_east_asian == 0 && east_asian != 0)
           {
-            num_values[n_num] = _gtk_css_ident_value_try (parser, "ordinal", NULL);
-            if (num_values[n_num])
-              {
-                n_num++;
-                ordinal = TRUE;
-                found = TRUE;
-              }
+            _gtk_css_parser_error (parser, "Invalid combination of east asian values");
+            return FALSE;
           }
-        if (!zero)
+        if (parsed_east_asian == GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL)
           {
-            num_values[n_num] = _gtk_css_ident_value_try (parser, "slashed-zero", NULL);
-            if (num_values[n_num])
-              {
-                n_num++;
-                zero = TRUE;
-                found = TRUE;
-              }
+            _gtk_css_parser_error (parser, "Unexpected east asian value");
+            return FALSE;
           }
-        if (alt_value == NULL)
+        if (parsed_east_asian != east_asian)
           {
-            alt_value = _gtk_css_ident_value_try (parser, "historical-forms", NULL);
-            if (alt_value)
-              found = TRUE;
+            east_asian = parsed_east_asian;
+            goto found;
           }
 
         if (values[1] == NULL)
           {
-            values[1] = _gtk_css_ident_value_try (parser, "sub", "super", NULL);
+            values[1] = _gtk_css_font_variant_position_value_try_parse (parser);
             if (values[1])
-              found = TRUE;
+              {
+                if (_gtk_css_font_variant_position_value_get (values[1]) == 
GTK_CSS_FONT_VARIANT_POSITION_NORMAL)
+                  {
+                    _gtk_css_parser_error (parser, "Unexpected position value");
+                    return FALSE;
+                  }
+                goto found;
+              }
           }
         if (values[2] == NULL)
           {
-            values[2] = _gtk_css_ident_value_try (parser, "small-caps", "all-small-caps",
-                                                          "petite-caps", "all-petite-caps",
-                                                          "unicase", "titling-caps", NULL);
+            values[2] = _gtk_css_font_variant_caps_value_try_parse (parser);
             if (values[2])
-              found = TRUE;
-          }
-
-        if (!variant)
-          {
-            ea_values[n_ea] = _gtk_css_ident_value_try (parser, "jis78", "jis83", "jis90", "jis04",
-                                                        "simplified", "traditional", NULL);
-            if (ea_values[n_ea])
-              {
-                n_ea++;
-                variant = TRUE;
-              }
-         }
-        if (!width)
-          {
-            ea_values[n_ea] = _gtk_css_ident_value_try (parser, "full-width"
-                                                                "proportional-width", NULL);
-            if (ea_values[n_ea])
               {
-                n_ea++;
-                width = TRUE;
+                if (_gtk_css_font_variant_caps_value_get (values[2]) == GTK_CSS_FONT_VARIANT_CAPS_NORMAL)
+                  {
+                    _gtk_css_parser_error (parser, "Unexpected caps value");
+                    return FALSE;
+                  }
+                goto found;
               }
-         }
-        if (!ruby)
+          }
+
+        if (values[4] == NULL)
           {
-            ea_values[n_ea] = _gtk_css_ident_value_try (parser, "ruby", NULL);
-            if (ea_values[n_ea])
+            values[4] = _gtk_css_font_variant_alternate_value_try_parse (parser);
+            if (values[4])
               {
-                n_ea++;
-                ruby = TRUE;
+                if (_gtk_css_font_variant_alternate_value_get (values[4]) == 
GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL)
+                  {
+                    _gtk_css_parser_error (parser, "Unexpected alternate value");
+                    return FALSE;
+                  }
+                goto found;
               }
-         }
+          }
 
+        _gtk_css_parser_error (parser, "Unknown value for property");
+        return FALSE;
 
-        if (!found)
-          {
-            _gtk_css_parser_error (parser, "Unknown value for property");
-            return FALSE;
-          }
-      } while (!value_is_done_parsing (parser));
+found:
+        if (value_is_done_parsing (parser))
+          break;
 
-      if (n_ligs > 0)
-        values[0] = _gtk_css_array_value_new_from_array (lig_values, n_ligs);
+      } while (1);
 
-      if (n_num > 0)
-        values[3] = _gtk_css_array_value_new_from_array (num_values, n_num);
+      if (ligatures != 0)
+        {
+          values[0] = _gtk_css_font_variant_ligature_value_new (ligatures);
+          if (values[0] == NULL)
+            {
+              _gtk_css_parser_error (parser, "Invalid combination of ligature values");
+              return FALSE;
+            }
+        }
 
-      if (alt_value)
-        values[4] = _gtk_css_array_value_new (alt_value);
+      if (numeric != 0)
+        {
+          values[3] = _gtk_css_font_variant_numeric_value_new (numeric);
+          if (values[3] == NULL)
+            {
+              _gtk_css_parser_error (parser, "Invalid combination of numeric values");
+              return FALSE;
+            }
+        }
 
-      if (n_ea > 0)
-        values[5] = _gtk_css_array_value_new_from_array  (ea_values, n_ea);
+      if (east_asian != 0)
+        {
+          values[5] = _gtk_css_font_variant_east_asian_value_new (east_asian);
+          if (values[5] == NULL)
+            {
+              _gtk_css_parser_error (parser, "Invalid combination of east asian values");
+              return FALSE;
+            }
+        }
     }
 
   return TRUE;
diff --git a/gtk/gtkcssstyle.c b/gtk/gtkcssstyle.c
index 245d48a..8cdcd2e 100644
--- a/gtk/gtkcssstyle.c
+++ b/gtk/gtkcssstyle.c
@@ -216,6 +216,14 @@ add_pango_attr (PangoAttrList  *attrs,
   return attrs;
 }
 
+static void
+append_separated (GString *s, const char *text)
+{
+  if (s->len > 0)
+    g_string_append (s, ", ");
+  g_string_append (s, text);
+}
+
 PangoAttrList *
 gtk_css_style_get_pango_attributes (GtkCssStyle *style)
 {
@@ -225,15 +233,11 @@ gtk_css_style_get_pango_attributes (GtkCssStyle *style)
   const GdkRGBA *color;
   const GdkRGBA *decoration_color;
   gint letter_spacing;
-  GtkCssValue *kerning;
-  GtkCssValue *ligatures;
-  GtkCssValue *position;
-  GtkCssValue *caps;
-  GtkCssValue *numeric;
-  GtkCssValue *alternates;
-  GtkCssValue *east_asian;
+  GtkCssValue *value;
+  GtkCssFontVariantLigature ligatures;
+  GtkCssFontVariantNumeric numeric;
+  GtkCssFontVariantEastAsian east_asian;
   GString *s;
-  int i;
 
   /* text-decoration */
   decoration_line = _gtk_css_text_decoration_line_value_get (gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_TEXT_DECORATION_LINE));
@@ -273,136 +277,143 @@ gtk_css_style_get_pango_attributes (GtkCssStyle *style)
 
   s = g_string_new ("");
 
-  kerning = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_KERNING);
-  if (strcmp (_gtk_css_ident_value_get (kerning), "normal") == 0)
-    g_string_append (s, "kern 1");
-  else if (strcmp (_gtk_css_ident_value_get (kerning), "none") == 0)
-    g_string_append (s, "kern 0");
-
-  ligatures = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES);
-  for (i = 0; i < _gtk_css_array_value_get_n_values (ligatures); i++)
+  value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_KERNING);
+  switch (_gtk_css_font_kerning_value_get (value))
     {
-      GtkCssValue *value = _gtk_css_array_value_get_nth (ligatures, i);
-      if (s->len > 0) g_string_append (s, ", ");
-      if (strcmp (_gtk_css_ident_value_get (value), "none") == 0)
-        g_string_append (s, "liga 0, clig 0, dlig 0, hlig 0, calt 0");
-      else if (strcmp (_gtk_css_ident_value_get (value), "common-ligatures") == 0)
-        g_string_append (s, "liga 1, clig 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "no-common-ligatures") == 0)
-        g_string_append (s, "liga 0, clig 0");
-      else if (strcmp (_gtk_css_ident_value_get (value), "discretionary-ligatures") == 0)
-        g_string_append (s, "dlig 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "no-discretionary-ligatures") == 0)
-        g_string_append (s, "dlig 0");
-      else if (strcmp (_gtk_css_ident_value_get (value), "historical-ligatures") == 0)
-        g_string_append (s, "hlig 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "no-historical-ligatures") == 0)
-        g_string_append (s, "hlig 0");
-      else if (strcmp (_gtk_css_ident_value_get (value), "contextual") == 0)
-        g_string_append (s, "calt 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "no-contextual") == 0)
-        g_string_append (s, "calt 0");
+    case GTK_CSS_FONT_KERNING_NORMAL:
+      append_separated (s, "kern 1");
+      break;
+    case GTK_CSS_FONT_KERNING_NONE:
+      append_separated (s, "kern 0");
+      break;
+    default: ;
     }
 
-  position = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_POSITION);
-  if (strcmp (_gtk_css_ident_value_get (position), "sub") == 0)
+  value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES);
+  ligatures = _gtk_css_font_variant_ligature_value_get (value);
+  if (ligatures == GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL)
     {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "subs 1");
+      /* all defaults */
     }
-  else if (strcmp (_gtk_css_ident_value_get (kerning), "super") == 0)
+  else if (ligatures == GTK_CSS_FONT_VARIANT_LIGATURE_NONE)
+    append_separated (s, "liga 0, clig 0, dlig 0, hlig 0, calt 0");
+  else
     {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "sups 1");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_COMMON_LIGATURES)
+        append_separated (s, "liga 1, clig 1");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_COMMON_LIGATURES)
+        append_separated (s, "liga 0, clig 0");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_DISCRETIONARY_LIGATURES)
+        append_separated (s, "dlig 1");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_DISCRETIONARY_LIGATURES)
+        append_separated (s, "dlig 0");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_HISTORICAL_LIGATURES)
+        append_separated (s, "hlig 1");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_HISTORICAL_LIGATURES)
+        append_separated (s, "hlig 0");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_CONTEXTUAL)
+        append_separated (s, "calt 1");
+      if (ligatures & GTK_CSS_FONT_VARIANT_LIGATURE_NO_CONTEXTUAL)
+        append_separated (s, "calt 0");
     }
 
-  caps = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_CAPS);
-  if (strcmp (_gtk_css_ident_value_get (caps), "small-caps") == 0)
-    {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "smcp 1");
-    }
-  else if (strcmp (_gtk_css_ident_value_get (caps), "all-small-caps") == 0)
-    {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "c2sc 1, smcp 1");
-    }
-  else if (strcmp (_gtk_css_ident_value_get (caps), "petite-caps") == 0)
+  value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_POSITION);
+  switch (_gtk_css_font_variant_position_value_get (value))
     {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "pcap 1");
+    case GTK_CSS_FONT_VARIANT_POSITION_SUB:
+      append_separated (s, "subs 1");
+      break;
+    case GTK_CSS_FONT_VARIANT_POSITION_SUPER:
+      append_separated (s, "sups 1");
+      break;
+    default: ;
     }
-  else if (strcmp (_gtk_css_ident_value_get (caps), "all-petite-caps") == 0)
+
+  value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_CAPS);
+  switch (_gtk_css_font_variant_caps_value_get (value))
     {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "c2pc 1, pcap 1");
+    case GTK_CSS_FONT_VARIANT_CAPS_SMALL_CAPS:
+      append_separated (s, "smcp 1");
+      break;
+    case GTK_CSS_FONT_VARIANT_CAPS_ALL_SMALL_CAPS:
+      append_separated (s, "c2sc 1, smcp 1");
+      break;
+    case GTK_CSS_FONT_VARIANT_CAPS_PETITE_CAPS:
+      append_separated (s, "pcap 1");
+      break;
+    case GTK_CSS_FONT_VARIANT_CAPS_ALL_PETITE_CAPS:
+      append_separated (s, "c2pc 1, pcap 1");
+      break;
+    case GTK_CSS_FONT_VARIANT_CAPS_UNICASE:
+      append_separated (s, "unic 1");
+      break;
+    case GTK_CSS_FONT_VARIANT_CAPS_TITLING_CAPS:
+      append_separated (s, "titl 1");
+    break;
+    default: ;
     }
-  else if (strcmp (_gtk_css_ident_value_get (caps), "unicase") == 0)
+
+  value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_NUMERIC);
+  numeric = _gtk_css_font_variant_numeric_value_get (value);
+  if (numeric == GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL)
     {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "unic 1");
+      /* all defaults */
     }
-  else if (strcmp (_gtk_css_ident_value_get (caps), "titling-caps") == 0)
+  else
     {
-      if (s->len > 0) g_string_append (s, ", ");
-      g_string_append (s, "titl 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS)
+        append_separated (s, "lnum 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS)
+        append_separated (s, "onum 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS)
+        append_separated (s, "pnum 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS)
+        append_separated (s, "tnum 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS)
+        append_separated (s, "frac 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS)
+        append_separated (s, "afrc 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_ORDINAL)
+        append_separated (s, "ordn 1");
+      if (numeric & GTK_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO)
+        append_separated (s, "zero 1");
     }
 
-  numeric = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_NUMERIC);
-  for (i = 0; i < _gtk_css_array_value_get_n_values (numeric); i++)
+  value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_ALTERNATES);
+  switch (_gtk_css_font_variant_alternate_value_get (value))
     {
-      GtkCssValue *value = _gtk_css_array_value_get_nth (numeric, i);
-      if (s->len > 0) g_string_append (s, ", ");
-      if (strcmp (_gtk_css_ident_value_get (value), "lining-nums") == 0)
-        g_string_append (s, "lnum 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "oldstyle-nums") == 0)
-        g_string_append (s, "onum 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "proportional-nums") == 0)
-        g_string_append (s, "pnum 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "tabular-nums") == 0)
-        g_string_append (s, "tnum 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "diagonal-fractions") == 0)
-        g_string_append (s, "frac 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "stacked-fractions") == 0)
-        g_string_append (s, "afrc 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "ordinal") == 0)
-        g_string_append (s, "ordn 1");
-      else if (strcmp (_gtk_css_ident_value_get (value), "slashed-zero") == 0)
-        g_string_append (s, "zero 1");
+    case GTK_CSS_FONT_VARIANT_ALTERNATE_HISTORICAL_FORMS:
+      append_separated (s, "hist 1");
+      break;
+    default: ;
     }
 
-  alternates = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_ALTERNATES);
-  for (i = 0; i < _gtk_css_array_value_get_n_values (alternates); i++)
+  value = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_EAST_ASIAN);
+  east_asian = _gtk_css_font_variant_east_asian_value_get (value);
+  if (east_asian == GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL)
     {
-      GtkCssValue *value = _gtk_css_array_value_get_nth (alternates, i);
-      if (s->len > 0) g_string_append (s, ", ");
-      if (strcmp (_gtk_css_ident_value_get (value), "historical-forms") == 0)
-        g_string_append (s, "hist 1");
+      /* all defaults */
     }
-
-  east_asian = gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_VARIANT_EAST_ASIAN);
-  for (i = 0; i < _gtk_css_array_value_get_n_values (east_asian); i++)
+  else
     {
-      GtkCssValue *value = _gtk_css_array_value_get_nth (east_asian, i);
-      if (s->len > 0) g_string_append (s, ", ");
-      if (strcmp (_gtk_css_ident_value_get (value), "jis78") == 0)
-        g_string_append (s, "jp78 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "jis83") == 0)
-        g_string_append (s, "jp83 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "jis90") == 0)
-        g_string_append (s, "jp90 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "jis04") == 0)
-        g_string_append (s, "jp04 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "simplified") == 0)
-        g_string_append (s, "smpl 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "traditional") == 0)
-        g_string_append (s, "trad 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "full-width") == 0)
-        g_string_append (s, "fwid 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "proportional-width") == 0)
-        g_string_append (s, "pwid 1");
-      if (strcmp (_gtk_css_ident_value_get (value), "ruby") == 0)
-        g_string_append (s, "ruby 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS78)
+        append_separated (s, "jp78 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS83)
+        append_separated (s, "jp83 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS90)
+        append_separated (s, "jp90 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS04)
+        append_separated (s, "jp04 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED)
+        append_separated (s, "smpl 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL)
+        append_separated (s, "trad 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH)
+        append_separated (s, "fwid 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL)
+        append_separated (s, "pwid 1");
+      if (east_asian & GTK_CSS_FONT_VARIANT_EAST_ASIAN_RUBY)
+        append_separated (s, "ruby 1");
     }
 
   attrs = add_pango_attr (attrs, pango_attr_font_features_new (s->str));
diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c
index c791219..036bd02 100644
--- a/gtk/gtkcssstylepropertyimpl.c
+++ b/gtk/gtkcssstylepropertyimpl.c
@@ -1,4 +1,4 @@
-/* GTK - The GIMP Toolkit
+/*
  * Copyright (C) 2010 Carlos Garnacho <carlosg gnome org>
  *
  * This library is free software; you can redistribute it and/or
@@ -513,9 +513,8 @@ static GtkCssValue *
 parse_font_kerning (GtkCssStyleProperty *property,
                     GtkCssParser        *parser)
 {
-  GtkCssValue *value = NULL;
+  GtkCssValue *value = _gtk_css_font_kerning_value_try_parse (parser);
 
-  value = _gtk_css_ident_value_try (parser, "auto", "normal", "none", NULL);
   if (value == NULL)
     _gtk_css_parser_error (parser, "unknown value for property");
 
@@ -536,73 +535,24 @@ parse_font_variant_ligatures (GtkCssStyleProperty *property,
                               GtkCssParser        *parser)
 {
   GtkCssValue *value = NULL;
+  GtkCssFontVariantLigature ligatures;
 
-  if (_gtk_css_parser_try (parser, "normal", TRUE))
-    value = _gtk_css_array_value_new (_gtk_css_ident_value_new ("normal"));
-  else if (_gtk_css_parser_try (parser, "none", TRUE))
-    value = _gtk_css_array_value_new (_gtk_css_ident_value_new ("none"));
-  else
-    {
-      GtkCssValue *values[4] = { NULL, NULL, NULL, NULL };
-      guint n_values = 0;
-      guint old_n;
-      gboolean common = FALSE;
-      gboolean discretionary = FALSE;
-      gboolean historical = FALSE;
-      gboolean contextual = FALSE;
-
-      do {
-        old_n = n_values;
-        if (!common)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "common-ligatures",
-                                                                 "no-common-ligatures", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                common = TRUE;
-              }
-          }
-        if (!discretionary)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "discretionary-ligatures",
-                                                                 "no-discretionary-ligatures", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                discretionary = TRUE;
-              }
-          }
-        if (!historical)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "historical-ligatures",
-                                                                 "no-historical-ligatures",
-                                                                 NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                historical = TRUE;
-              }
-          }
-        if (!contextual)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "contextual",
-                                                                 "no-contextual", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                contextual = TRUE;
-              }
-          }
-        if (old_n == n_values)
-          {
-            _gtk_css_parser_error (parser, "Not a valid value");
-            return NULL;
-          }
-      } while (!value_is_done_parsing (parser));
-
-      value = _gtk_css_array_value_new_from_array (values, n_values);
-    }
+  ligatures = 0;
+  do {
+    GtkCssFontVariantLigature parsed;
+
+    parsed = _gtk_css_font_variant_ligature_try_parse_one (parser, ligatures);
+    if (parsed == 0 || parsed == ligatures)
+      {
+        _gtk_css_parser_error (parser, "Not a valid value");
+        return NULL;
+      }
+    ligatures = parsed;
+  } while (!value_is_done_parsing (parser));
+
+  value = _gtk_css_font_variant_ligature_value_new (ligatures);
+  if (value == NULL)
+    _gtk_css_parser_error (parser, "Invalid combination of values");
 
   return value;
 }
@@ -611,9 +561,8 @@ static GtkCssValue *
 parse_font_variant_position (GtkCssStyleProperty *property,
                              GtkCssParser        *parser)
 {
-  GtkCssValue *value = NULL;
+  GtkCssValue *value = _gtk_css_font_variant_position_value_try_parse (parser);
 
-  value = _gtk_css_ident_value_try (parser, "normal", "sub", "super", NULL);
   if (value == NULL)
     _gtk_css_parser_error (parser, "unknown value for property");
 
@@ -624,12 +573,8 @@ static GtkCssValue *
 parse_font_variant_caps (GtkCssStyleProperty *property,
                          GtkCssParser        *parser)
 {
-  GtkCssValue *value = NULL;
+  GtkCssValue *value = _gtk_css_font_variant_caps_value_try_parse (parser);
 
-  value = _gtk_css_ident_value_try (parser, "normal",
-                                            "small-caps", "all-small-caps",
-                                            "petite-caps", "all-petite-caps",
-                                            "unicase", "titling-caps", NULL);
   if (value == NULL)
     _gtk_css_parser_error (parser, "unknown value for property");
 
@@ -641,76 +586,24 @@ parse_font_variant_numeric (GtkCssStyleProperty *property,
                             GtkCssParser        *parser)
 {
   GtkCssValue *value = NULL;
+  GtkCssFontVariantNumeric numeric;
 
-  if (_gtk_css_parser_try (parser, "normal", TRUE))
-    value = _gtk_css_array_value_new (_gtk_css_ident_value_new ("normal"));
-  else
-    {
-      GtkCssValue *values[5] = { NULL, NULL, NULL, NULL };
-      guint n_values = 0;
-      guint old_n;
-      gboolean figure = FALSE;
-      gboolean spacing = FALSE;
-      gboolean fraction = FALSE;
-      gboolean ordinal = FALSE;
-      gboolean zero = FALSE;
-
-      do {
-        old_n = n_values;
-        if (!figure)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "lining-nums", "oldstyle-nums", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                figure = TRUE;
-              }
-         }
-        if (!spacing)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "proportional-nums", "tabular-nums", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                spacing = TRUE;
-              }
-         }
-        if (!fraction)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "diagonal-fractions", "stacked-fractions", 
NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                fraction = TRUE;
-              }
-         }
-        if (!ordinal)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "ordinal", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                ordinal = TRUE;
-              }
-         }
-        if (!zero)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "slashed-zero", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                zero = TRUE;
-              }
-         }
-        if (old_n == n_values)
-          {
-            _gtk_css_parser_error (parser, "Not a valid value");
-            return NULL;
-          }
-      } while (!value_is_done_parsing (parser));
-
-      value = _gtk_css_array_value_new_from_array (values, n_values);
-    }
+  numeric = 0;
+  do {
+    GtkCssFontVariantNumeric parsed;
+
+    parsed = _gtk_css_font_variant_numeric_try_parse_one (parser, numeric);
+    if (parsed == 0 || parsed == numeric)
+      {
+        _gtk_css_parser_error (parser, "Not a valid value");
+        return NULL;
+      }
+    numeric = parsed;
+  } while (!value_is_done_parsing (parser));
+
+  value = _gtk_css_font_variant_numeric_value_new (numeric);
+  if (value == NULL)
+    _gtk_css_parser_error (parser, "Invalid combination of values");
 
   return value;
 }
@@ -719,11 +612,10 @@ static GtkCssValue *
 parse_font_variant_alternates (GtkCssStyleProperty *property,
                                GtkCssParser        *parser)
 {
-  GtkCssValue *value = NULL;
+  GtkCssValue *value = _gtk_css_font_variant_alternate_value_try_parse (parser);
 
-  value = _gtk_css_ident_value_try (parser, "normal", "historical-forms", NULL);
   if (value == NULL)
-    _gtk_css_parser_error (parser, "Not a valid value");
+    _gtk_css_parser_error (parser, "unknown value for property");
 
   return value;
 }
@@ -733,63 +625,28 @@ parse_font_variant_east_asian (GtkCssStyleProperty *property,
                                GtkCssParser        *parser)
 {
   GtkCssValue *value = NULL;
+  GtkCssFontVariantEastAsian east_asian;
 
-  if (_gtk_css_parser_try (parser, "normal", TRUE))
-    value = _gtk_css_array_value_new (_gtk_css_ident_value_new ("normal"));
-  else
-    {
-      GtkCssValue *values[3] = { NULL, NULL, NULL };
-      guint n_values = 0;
-      guint old_n;
-      gboolean variant = FALSE;
-      gboolean width = FALSE;
-      gboolean ruby = FALSE;
-
-      do {
-        old_n = n_values;
-        if (!variant)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "jis78", "jis83", "jis90", "jis04",
-                                                                 "simplified", "traditional", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                variant = TRUE;
-              }
-         }
-        if (!width)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "full-width"
-                                                                 "proportional-width", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                width = TRUE;
-              }
-         }
-        if (!ruby)
-          {
-            values[n_values] = _gtk_css_ident_value_try (parser, "ruby", NULL);
-            if (values[n_values])
-              {
-                n_values++;
-                ruby = TRUE;
-              }
-         }
-        if (old_n == n_values)
-          {
-            _gtk_css_parser_error (parser, "Not a valid value");
-            return NULL;
-          }
-      } while (!value_is_done_parsing (parser));
-
-      value = _gtk_css_array_value_new_from_array (values, n_values);
-    }
+  east_asian = 0;
+  do {
+    GtkCssFontVariantEastAsian parsed;
+
+    parsed = _gtk_css_font_variant_east_asian_try_parse_one (parser, east_asian);
+    if (parsed == 0 || parsed == east_asian)
+      {
+        _gtk_css_parser_error (parser, "Not a valid value");
+        return NULL;
+      }
+    east_asian = parsed;
+  } while (!value_is_done_parsing (parser));
+
+  value = _gtk_css_font_variant_east_asian_value_new (east_asian);
+  if (value == NULL)
+    _gtk_css_parser_error (parser, "Invalid combination of values");
 
   return value;
 }
 
-
 static GtkCssValue *
 box_shadow_value_parse (GtkCssStyleProperty *property,
                         GtkCssParser        *parser)
@@ -1274,7 +1131,7 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_font_kerning,
                                           NULL,
-                                          _gtk_css_ident_value_new ("auto"));
+                                          _gtk_css_font_kerning_value_new (GTK_CSS_FONT_KERNING_AUTO));
   gtk_css_style_property_register        ("font-variant-ligatures",
                                           GTK_CSS_PROPERTY_FONT_VARIANT_LIGATURES,
                                           G_TYPE_NONE,
@@ -1282,7 +1139,7 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_font_variant_ligatures,
                                           NULL,
-                                          _gtk_css_array_value_new (_gtk_css_ident_value_new ("normal")));
+                                          _gtk_css_font_variant_ligature_value_new 
(GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL));
   gtk_css_style_property_register        ("font-variant-position",
                                           GTK_CSS_PROPERTY_FONT_VARIANT_POSITION,
                                           G_TYPE_NONE,
@@ -1290,7 +1147,7 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_font_variant_position,
                                           NULL,
-                                          _gtk_css_ident_value_new ("normal"));
+                                          _gtk_css_font_variant_position_value_new 
(GTK_CSS_FONT_VARIANT_POSITION_NORMAL));
   gtk_css_style_property_register        ("font-variant-caps",
                                           GTK_CSS_PROPERTY_FONT_VARIANT_CAPS,
                                           G_TYPE_NONE,
@@ -1298,7 +1155,7 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_font_variant_caps,
                                           NULL,
-                                          _gtk_css_ident_value_new ("normal"));
+                                          _gtk_css_font_variant_caps_value_new 
(GTK_CSS_FONT_VARIANT_CAPS_NORMAL));
   gtk_css_style_property_register        ("font-variant-numeric",
                                           GTK_CSS_PROPERTY_FONT_VARIANT_NUMERIC,
                                           G_TYPE_NONE,
@@ -1306,7 +1163,7 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_font_variant_numeric,
                                           NULL,
-                                          _gtk_css_array_value_new (_gtk_css_ident_value_new ("normal")));
+                                          _gtk_css_font_variant_numeric_value_new 
(GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL));
   gtk_css_style_property_register        ("font-variant-alternates",
                                           GTK_CSS_PROPERTY_FONT_VARIANT_ALTERNATES,
                                           G_TYPE_NONE,
@@ -1314,7 +1171,7 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_font_variant_alternates,
                                           NULL,
-                                          _gtk_css_array_value_new (_gtk_css_ident_value_new ("normal")));
+                                          _gtk_css_font_variant_alternate_value_new 
(GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL));
   gtk_css_style_property_register        ("font-variant-east-asian",
                                           GTK_CSS_PROPERTY_FONT_VARIANT_EAST_ASIAN,
                                           G_TYPE_NONE,
@@ -1322,7 +1179,7 @@ _gtk_css_style_property_init_properties (void)
                                           GTK_CSS_AFFECTS_TEXT | GTK_CSS_AFFECTS_TEXT_ATTRS,
                                           parse_font_variant_east_asian,
                                           NULL,
-                                          _gtk_css_array_value_new (_gtk_css_ident_value_new ("normal")));
+                                          _gtk_css_font_variant_east_asian_value_new 
(GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL));
   gtk_css_style_property_register        ("text-shadow",
                                           GTK_CSS_PROPERTY_TEXT_SHADOW,
                                           G_TYPE_NONE,
diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h
index a56c345..cae2395 100644
--- a/gtk/gtkcsstypesprivate.h
+++ b/gtk/gtkcsstypesprivate.h
@@ -364,6 +364,71 @@ typedef enum /*< skip >*/ {
   GTK_CSS_MS,
 } GtkCssUnit;
 
+typedef enum /*< skip >*/ {
+  GTK_CSS_FONT_KERNING_AUTO,
+  GTK_CSS_FONT_KERNING_NORMAL,
+  GTK_CSS_FONT_KERNING_NONE
+} GtkCssFontKerning;
+
+typedef enum /*< skip >*/ {
+  GTK_CSS_FONT_VARIANT_LIGATURE_NORMAL                     = 1 << 0,
+  GTK_CSS_FONT_VARIANT_LIGATURE_NONE                       = 1 << 1,
+  GTK_CSS_FONT_VARIANT_LIGATURE_COMMON_LIGATURES           = 1 << 2,
+  GTK_CSS_FONT_VARIANT_LIGATURE_NO_COMMON_LIGATURES        = 1 << 3,
+  GTK_CSS_FONT_VARIANT_LIGATURE_DISCRETIONARY_LIGATURES    = 1 << 4,
+  GTK_CSS_FONT_VARIANT_LIGATURE_NO_DISCRETIONARY_LIGATURES = 1 << 5,
+  GTK_CSS_FONT_VARIANT_LIGATURE_HISTORICAL_LIGATURES       = 1 << 6,
+  GTK_CSS_FONT_VARIANT_LIGATURE_NO_HISTORICAL_LIGATURES    = 1 << 7,
+  GTK_CSS_FONT_VARIANT_LIGATURE_CONTEXTUAL                 = 1 << 8,
+  GTK_CSS_FONT_VARIANT_LIGATURE_NO_CONTEXTUAL              = 1 << 9
+} GtkCssFontVariantLigature;
+
+typedef enum /*< skip >*/ {
+  GTK_CSS_FONT_VARIANT_POSITION_NORMAL,
+  GTK_CSS_FONT_VARIANT_POSITION_SUB,
+  GTK_CSS_FONT_VARIANT_POSITION_SUPER
+} GtkCssFontVariantPosition;
+
+typedef enum /*< skip >*/ {
+  GTK_CSS_FONT_VARIANT_NUMERIC_NORMAL             = 1 << 0,
+  GTK_CSS_FONT_VARIANT_NUMERIC_LINING_NUMS        = 1 << 1,
+  GTK_CSS_FONT_VARIANT_NUMERIC_OLDSTYLE_NUMS      = 1 << 2,
+  GTK_CSS_FONT_VARIANT_NUMERIC_PROPORTIONAL_NUMS  = 1 << 3,
+  GTK_CSS_FONT_VARIANT_NUMERIC_TABULAR_NUMS       = 1 << 4,
+  GTK_CSS_FONT_VARIANT_NUMERIC_DIAGONAL_FRACTIONS = 1 << 5,
+  GTK_CSS_FONT_VARIANT_NUMERIC_STACKED_FRACTIONS  = 1 << 6,
+  GTK_CSS_FONT_VARIANT_NUMERIC_ORDINAL            = 1 << 7,
+  GTK_CSS_FONT_VARIANT_NUMERIC_SLASHED_ZERO       = 1 << 8
+} GtkCssFontVariantNumeric;
+
+typedef enum /*< skip >*/ {
+  GTK_CSS_FONT_VARIANT_CAPS_NORMAL,
+  GTK_CSS_FONT_VARIANT_CAPS_SMALL_CAPS,
+  GTK_CSS_FONT_VARIANT_CAPS_ALL_SMALL_CAPS,
+  GTK_CSS_FONT_VARIANT_CAPS_PETITE_CAPS,
+  GTK_CSS_FONT_VARIANT_CAPS_ALL_PETITE_CAPS,
+  GTK_CSS_FONT_VARIANT_CAPS_UNICASE,
+  GTK_CSS_FONT_VARIANT_CAPS_TITLING_CAPS
+} GtkCssFontVariantCaps;
+
+typedef enum /*< skip >*/ {
+  GTK_CSS_FONT_VARIANT_ALTERNATE_NORMAL,
+  GTK_CSS_FONT_VARIANT_ALTERNATE_HISTORICAL_FORMS
+} GtkCssFontVariantAlternate;
+
+typedef enum /*< skip >*/ {
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_NORMAL       = 1 << 0,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS78        = 1 << 1,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS83        = 1 << 2,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS90        = 1 << 3,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_JIS04        = 1 << 4,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_SIMPLIFIED   = 1 << 5,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_TRADITIONAL  = 1 << 6,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_FULL_WIDTH   = 1 << 7,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_PROPORTIONAL = 1 << 8,
+  GTK_CSS_FONT_VARIANT_EAST_ASIAN_RUBY         = 1 << 9
+} GtkCssFontVariantEastAsian;
+
 cairo_operator_t        _gtk_css_blend_mode_get_operator         (GskBlendMode       mode);
 
 GtkCssChange            _gtk_css_change_for_sibling              (GtkCssChange       match);


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