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);
This commit is contained in:
Benjamin Otte
2016-03-27 07:41:24 +02:00
parent fabc1f633d
commit 87eeb1bdfb
7 changed files with 183 additions and 46 deletions

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 *