diff --git a/gtk/Makefile.am b/gtk/Makefile.am index 01ea4cac1c..062b99916b 100644 --- a/gtk/Makefile.am +++ b/gtk/Makefile.am @@ -425,6 +425,7 @@ gtk_private_h_sources = \ gtkcontainerprivate.h \ gtkcssarrayvalueprivate.h \ gtkcssbgsizevalueprivate.h \ + gtkcssbordervalueprivate.h \ gtkcsscomputedvaluesprivate.h \ gtkcsscornervalueprivate.h \ gtkcsscustompropertyprivate.h \ @@ -638,6 +639,7 @@ gtk_base_c_sources = \ gtkcontainer.c \ gtkcssarrayvalue.c \ gtkcssbgsizevalue.c \ + gtkcssbordervalue.c \ gtkcsscomputedvalues.c \ gtkcsscornervalue.c \ gtkcsscustomproperty.c \ diff --git a/gtk/gtkborderimage.c b/gtk/gtkborderimage.c index 934786075c..f75d7e0e4e 100644 --- a/gtk/gtkborderimage.c +++ b/gtk/gtkborderimage.c @@ -25,7 +25,9 @@ #include #include "gtkborderimageprivate.h" +#include "gtkcssbordervalueprivate.h" #include "gtkcssimagevalueprivate.h" +#include "gtkcssnumbervalueprivate.h" #include "gtkcssrepeatvalueprivate.h" #include "gtkstylepropertiesprivate.h" #include "gtkthemingengineprivate.h" @@ -45,7 +47,7 @@ _gtk_border_image_init (GtkBorderImage *image, if (image->source == NULL) return FALSE; - image->slice = *(GtkBorder *) _gtk_css_value_get_boxed (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE)); + image->slice = _gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE); width = _gtk_css_value_get_boxed (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH)); if (width) { @@ -254,12 +256,12 @@ _gtk_border_image_render (GtkBorderImage *image, gtk_border_image_compute_slice_size (horizontal_slice, source_width, - image->slice.left, - image->slice.right); + _gtk_css_number_value_get (_gtk_css_border_value_get_left (image->slice), source_width), + _gtk_css_number_value_get (_gtk_css_border_value_get_right (image->slice), source_width)); gtk_border_image_compute_slice_size (vertical_slice, source_height, - image->slice.top, - image->slice.bottom); + _gtk_css_number_value_get (_gtk_css_border_value_get_top (image->slice), source_height), + _gtk_css_number_value_get (_gtk_css_border_value_get_bottom (image->slice), source_height)); gtk_border_image_compute_border_size (horizontal_border, x, width, diff --git a/gtk/gtkborderimageprivate.h b/gtk/gtkborderimageprivate.h index c77de04d97..f57149ccfe 100644 --- a/gtk/gtkborderimageprivate.h +++ b/gtk/gtkborderimageprivate.h @@ -34,7 +34,7 @@ typedef struct _GtkBorderImage GtkBorderImage; struct _GtkBorderImage { GtkCssImage *source; - GtkBorder slice; + GtkCssValue *slice; gboolean has_width; GtkBorder width; GtkCssValue *repeat; diff --git a/gtk/gtkcssbordervalue.c b/gtk/gtkcssbordervalue.c new file mode 100644 index 0000000000..92ae98a9c6 --- /dev/null +++ b/gtk/gtkcssbordervalue.c @@ -0,0 +1,235 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 2011 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkcssbordervalueprivate.h" + +#include "gtkcssnumbervalueprivate.h" + +struct _GtkCssValue { + GTK_CSS_VALUE_BASE + guint fill :1; + GtkCssValue *values[4]; +}; + +static void +gtk_css_value_border_free (GtkCssValue *value) +{ + guint i; + + for (i = 0; i < 4; i++) + { + if (value->values[i]) + _gtk_css_value_unref (value->values[i]); + } + + g_slice_free (GtkCssValue, value); +} + +static gboolean +gtk_css_value_border_equal (const GtkCssValue *value1, + const GtkCssValue *value2) +{ + guint i; + + if (value1->fill != value2->fill) + return FALSE; + + for (i = 0; i < 4; i++) + { + if (!_gtk_css_value_equal0 (value1->values[i], value2->values[i])) + return FALSE; + } + + return TRUE; +} + +static GtkCssValue * +gtk_css_value_border_transition (GtkCssValue *start, + GtkCssValue *end, + double progress) +{ + return NULL; +} + +static void +gtk_css_value_border_print (const GtkCssValue *value, + GString *string) +{ + guint i, n; + + if (!_gtk_css_value_equal0 (value->values[GTK_CSS_RIGHT], value->values[GTK_CSS_LEFT])) + n = 4; + else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_BOTTOM])) + n = 3; + else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_RIGHT])) + n = 2; + else + n = 1; + + for (i = 0; i < n; i++) + { + if (i > 0) + g_string_append_c (string, ' '); + + if (value->values[i] == NULL) + g_string_append (string, "auto"); + else + _gtk_css_value_print (value->values[i], string); + } + + if (value->fill) + g_string_append (string, " fill"); +} + +static const GtkCssValueClass GTK_CSS_VALUE_BORDER = { + gtk_css_value_border_free, + gtk_css_value_border_equal, + gtk_css_value_border_transition, + gtk_css_value_border_print +}; + +GtkCssValue * +_gtk_css_border_value_new (GtkCssValue *top, + GtkCssValue *right, + GtkCssValue *bottom, + GtkCssValue *left) +{ + GtkCssValue *result; + + result = _gtk_css_value_new (GtkCssValue, >K_CSS_VALUE_BORDER); + result->values[GTK_CSS_TOP] = top; + result->values[GTK_CSS_RIGHT] = right; + result->values[GTK_CSS_BOTTOM] = bottom; + result->values[GTK_CSS_LEFT] = left; + + return result; +} + +GtkCssValue * +_gtk_css_border_value_parse (GtkCssParser *parser, + GtkCssNumberParseFlags flags, + gboolean allow_auto, + gboolean allow_fill) +{ + GtkCssValue *result; + guint i; + + result = _gtk_css_border_value_new (NULL, NULL, NULL, NULL); + + if (allow_fill) + result->fill = _gtk_css_parser_try (parser, "fill", TRUE); + + for (i = 0; i < 4; i++) + { + if (allow_auto && _gtk_css_parser_try (parser, "auto", TRUE)) + continue; + + if (!_gtk_css_parser_has_number (parser)) + break; + + result->values[i] = _gtk_css_number_value_parse (parser, flags); + if (result->values[i] == NULL) + { + _gtk_css_value_unref (result); + return NULL; + } + } + + if (i == 0) + { + _gtk_css_parser_error (parser, "Expected a number"); + _gtk_css_value_unref (result); + return NULL; + } + + if (allow_fill && !result->fill) + result->fill = _gtk_css_parser_try (parser, "fill", TRUE); + + for (; i < 4; i++) + { + if (result->values[(i - 1) >> 1]) + result->values[i] = _gtk_css_value_ref (result->values[(i - 1) >> 1]); + } + + return result; +} + +GtkCssValue * +_gtk_css_border_value_get_top (const GtkCssValue *value) +{ + g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); + + return value->values[GTK_CSS_TOP]; +} + +GtkCssValue * +_gtk_css_border_value_get_right (const GtkCssValue *value) +{ + g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); + + return value->values[GTK_CSS_RIGHT]; +} + +GtkCssValue * +_gtk_css_border_value_get_bottom (const GtkCssValue *value) +{ + g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); + + return value->values[GTK_CSS_BOTTOM]; +} + +GtkCssValue * +_gtk_css_border_value_get_left (const GtkCssValue *value) +{ + g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); + + return value->values[GTK_CSS_LEFT]; +} + +GtkCssValue * +_gtk_css_border_value_compute (GtkCssValue *value, + GtkStyleContext *context) +{ + GtkCssValue *computed; + gboolean changed = FALSE; + guint i; + + g_return_val_if_fail (value->class == >K_CSS_VALUE_BORDER, NULL); + + computed = _gtk_css_border_value_new (NULL, NULL, NULL, NULL); + computed->fill = value->fill; + + for (i = 0; i < 4; i++) + { + if (value->values[i]) + { + computed->values[i] = _gtk_css_number_value_compute (value->values[i], context); + changed |= (computed->values[i] != value->values[i]); + } + } + + if (!changed) + { + _gtk_css_value_unref (computed); + return _gtk_css_value_ref (value); + } + + return computed; +} + diff --git a/gtk/gtkcssbordervalueprivate.h b/gtk/gtkcssbordervalueprivate.h new file mode 100644 index 0000000000..458462b615 --- /dev/null +++ b/gtk/gtkcssbordervalueprivate.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2012 Red Hat Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Alexander Larsson + */ + +#ifndef __GTK_CSS_BORDER_VALUE_PRIVATE_H__ +#define __GTK_CSS_BORDER_VALUE_PRIVATE_H__ + +#include "gtkcssparserprivate.h" +#include "gtkcssvalueprivate.h" + +G_BEGIN_DECLS + +GtkCssValue * _gtk_css_border_value_new (GtkCssValue *top, + GtkCssValue *right, + GtkCssValue *bottom, + GtkCssValue *left); +GtkCssValue * _gtk_css_border_value_parse (GtkCssParser *parser, + GtkCssNumberParseFlags flags, + gboolean allow_auto, + gboolean allow_fill); + +GtkCssValue * _gtk_css_border_value_get_top (const GtkCssValue *value); +GtkCssValue * _gtk_css_border_value_get_right (const GtkCssValue *value); +GtkCssValue * _gtk_css_border_value_get_bottom (const GtkCssValue *value); +GtkCssValue * _gtk_css_border_value_get_left (const GtkCssValue *value); + +GtkCssValue * _gtk_css_border_value_compute (GtkCssValue *border, + GtkStyleContext *context); + + +G_END_DECLS + +#endif /* __GTK_CSS_BORDER_VALUE_PRIVATE_H__ */ diff --git a/gtk/gtkcssshorthandpropertyimpl.c b/gtk/gtkcssshorthandpropertyimpl.c index f93859cba2..3a26a28afd 100644 --- a/gtk/gtkcssshorthandpropertyimpl.c +++ b/gtk/gtkcssshorthandpropertyimpl.c @@ -25,6 +25,7 @@ #include #include "gtkcssarrayvalueprivate.h" +#include "gtkcssbordervalueprivate.h" #include "gtkcsscornervalueprivate.h" #include "gtkcssenumvalueprivate.h" #include "gtkcssimageprivate.h" @@ -304,16 +305,19 @@ parse_border_image (GtkCssShorthandProperty *shorthand, } else if (values[1] == NULL) { - GValue value = G_VALUE_INIT; - - g_value_init (&value, GTK_TYPE_BORDER); - if (!_gtk_css_style_parse_value (&value, parser, base)) + values[1] = _gtk_css_border_value_parse (parser, + GTK_CSS_PARSE_PERCENT + | GTK_CSS_PARSE_NUMBER + | GTK_CSS_POSITIVE_ONLY, + FALSE, + TRUE); + if (values[1] == NULL) return FALSE; - values[1] = _gtk_css_value_new_from_gvalue (&value); - g_value_unset (&value); if (_gtk_css_parser_try (parser, "/", TRUE)) { + GValue value = G_VALUE_INIT; + g_value_init (&value, GTK_TYPE_BORDER); if (!_gtk_css_style_parse_value (&value, parser, base)) return FALSE; diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c index e5b3461c8d..530a85ec3c 100644 --- a/gtk/gtkcssstylepropertyimpl.c +++ b/gtk/gtkcssstylepropertyimpl.c @@ -42,6 +42,7 @@ #include "gtkbindings.h" #include "gtkcssarrayvalueprivate.h" #include "gtkcssbgsizevalueprivate.h" +#include "gtkcssbordervalueprivate.h" #include "gtkcsscornervalueprivate.h" #include "gtkcsseasevalueprivate.h" #include "gtkcssenginevalueprivate.h" @@ -159,6 +160,38 @@ assign_length_from_double (GtkCssStyleProperty *property, return _gtk_css_number_value_new (g_value_get_double (value), GTK_CSS_PX); } +static void +query_border (GtkCssStyleProperty *property, + const GtkCssValue *css_value, + GValue *value) +{ + GtkBorder border; + + g_value_init (value, GTK_TYPE_BORDER); + + border.top = round (_gtk_css_number_value_get (_gtk_css_border_value_get_top (css_value), 100)); + border.right = round (_gtk_css_number_value_get (_gtk_css_border_value_get_right (css_value), 100)); + border.bottom = round (_gtk_css_number_value_get (_gtk_css_border_value_get_bottom (css_value), 100)); + border.left = round (_gtk_css_number_value_get (_gtk_css_border_value_get_left (css_value), 100)); + + g_value_set_boxed (value, &border); +} + +static GtkCssValue * +assign_border (GtkCssStyleProperty *property, + const GValue *value) +{ + const GtkBorder *border = g_value_get_boxed (value); + + if (border == NULL) + return _gtk_css_value_ref (_gtk_css_style_property_get_initial_value (property)); + else + return _gtk_css_border_value_new (_gtk_css_number_value_new (border->top, GTK_CSS_PX), + _gtk_css_number_value_new (border->right, GTK_CSS_PX), + _gtk_css_number_value_new (border->bottom, GTK_CSS_PX), + _gtk_css_number_value_new (border->left, GTK_CSS_PX)); +} + static GtkCssValue * color_parse (GtkCssStyleProperty *property, GtkCssParser *parser, @@ -683,20 +716,12 @@ border_image_slice_parse (GtkCssStyleProperty *property, GtkCssParser *parser, GFile *base) { - GValue value = G_VALUE_INIT; - GtkCssValue *result; - - g_value_init (&value, GTK_TYPE_BORDER); - if (!_gtk_css_style_parse_value (&value, parser, base)) - { - g_value_unset (&value); - return NULL; - } - - result = _gtk_css_value_new_from_gvalue (&value); - g_value_unset (&value); - - return result; + return _gtk_css_border_value_parse (parser, + GTK_CSS_PARSE_PERCENT + | GTK_CSS_PARSE_NUMBER + | GTK_CSS_POSITIVE_ONLY, + FALSE, + TRUE); } static GtkCssValue * @@ -720,6 +745,14 @@ border_image_width_parse (GtkCssStyleProperty *property, return result; } +static GtkCssValue * +compute_border (GtkCssStyleProperty *property, + GtkStyleContext *context, + GtkCssValue *specified) +{ + return _gtk_css_border_value_compute (specified, context); +} + static GtkCssValue * transition_property_parse_one (GtkCssParser *parser) { @@ -942,8 +975,6 @@ gtk_symbolic_color_new_rgba (double red, void _gtk_css_style_property_init_properties (void) { - GtkBorder border_of_ones = { 1, 1, 1, 1 }; - /* Initialize "color" and "font-size" first, * so that when computing values later they are * done first. That way, 'currentColor' and font @@ -1492,18 +1523,20 @@ _gtk_css_style_property_init_properties (void) _gtk_css_border_repeat_value_new (GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH)); - /* XXX: The initial value is wrong, it should be 100% */ gtk_css_style_property_register ("border-image-slice", GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE, GTK_TYPE_BORDER, 0, border_image_slice_parse, NULL, + compute_border, + query_border, + assign_border, NULL, - query_simple, - assign_simple, - NULL, - _gtk_css_value_new_from_boxed (GTK_TYPE_BORDER, &border_of_ones)); + _gtk_css_border_value_new (_gtk_css_number_value_new (100, GTK_CSS_PERCENT), + _gtk_css_number_value_new (100, GTK_CSS_PERCENT), + _gtk_css_number_value_new (100, GTK_CSS_PERCENT), + _gtk_css_number_value_new (100, GTK_CSS_PERCENT))); gtk_css_style_property_register ("border-image-width", GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH, GTK_TYPE_BORDER, diff --git a/gtk/gtkcssvalue.c b/gtk/gtkcssvalue.c index 80ccd54585..477d7b1f0d 100644 --- a/gtk/gtkcssvalue.c +++ b/gtk/gtkcssvalue.c @@ -349,6 +349,19 @@ _gtk_css_value_equal (const GtkCssValue *value1, return value1->class->equal (value1, value2); } +gboolean +_gtk_css_value_equal0 (const GtkCssValue *value1, + const GtkCssValue *value2) +{ + if (value1 == NULL && value2 == NULL) + return TRUE; + + if (value1 == NULL || value2 == NULL) + return FALSE; + + return _gtk_css_value_equal (value1, value2); +} + GtkCssValue * _gtk_css_value_transition (GtkCssValue *start, GtkCssValue *end, diff --git a/gtk/gtkcssvalueprivate.h b/gtk/gtkcssvalueprivate.h index 0dc1f9af66..66453cc6a5 100644 --- a/gtk/gtkcssvalueprivate.h +++ b/gtk/gtkcssvalueprivate.h @@ -66,6 +66,8 @@ void _gtk_css_value_unref (GtkCssValue gboolean _gtk_css_value_equal (const GtkCssValue *value1, const GtkCssValue *value2); +gboolean _gtk_css_value_equal0 (const GtkCssValue *value1, + const GtkCssValue *value2); GtkCssValue *_gtk_css_value_transition (GtkCssValue *start, GtkCssValue *end, double progress);