From 87eeb1bdfbf3407ca36db03740b91423c99e1032 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 27 Mar 2016 07:41:24 +0200 Subject: [PATCH] cssimage: Add token parser for linear-gradient This requires refactoring of gtk_css_token_source_consume_function() to allow a single call to the parse_args function to consume multiple arguments. Because the first argument to linear-gradient() is the optional direction, we need to indicate that we skipped it. So the parse function returns 2 in that case. This way we can set the minimum required arguments to 3, while still allowing linear-gradient(red, blue); which is equivalent to linear-gradient(to bottom, red, blue); --- gtk/gtkcsseasevalue.c | 18 ++--- gtk/gtkcssimageicontheme.c | 6 +- gtk/gtkcssimagelinear.c | 125 +++++++++++++++++++++++++++++++++ gtk/gtkcssimagescaled.c | 6 +- gtk/gtkcsstokensource.c | 11 +-- gtk/gtkcsstokensourceprivate.h | 2 +- gtk/gtkcsstransformvalue.c | 61 +++++++++------- 7 files changed, 183 insertions(+), 46 deletions(-) diff --git a/gtk/gtkcsseasevalue.c b/gtk/gtkcsseasevalue.c index b342b4b32d..72f7a3775c 100644 --- a/gtk/gtkcsseasevalue.c +++ b/gtk/gtkcsseasevalue.c @@ -327,7 +327,7 @@ _gtk_css_ease_value_parse (GtkCssParser *parser) return NULL; } -static gboolean +static guint token_parse_cubic_bezier (GtkCssTokenSource *source, guint n, gpointer data) @@ -342,13 +342,13 @@ token_parse_cubic_bezier (GtkCssTokenSource *source, (numbers[n] < 0 || numbers[n] > 1.0)) { gtk_css_token_source_error (source, "Value %g out of range. Must be from 0.0 to 1.0", numbers[n]); - return FALSE; + return 0; } - return TRUE; + return 1; } -static gboolean +static guint token_parse_steps (GtkCssTokenSource *source, guint nth_argument, gpointer data) @@ -363,17 +363,17 @@ token_parse_steps (GtkCssTokenSource *source, { gtk_css_token_source_error (source, "Expected a positive integer for number of steps"); gtk_css_token_source_consume_all (source); - return FALSE; + return 0; } else if (token->number.number <= 0) { gtk_css_token_source_error (source, "Number of steps must be greater than 0"); gtk_css_token_source_consume_all (source); - return FALSE; + return 0; } value->u.steps.steps = token->number.number; gtk_css_token_source_consume_token (source); - return TRUE; + return 1; } else { @@ -385,10 +385,10 @@ token_parse_steps (GtkCssTokenSource *source, { gtk_css_token_source_error (source, "Only allowed values are 'start' and 'end'"); gtk_css_token_source_consume_all (source); - return FALSE; + return 0; } gtk_css_token_source_consume_token (source); - return TRUE; + return 1; } } diff --git a/gtk/gtkcssimageicontheme.c b/gtk/gtkcssimageicontheme.c index 520ec58325..46132185ab 100644 --- a/gtk/gtkcssimageicontheme.c +++ b/gtk/gtkcssimageicontheme.c @@ -117,7 +117,7 @@ gtk_css_image_icon_theme_parse (GtkCssImage *image, return TRUE; } -static gboolean +static guint token_parse_arg (GtkCssTokenSource *source, guint arg, gpointer data) @@ -130,13 +130,13 @@ token_parse_arg (GtkCssTokenSource *source, { gtk_css_token_source_error (source, "Expected a string for the icon name"); gtk_css_token_source_consume_all (source); - return FALSE; + return 0; } icon_theme->name = g_strdup (token->string.string); gtk_css_token_source_consume_token (source); - return TRUE; + return 1; } static gboolean diff --git a/gtk/gtkcssimagelinear.c b/gtk/gtkcssimagelinear.c index b4a53f5633..a3144ae1b9 100644 --- a/gtk/gtkcssimagelinear.c +++ b/gtk/gtkcssimagelinear.c @@ -361,6 +361,130 @@ gtk_css_image_linear_parse (GtkCssImage *image, return TRUE; } +static guint +gtk_css_image_linear_token_parse_argument (GtkCssTokenSource *source, + guint arg, + gpointer data) +{ + GtkCssImageLinear *linear = data; + GtkCssImageLinearColorStop stop; + const GtkCssToken *token; + + if (arg == 0) + { + token = gtk_css_token_source_get_token (source); + + if (gtk_css_token_is_ident (token, "to")) + { + static const struct { + const char *name; + guint value; + guint optional_index[2]; + } sides[] = { + { "top", 1 << GTK_CSS_TOP, { 2, 3 } }, + { "bottom", 1 << GTK_CSS_BOTTOM, { 2, 3 } }, + { "left", 1 << GTK_CSS_LEFT, { 0, 1 } }, + { "right", 1 << GTK_CSS_RIGHT, { 0, 1 } } + }; + guint i, j; + gtk_css_token_source_consume_token (source); + + token = gtk_css_token_source_get_token (source); + for (i = 0; i < G_N_ELEMENTS (sides); i++) + { + if (!gtk_css_token_is_ident (token, sides[i].name)) + continue; + + linear->side = sides[i].value; + gtk_css_token_source_consume_token (source); + + token = gtk_css_token_source_get_token (source); + for (j = 0; j < G_N_ELEMENTS (sides[i].optional_index); j++) + { + guint idx = sides[i].optional_index[j]; + if (!gtk_css_token_is_ident (token, sides[idx].name)) + continue; + + linear->side = sides[idx].value; + gtk_css_token_source_consume_token (source); + break; + } + + return 1; + } + + gtk_css_token_source_error (source, "Expected a direction"); + gtk_css_token_source_consume_all (source); + return 0; + } + else if (!gtk_css_color_value_check_token (token)) + { + /* We check for !color here so the error message is "expected angle" + * for nonsense values */ + linear->angle = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE); + if (linear->angle == NULL) + return 0; + return 1; + } + + linear->side = 1 << GTK_CSS_BOTTOM; + } + + stop.color = gtk_css_color_value_token_parse (source); + if (stop.color == NULL) + return 0; + + token = gtk_css_token_source_get_token (source); + if (gtk_css_number_value_check_token (token)) + { + stop.offset = gtk_css_number_value_token_parse (source, + GTK_CSS_PARSE_PERCENT + | GTK_CSS_PARSE_LENGTH); + if (stop.offset == NULL) + { + _gtk_css_value_unref (stop.color); + return FALSE; + } + } + else + { + stop.offset = NULL; + } + + g_array_append_val (linear->stops, stop); + /* We consume the optional side argument here, too. */ + return arg == 0 ? 2 : 1; +} + +static gboolean +gtk_css_image_linear_token_parse (GtkCssImage *image, + GtkCssTokenSource *source) +{ + GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image); + const GtkCssToken *token; + + token = gtk_css_token_source_get_token (source); + if (gtk_css_token_is_function (token, "linear-gradient")) + { + /* nothing to do here */ + } + else if (gtk_css_token_is_function (token, "repeating-linear-gradient")) + { + linear->repeating = TRUE; + } + else + { + gtk_css_token_source_error (source, "Expected 'linear-gradient('"); + gtk_css_token_source_consume_all (source); + return FALSE; + } + + return gtk_css_token_source_consume_function (source, + 3, G_MAXUINT, + gtk_css_image_linear_token_parse_argument, + image); +} + static void gtk_css_image_linear_print (GtkCssImage *image, GString *string) @@ -598,6 +722,7 @@ _gtk_css_image_linear_class_init (GtkCssImageLinearClass *klass) image_class->draw = gtk_css_image_linear_draw; image_class->parse = gtk_css_image_linear_parse; + image_class->token_parse = gtk_css_image_linear_token_parse; image_class->print = gtk_css_image_linear_print; image_class->compute = gtk_css_image_linear_compute; image_class->equal = gtk_css_image_linear_equal; diff --git a/gtk/gtkcssimagescaled.c b/gtk/gtkcssimagescaled.c index 1c7add55e0..afa78c8e14 100644 --- a/gtk/gtkcssimagescaled.c +++ b/gtk/gtkcssimagescaled.c @@ -180,7 +180,7 @@ gtk_css_image_scaled_parse (GtkCssImage *image, return TRUE; } -static gboolean +static guint token_parse_arg (GtkCssTokenSource *source, guint arg, gpointer data) @@ -190,11 +190,11 @@ token_parse_arg (GtkCssTokenSource *source, image = gtk_css_image_new_token_parse (source); if (image == NULL) - return FALSE; + return 0; g_ptr_array_add (images, image); - return TRUE; + return 1; } static gboolean diff --git a/gtk/gtkcsstokensource.c b/gtk/gtkcsstokensource.c index ef2435decd..994086f851 100644 --- a/gtk/gtkcsstokensource.c +++ b/gtk/gtkcsstokensource.c @@ -343,7 +343,7 @@ gboolean gtk_css_token_source_consume_function (GtkCssTokenSource *source, guint min_args, guint max_args, - gboolean (* parse_func) (GtkCssTokenSource *, guint, gpointer), + guint (* parse_func) (GtkCssTokenSource *, guint, gpointer), gpointer data) { const GtkCssToken *token; @@ -358,17 +358,20 @@ gtk_css_token_source_consume_function (GtkCssTokenSource *source, gtk_css_token_source_consume_token (source); func_source = gtk_css_token_source_new_for_part (source, GTK_CSS_TOKEN_CLOSE_PARENS); - for (arg = 0; arg < max_args; arg++) + arg = 0; + while (arg < max_args) { - if (!parse_func (func_source, arg, data)) + guint parse_args = parse_func (func_source, arg, data); + if (parse_args == 0) { gtk_css_token_source_consume_all (func_source); break; } + arg += parse_args; token = gtk_css_token_source_get_token (func_source); if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF)) { - if (arg + 1 < min_args) + if (arg < min_args) { gtk_css_token_source_error (source, "%s() requires at least %u arguments", function_name, min_args); gtk_css_token_source_consume_all (source); diff --git a/gtk/gtkcsstokensourceprivate.h b/gtk/gtkcsstokensourceprivate.h index def15bcebd..6748cb5512 100644 --- a/gtk/gtkcsstokensourceprivate.h +++ b/gtk/gtkcsstokensourceprivate.h @@ -70,7 +70,7 @@ char * gtk_css_token_source_consume_to_string (GtkCssTokenSour gboolean gtk_css_token_source_consume_function (GtkCssTokenSource *source, guint min_args, guint max_args, - gboolean (* parse_func) (GtkCssTokenSource *, guint, gpointer), + guint (* parse_func) (GtkCssTokenSource *, guint, gpointer), gpointer data); gboolean gtk_css_token_source_consume_number (GtkCssTokenSource *source, double *number); diff --git a/gtk/gtkcsstransformvalue.c b/gtk/gtkcsstransformvalue.c index b456af8d3d..b9dc3f1954 100644 --- a/gtk/gtkcsstransformvalue.c +++ b/gtk/gtkcsstransformvalue.c @@ -1015,7 +1015,7 @@ _gtk_css_transform_value_parse (GtkCssParser *parser) return value; } -static gboolean +static guint token_parse_matrix (GtkCssTokenSource *source, guint n, gpointer data) @@ -1025,24 +1025,24 @@ token_parse_matrix (GtkCssTokenSource *source, switch (n) { case 0: - return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.xx); + return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.xx) ? 1 : 0; case 1: - return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.xy); + return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.xy) ? 1 : 0; case 2: - return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.x0); + return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.x0) ? 1 : 0; case 3: - return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.yx); + return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.yx) ? 1 : 0; case 4: - return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.yy); + return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.yy) ? 1 : 0; case 5: - return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.y0); + return gtk_css_token_source_consume_number (source, &transform->matrix.matrix.y0) ? 1 : 0; default: g_assert_not_reached (); - return FALSE; + return 0; } } -static gboolean +static guint token_parse_translate (GtkCssTokenSource *source, guint n, gpointer data) @@ -1053,7 +1053,7 @@ token_parse_translate (GtkCssTokenSource *source, { transform->translate.x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_LENGTH); if (transform->translate.x == NULL) - return FALSE; + return 0; transform->translate.y = _gtk_css_number_value_new (0, GTK_CSS_PX); } else if (n == 1) @@ -1061,16 +1061,16 @@ token_parse_translate (GtkCssTokenSource *source, _gtk_css_value_unref (transform->translate.y); transform->translate.y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_LENGTH); if (transform->translate.y == NULL) - return FALSE; + return 0; } else { g_assert_not_reached (); } - return TRUE; + return 1; } -static gboolean +static guint token_parse_length (GtkCssTokenSource *source, guint n, gpointer data) @@ -1078,10 +1078,13 @@ token_parse_length (GtkCssTokenSource *source, GtkCssValue **value = data; *value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_LENGTH); - return *value != NULL; + if (*value == NULL) + return 0; + + return 1; } -static gboolean +static guint token_parse_scale (GtkCssTokenSource *source, guint n, gpointer data) @@ -1092,7 +1095,7 @@ token_parse_scale (GtkCssTokenSource *source, { transform->scale.x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_NUMBER); if (transform->scale.x == NULL) - return FALSE; + return 0; transform->scale.y = _gtk_css_value_ref (transform->scale.x); } else if (n == 1) @@ -1100,16 +1103,16 @@ token_parse_scale (GtkCssTokenSource *source, _gtk_css_value_unref (transform->scale.y); transform->scale.y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_NUMBER); if (transform->scale.y == NULL) - return FALSE; + return 0; } else { g_assert_not_reached (); } - return TRUE; + return 1; } -static gboolean +static guint token_parse_number (GtkCssTokenSource *source, guint n, gpointer data) @@ -1117,10 +1120,13 @@ token_parse_number (GtkCssTokenSource *source, GtkCssValue **value = data; *value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_NUMBER); - return *value != NULL; + if (*value == NULL) + return 0; + + return 1; } -static gboolean +static guint token_parse_angle (GtkCssTokenSource *source, guint n, gpointer data) @@ -1128,10 +1134,13 @@ token_parse_angle (GtkCssTokenSource *source, GtkCssValue **value = data; *value = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE); - return *value != NULL; + if (*value == NULL) + return 0; + + return 1; } -static gboolean +static guint token_parse_skew (GtkCssTokenSource *source, guint n, gpointer data) @@ -1142,7 +1151,7 @@ token_parse_skew (GtkCssTokenSource *source, { transform->skew.x = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE); if (transform->skew.x == NULL) - return FALSE; + return 0; transform->skew.y = _gtk_css_number_value_new (0, GTK_CSS_PX); } else if (n == 1) @@ -1150,13 +1159,13 @@ token_parse_skew (GtkCssTokenSource *source, _gtk_css_value_unref (transform->skew.y); transform->skew.y = gtk_css_number_value_token_parse (source, GTK_CSS_PARSE_ANGLE); if (transform->skew.y == NULL) - return FALSE; + return 0; } else { g_assert_not_reached (); } - return TRUE; + return 1; } GtkCssValue *