[gtk+] css: Make font property a shorthand



commit 0d253b67f41fd9f8956f763dda275cfa8353cd7f
Author: Benjamin Otte <otte redhat com>
Date:   Sun May 29 07:03:59 2011 +0200

    css: Make font property a shorthand
    
    ... and implement the CSS font properties:
    - font-size
    - font-style
    - font-family
    - font-weight
    - font-variant
    
    This is the second try at this. The first was backed out previously due
    to bugginess. Let's hope this one survives a bit longer.
    
    Also makes the font-family CSS test work again.

 gtk/gtkcssparser.c     |    5 +-
 gtk/gtkcssprovider.c   |   30 ++++++
 gtk/gtkstylecontext.c  |   30 +++++-
 gtk/gtkstyleproperty.c |  245 +++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 302 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkcssparser.c b/gtk/gtkcssparser.c
index 8054451..1b2710d 100644
--- a/gtk/gtkcssparser.c
+++ b/gtk/gtkcssparser.c
@@ -386,7 +386,10 @@ _gtk_css_parser_read_string (GtkCssParser *parser)
   quote = *parser->data;
   
   if (quote != '"' && quote != '\'')
-    return NULL;
+    {
+      _gtk_css_parser_error (parser, "Expected a string.");
+      return NULL;
+    }
   
   parser->data++;
   str = g_string_new (NULL);
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 2e67a47..4be5b75 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -725,6 +725,36 @@
  *         <entry>[transparent|color]{1,4}</entry>
  *       </row>
  *       <row>
+ *         <entry>font-family</entry>
+ *         <entry>@family [, @family]*</entry>
+ *         <entry>#gchararray</entry>
+ *         <entry>font-family: Sans, Arial;</entry>
+ *       </row>
+ *       <row>
+ *         <entry>font-style</entry>
+ *         <entry>[normal|oblique|italic]</entry>
+ *         <entry>#PANGO_TYPE_STYLE</entry>
+ *         <entry>font-style: italic;</entry>
+ *       </row>
+ *       <row>
+ *         <entry>font-variant</entry>
+ *         <entry>[normal|small-caps]</entry>
+ *         <entry>#PANGO_TYPE_VARIANT</entry>
+ *         <entry>font-variant: normal;</entry>
+ *       </row>
+ *       <row>
+ *         <entry>font-weight</entry>
+ *         <entry>[normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900]</entry>
+ *         <entry>#PANGO_TYPE_WEIGHT</entry>
+ *         <entry>font-weight: bold;</entry>
+ *       </row>
+ *       <row>
+ *         <entry>font-size</entry>
+ *         <entry>Font size in point</entry>
+ *         <entry>#gint</entry>
+ *         <entry>font-size: 13;</entry>
+ *       </row>
+ *       <row>
  *         <entry>font</entry>
  *         <entry>@family [ style] [ size]</entry>
  *         <entry>#PangoFontDescription</entry>
diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c
index 762f889..9ac9b47 100644
--- a/gtk/gtkstylecontext.c
+++ b/gtk/gtkstylecontext.c
@@ -3562,7 +3562,8 @@ gtk_style_context_get_font (GtkStyleContext *context,
 {
   GtkStyleContextPrivate *priv;
   StyleData *data;
-  const GValue *value;
+  GHashTable *font_cache;
+  PangoFontDescription *description;
 
   g_return_val_if_fail (GTK_IS_STYLE_CONTEXT (context), NULL);
 
@@ -3570,12 +3571,31 @@ gtk_style_context_get_font (GtkStyleContext *context,
   g_return_val_if_fail (priv->widget_path != NULL, NULL);
 
   data = style_data_lookup (context);
-  value = _gtk_style_properties_peek_property (data->store, "font", state, NULL);
 
-  if (value)
-    return g_value_get_boxed (value);
+  /* Yuck, fonts are created on-demand but we don't return a ref.
+   * Do bad things to achieve this requirement */
+  font_cache = g_object_get_data (G_OBJECT (data->store), "font-cache-for-get_font");
+  if (font_cache)
+    {
+      description = g_hash_table_lookup (font_cache, GUINT_TO_POINTER (state));
+    }
+  else
+    {
+      font_cache = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) pango_font_description_free);
+      g_object_set_data_full (G_OBJECT (data->store),
+                              "font-cache-for-get_font",
+                              font_cache,
+                              (GDestroyNotify) g_hash_table_unref);
+      description = NULL;
+    }
 
-  return NULL;
+  if (description == NULL)
+    {
+      gtk_style_properties_get (data->store, state, "font", &description, NULL);
+      g_hash_table_insert (font_cache, GUINT_TO_POINTER (state), description);
+    }
+
+  return description;
 }
 
 static void
diff --git a/gtk/gtkstyleproperty.c b/gtk/gtkstyleproperty.c
index 27cc9b2..f3c1998 100644
--- a/gtk/gtkstyleproperty.c
+++ b/gtk/gtkstyleproperty.c
@@ -22,6 +22,7 @@
 #include "gtkstylepropertyprivate.h"
 
 #include <errno.h>
+#include <math.h>
 #include <stdlib.h>
 #include <string.h>
 
@@ -227,6 +228,74 @@ symbolic_color_value_print (const GValue *value,
     }
 }
 
+static gboolean
+font_family_parse (GtkCssParser *parser,
+                   GFile        *base,
+                   GValue       *value)
+{
+  GPtrArray *names;
+  char *name;
+
+  /* We don't special case generic families. Pango should do
+   * that for us */
+
+  names = g_ptr_array_new ();
+
+  do {
+    name = _gtk_css_parser_try_ident (parser, TRUE);
+    if (name)
+      {
+        GString *string = g_string_new (name);
+        g_free (name);
+        while ((name = _gtk_css_parser_try_ident (parser, TRUE)))
+          {
+            g_string_append_c (string, ' ');
+            g_string_append (string, name);
+            g_free (name);
+          }
+        name = g_string_free (string, FALSE);
+      }
+    else 
+      {
+        name = _gtk_css_parser_read_string (parser);
+        if (name == NULL)
+          {
+            g_ptr_array_free (names, TRUE);
+            return FALSE;
+          }
+      }
+
+    g_ptr_array_add (names, name);
+  } while (_gtk_css_parser_try (parser, ",", TRUE));
+
+  /* NULL-terminate array */
+  g_ptr_array_add (names, NULL);
+  g_value_set_boxed (value, g_ptr_array_free (names, FALSE));
+  return TRUE;
+}
+
+static void
+font_family_value_print (const GValue *value,
+                         GString      *string)
+{
+  const char **names = g_value_get_boxed (value);
+
+  if (names == NULL || *names == NULL)
+    {
+      g_string_append (string, "none");
+      return;
+    }
+
+  string_append_string (string, *names);
+  names++;
+  while (*names)
+    {
+      g_string_append (string, ", ");
+      string_append_string (string, *names);
+      names++;
+    }
+}
+
 static gboolean 
 font_description_value_parse (GtkCssParser *parser,
                               GFile        *base,
@@ -1755,6 +1824,119 @@ pack_border_radius (GValue             *value,
 }
 
 static GParameter *
+unpack_font_description (const GValue *value,
+                         guint        *n_params)
+{
+  GParameter *parameter = g_new0 (GParameter, 5);
+  PangoFontDescription *description;
+  PangoFontMask mask;
+  guint n;
+  
+  /* For backwards compat, we only unpack values that are indeed set.
+   * For strict CSS conformance we need to unpack all of them.
+   * Note that we do set all of them in the parse function, so it
+   * will not have effects when parsing CSS files. It will though
+   * for custom style providers.
+   */
+
+  description = g_value_get_boxed (value);
+  n = 0;
+
+  if (description)
+    mask = pango_font_description_get_set_fields (description);
+  else
+    mask = 0;
+
+  if (mask & PANGO_FONT_MASK_FAMILY)
+    {
+      GPtrArray *strv = g_ptr_array_new ();
+
+      g_ptr_array_add (strv, g_strdup (pango_font_description_get_family (description)));
+      g_ptr_array_add (strv, NULL);
+      parameter[n].name = "font-family";
+      g_value_init (&parameter[n].value, G_TYPE_STRV);
+      g_value_take_boxed (&parameter[n].value,
+                          g_ptr_array_free (strv, FALSE));
+      n++;
+    }
+
+  if (mask & PANGO_FONT_MASK_STYLE)
+    {
+      parameter[n].name = "font-style";
+      g_value_init (&parameter[n].value, PANGO_TYPE_STYLE);
+      g_value_set_enum (&parameter[n].value,
+                        pango_font_description_get_style (description));
+      n++;
+    }
+
+  if (mask & PANGO_FONT_MASK_VARIANT)
+    {
+      parameter[n].name = "font-variant";
+      g_value_init (&parameter[n].value, PANGO_TYPE_VARIANT);
+      g_value_set_enum (&parameter[n].value,
+                        pango_font_description_get_variant (description));
+      n++;
+    }
+
+  if (mask & PANGO_FONT_MASK_WEIGHT)
+    {
+      parameter[n].name = "font-weight";
+      g_value_init (&parameter[n].value, PANGO_TYPE_WEIGHT);
+      g_value_set_enum (&parameter[n].value,
+                        pango_font_description_get_weight (description));
+      n++;
+    }
+
+  if (mask & PANGO_FONT_MASK_SIZE)
+    {
+      parameter[n].name = "font-size";
+      g_value_init (&parameter[n].value, G_TYPE_DOUBLE);
+      g_value_set_double (&parameter[n].value,
+                          (double) pango_font_description_get_size (description) / PANGO_SCALE);
+      n++;
+    }
+
+  *n_params = n;
+
+  return parameter;
+}
+
+static void
+pack_font_description (GValue             *value,
+                       GtkStyleProperties *props,
+                       GtkStateFlags       state)
+{
+  PangoFontDescription *description;
+  char **families;
+  PangoStyle style;
+  PangoVariant variant;
+  PangoWeight weight;
+  double size;
+
+  gtk_style_properties_get (props,
+                            state,
+                            "font-family", &families,
+                            "font-style", &style,
+                            "font-variant", &variant,
+                            "font-weight", &weight,
+                            "font-size", &size,
+                            NULL);
+
+  description = pango_font_description_new ();
+  /* xxx: Can we set all the families here somehow? */
+  if (families)
+    pango_font_description_set_family (description, families[0]);
+  pango_font_description_set_size (description, round (size * PANGO_SCALE));
+  pango_font_description_set_style (description, style);
+  pango_font_description_set_variant (description, variant);
+  pango_font_description_set_weight (description, weight);
+
+  g_free (families);
+
+  g_value_take_boxed (value, description);
+}
+
+static GParameter *
 unpack_border_color (const GValue *value,
                      guint        *n_params)
 {
@@ -2220,14 +2402,73 @@ gtk_style_property_init (void)
                                                               "Background color",
                                                               GDK_TYPE_RGBA, 0));
 
+  _gtk_style_property_register           (g_param_spec_boxed ("font-family",
+                                                              "Font family",
+                                                              "Font family",
+                                                              G_TYPE_STRV, 0),
+                                          GTK_STYLE_PROPERTY_INHERIT,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          font_family_parse,
+                                          font_family_value_print,
+                                          NULL);
+  _gtk_style_property_register           (g_param_spec_enum ("font-style",
+                                                             "Font style",
+                                                             "Font style",
+                                                             PANGO_TYPE_STYLE,
+                                                             PANGO_STYLE_NORMAL, 0),
+                                          GTK_STYLE_PROPERTY_INHERIT,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL);
+  _gtk_style_property_register           (g_param_spec_enum ("font-variant",
+                                                             "Font variant",
+                                                             "Font variant",
+                                                             PANGO_TYPE_VARIANT,
+                                                             PANGO_VARIANT_NORMAL, 0),
+                                          GTK_STYLE_PROPERTY_INHERIT,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL);
+  /* xxx: need to parse this properly, ie parse the numbers */
+  _gtk_style_property_register           (g_param_spec_enum ("font-weight",
+                                                             "Font weight",
+                                                             "Font weight",
+                                                             PANGO_TYPE_WEIGHT,
+                                                             PANGO_WEIGHT_NORMAL, 0),
+                                          GTK_STYLE_PROPERTY_INHERIT,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL);
+  _gtk_style_property_register           (g_param_spec_double ("font-size",
+                                                               "Font size",
+                                                               "Font size",
+                                                               0, G_MAXDOUBLE, 0, 0),
+                                          GTK_STYLE_PROPERTY_INHERIT,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL,
+                                          NULL);
   _gtk_style_property_register           (g_param_spec_boxed ("font",
                                                               "Font Description",
                                                               "Font Description",
                                                               PANGO_TYPE_FONT_DESCRIPTION, 0),
                                           GTK_STYLE_PROPERTY_INHERIT,
                                           NULL,
-                                          NULL,
-                                          NULL,
+                                          unpack_font_description,
+                                          pack_font_description,
                                           font_description_value_parse,
                                           font_description_value_print,
                                           NULL);



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