From: Benjamin Otte Date: Sun, 29 May 2011 05:03:59 +0000 (+0200) Subject: css: Make font property a shorthand X-Git-Url: http://pileus.org/git/?a=commitdiff_plain;h=0d253b67f41fd9f8956f763dda275cfa8353cd7f;p=~andy%2Fgtk 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. --- diff --git a/gtk/gtkcssparser.c b/gtk/gtkcssparser.c index 80544515e..1b2710d04 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 2e67a4757..4be5b7516 100644 --- a/gtk/gtkcssprovider.c +++ b/gtk/gtkcssprovider.c @@ -725,6 +725,36 @@ * [transparent|color]{1,4} * * + * font-family + * @family [, @family]* + * #gchararray + * font-family: Sans, Arial; + * + * + * font-style + * [normal|oblique|italic] + * #PANGO_TYPE_STYLE + * font-style: italic; + * + * + * font-variant + * [normal|small-caps] + * #PANGO_TYPE_VARIANT + * font-variant: normal; + * + * + * font-weight + * [normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900] + * #PANGO_TYPE_WEIGHT + * font-weight: bold; + * + * + * font-size + * Font size in point + * #gint + * font-size: 13; + * + * * font * @family [@style] [@size] * #PangoFontDescription diff --git a/gtk/gtkstylecontext.c b/gtk/gtkstylecontext.c index 762f889e8..9ac9b47b6 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 27cc9b26e..f3c19980d 100644 --- a/gtk/gtkstyleproperty.c +++ b/gtk/gtkstyleproperty.c @@ -22,6 +22,7 @@ #include "gtkstylepropertyprivate.h" #include +#include #include #include @@ -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, @@ -1754,6 +1823,119 @@ pack_border_radius (GValue *value, g_free (top_left); } +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 (¶meter[n].value, G_TYPE_STRV); + g_value_take_boxed (¶meter[n].value, + g_ptr_array_free (strv, FALSE)); + n++; + } + + if (mask & PANGO_FONT_MASK_STYLE) + { + parameter[n].name = "font-style"; + g_value_init (¶meter[n].value, PANGO_TYPE_STYLE); + g_value_set_enum (¶meter[n].value, + pango_font_description_get_style (description)); + n++; + } + + if (mask & PANGO_FONT_MASK_VARIANT) + { + parameter[n].name = "font-variant"; + g_value_init (¶meter[n].value, PANGO_TYPE_VARIANT); + g_value_set_enum (¶meter[n].value, + pango_font_description_get_variant (description)); + n++; + } + + if (mask & PANGO_FONT_MASK_WEIGHT) + { + parameter[n].name = "font-weight"; + g_value_init (¶meter[n].value, PANGO_TYPE_WEIGHT); + g_value_set_enum (¶meter[n].value, + pango_font_description_get_weight (description)); + n++; + } + + if (mask & PANGO_FONT_MASK_SIZE) + { + parameter[n].name = "font-size"; + g_value_init (¶meter[n].value, G_TYPE_DOUBLE); + g_value_set_double (¶meter[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);