mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 13:11:13 +00:00
css: Parse interpolation for linear gradients
Parse things like "in hsl hue longer". For details, see the CSS Images Module Level 4, https://www.w3.org/TR/css-images-4. Tests included. Gradient interpolation color spaces aren't supported for rendering yet.
This commit is contained in:
parent
f9cd30a859
commit
8da70fec91
@ -244,6 +244,9 @@ gtk_css_image_linear_snapshot (GtkCssImage *image,
|
|||||||
last = i;
|
last = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (linear->color_space != GTK_CSS_COLOR_SPACE_SRGB)
|
||||||
|
g_warning_once ("Gradient interpolation color spaces are not supported yet");
|
||||||
|
|
||||||
if (linear->repeating)
|
if (linear->repeating)
|
||||||
{
|
{
|
||||||
gtk_snapshot_append_repeating_linear_gradient (
|
gtk_snapshot_append_repeating_linear_gradient (
|
||||||
@ -304,75 +307,102 @@ gtk_css_image_linear_parse_first_arg (GtkCssImageLinear *linear,
|
|||||||
GArray *stop_array)
|
GArray *stop_array)
|
||||||
{
|
{
|
||||||
guint i;
|
guint i;
|
||||||
|
gboolean has_colorspace = FALSE;
|
||||||
|
gboolean has_side_or_angle = FALSE;
|
||||||
|
guint retval = 1;
|
||||||
|
|
||||||
if (gtk_css_parser_try_ident (parser, "to"))
|
do
|
||||||
{
|
{
|
||||||
for (i = 0; i < 2; i++)
|
if (!has_colorspace &>k_css_color_interpolation_method_can_parse (parser))
|
||||||
{
|
{
|
||||||
if (gtk_css_parser_try_ident (parser, "left"))
|
if (!gtk_css_color_interpolation_method_parse (parser, &linear->color_space, &linear->hue_interp))
|
||||||
{
|
return 0;
|
||||||
if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT)))
|
has_colorspace = TRUE;
|
||||||
{
|
|
||||||
gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
linear->side |= (1 << GTK_CSS_LEFT);
|
|
||||||
}
|
|
||||||
else if (gtk_css_parser_try_ident (parser, "right"))
|
|
||||||
{
|
|
||||||
if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT)))
|
|
||||||
{
|
|
||||||
gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
linear->side |= (1 << GTK_CSS_RIGHT);
|
|
||||||
}
|
|
||||||
else if (gtk_css_parser_try_ident (parser, "top"))
|
|
||||||
{
|
|
||||||
if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM)))
|
|
||||||
{
|
|
||||||
gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
linear->side |= (1 << GTK_CSS_TOP);
|
|
||||||
}
|
|
||||||
else if (gtk_css_parser_try_ident (parser, "bottom"))
|
|
||||||
{
|
|
||||||
if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM)))
|
|
||||||
{
|
|
||||||
gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
linear->side |= (1 << GTK_CSS_BOTTOM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else if (!has_side_or_angle && gtk_css_parser_try_ident (parser, "to"))
|
||||||
if (linear->side == 0)
|
|
||||||
{
|
{
|
||||||
gtk_css_parser_error_syntax (parser, "Expected side that gradient should go to");
|
gtk_css_parser_consume_token (parser);
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
if (gtk_css_parser_try_ident (parser, "left"))
|
||||||
|
{
|
||||||
|
if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT)))
|
||||||
|
{
|
||||||
|
gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
linear->side |= (1 << GTK_CSS_LEFT);
|
||||||
|
}
|
||||||
|
else if (gtk_css_parser_try_ident (parser, "right"))
|
||||||
|
{
|
||||||
|
if (linear->side & ((1 << GTK_CSS_LEFT) | (1 << GTK_CSS_RIGHT)))
|
||||||
|
{
|
||||||
|
gtk_css_parser_error_syntax (parser, "Expected 'top', 'bottom' or comma");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
linear->side |= (1 << GTK_CSS_RIGHT);
|
||||||
|
}
|
||||||
|
else if (gtk_css_parser_try_ident (parser, "top"))
|
||||||
|
{
|
||||||
|
if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM)))
|
||||||
|
{
|
||||||
|
gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
linear->side |= (1 << GTK_CSS_TOP);
|
||||||
|
}
|
||||||
|
else if (gtk_css_parser_try_ident (parser, "bottom"))
|
||||||
|
{
|
||||||
|
if (linear->side & ((1 << GTK_CSS_TOP) | (1 << GTK_CSS_BOTTOM)))
|
||||||
|
{
|
||||||
|
gtk_css_parser_error_syntax (parser, "Expected 'left', 'right' or comma");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
linear->side |= (1 << GTK_CSS_BOTTOM);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linear->side == 0)
|
||||||
|
{
|
||||||
|
gtk_css_parser_error_syntax (parser, "Expected side that gradient should go to");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
has_side_or_angle = TRUE;
|
||||||
|
}
|
||||||
|
else if (!has_side_or_angle && gtk_css_number_value_can_parse (parser))
|
||||||
|
{
|
||||||
|
linear->angle = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
|
||||||
|
if (linear->angle == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
has_side_or_angle = TRUE;
|
||||||
|
}
|
||||||
|
else if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_COMMA))
|
||||||
|
{
|
||||||
|
retval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (gtk_css_image_linear_parse_color_stop (linear, parser, stop_array))
|
||||||
|
{
|
||||||
|
retval = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
else if (gtk_css_number_value_can_parse (parser))
|
while (!(has_colorspace && has_side_or_angle));
|
||||||
{
|
|
||||||
linear->angle = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
|
|
||||||
if (linear->angle == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
if (linear->angle == NULL && linear->side == 0)
|
||||||
}
|
linear->side = (1 << GTK_CSS_BOTTOM);
|
||||||
else
|
|
||||||
{
|
|
||||||
linear->side = 1 << GTK_CSS_BOTTOM;
|
|
||||||
if (!gtk_css_image_linear_parse_color_stop (linear, parser, stop_array))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 2;
|
return retval;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -437,6 +467,7 @@ gtk_css_image_linear_print (GtkCssImage *image,
|
|||||||
{
|
{
|
||||||
GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
|
GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
|
||||||
guint i;
|
guint i;
|
||||||
|
gboolean has_printed = FALSE;
|
||||||
|
|
||||||
if (linear->repeating)
|
if (linear->repeating)
|
||||||
g_string_append (string, "repeating-linear-gradient(");
|
g_string_append (string, "repeating-linear-gradient(");
|
||||||
@ -459,15 +490,29 @@ gtk_css_image_linear_print (GtkCssImage *image,
|
|||||||
else if (linear->side & (1 << GTK_CSS_RIGHT))
|
else if (linear->side & (1 << GTK_CSS_RIGHT))
|
||||||
g_string_append (string, " right");
|
g_string_append (string, " right");
|
||||||
|
|
||||||
g_string_append (string, ", ");
|
has_printed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gtk_css_value_print (linear->angle, string);
|
gtk_css_value_print (linear->angle, string);
|
||||||
g_string_append (string, ", ");
|
has_printed = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (linear->color_space != GTK_CSS_COLOR_SPACE_SRGB)
|
||||||
|
{
|
||||||
|
if (has_printed)
|
||||||
|
g_string_append_c (string, ' ');
|
||||||
|
|
||||||
|
gtk_css_color_interpolation_method_print (linear->color_space,
|
||||||
|
linear->hue_interp,
|
||||||
|
string);
|
||||||
|
has_printed = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_printed)
|
||||||
|
g_string_append (string, ", ");
|
||||||
|
|
||||||
for (i = 0; i < linear->n_stops; i++)
|
for (i = 0; i < linear->n_stops; i++)
|
||||||
{
|
{
|
||||||
const GtkCssImageLinearColorStop *stop = &linear->color_stops[i];
|
const GtkCssImageLinearColorStop *stop = &linear->color_stops[i];
|
||||||
@ -499,6 +544,8 @@ gtk_css_image_linear_compute (GtkCssImage *image,
|
|||||||
copy = g_object_new (GTK_TYPE_CSS_IMAGE_LINEAR, NULL);
|
copy = g_object_new (GTK_TYPE_CSS_IMAGE_LINEAR, NULL);
|
||||||
copy->repeating = linear->repeating;
|
copy->repeating = linear->repeating;
|
||||||
copy->side = linear->side;
|
copy->side = linear->side;
|
||||||
|
copy->color_space = linear->color_space;
|
||||||
|
copy->hue_interp = linear->hue_interp;
|
||||||
|
|
||||||
if (linear->angle)
|
if (linear->angle)
|
||||||
copy->angle = gtk_css_value_compute (linear->angle, property_id, context);
|
copy->angle = gtk_css_value_compute (linear->angle, property_id, context);
|
||||||
@ -545,11 +592,15 @@ gtk_css_image_linear_transition (GtkCssImage *start_image,
|
|||||||
end = GTK_CSS_IMAGE_LINEAR (end_image);
|
end = GTK_CSS_IMAGE_LINEAR (end_image);
|
||||||
|
|
||||||
if ((start->repeating != end->repeating)
|
if ((start->repeating != end->repeating)
|
||||||
|| (start->n_stops != end->n_stops))
|
|| (start->n_stops != end->n_stops)
|
||||||
|
|| (start->color_space != end->color_space)
|
||||||
|
|| (start->hue_interp != end->hue_interp))
|
||||||
return GTK_CSS_IMAGE_CLASS (_gtk_css_image_linear_parent_class)->transition (start_image, end_image, property_id, progress);
|
return GTK_CSS_IMAGE_CLASS (_gtk_css_image_linear_parent_class)->transition (start_image, end_image, property_id, progress);
|
||||||
|
|
||||||
result = g_object_new (GTK_TYPE_CSS_IMAGE_LINEAR, NULL);
|
result = g_object_new (GTK_TYPE_CSS_IMAGE_LINEAR, NULL);
|
||||||
result->repeating = start->repeating;
|
result->repeating = start->repeating;
|
||||||
|
result->color_space = start->color_space;
|
||||||
|
result->hue_interp = start->hue_interp;
|
||||||
|
|
||||||
if (start->side != end->side)
|
if (start->side != end->side)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -618,7 +669,9 @@ gtk_css_image_linear_equal (GtkCssImage *image1,
|
|||||||
if (linear1->repeating != linear2->repeating ||
|
if (linear1->repeating != linear2->repeating ||
|
||||||
linear1->side != linear2->side ||
|
linear1->side != linear2->side ||
|
||||||
(linear1->side == 0 && !gtk_css_value_equal (linear1->angle, linear2->angle)) ||
|
(linear1->side == 0 && !gtk_css_value_equal (linear1->angle, linear2->angle)) ||
|
||||||
linear1->n_stops != linear2->n_stops)
|
linear1->n_stops != linear2->n_stops ||
|
||||||
|
linear1->color_space != linear2->color_space ||
|
||||||
|
linear1->hue_interp != linear2->hue_interp)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
for (i = 0; i < linear1->n_stops; i++)
|
for (i = 0; i < linear1->n_stops; i++)
|
||||||
|
@ -48,6 +48,9 @@ struct _GtkCssImageLinear
|
|||||||
guint repeating :1;
|
guint repeating :1;
|
||||||
GtkCssValue *angle;
|
GtkCssValue *angle;
|
||||||
|
|
||||||
|
GtkCssColorSpace color_space;
|
||||||
|
GtkCssHueInterpolation hue_interp;
|
||||||
|
|
||||||
guint n_stops;
|
guint n_stops;
|
||||||
GtkCssImageLinearColorStop *color_stops;
|
GtkCssImageLinearColorStop *color_stops;
|
||||||
};
|
};
|
||||||
|
39
testsuite/css/parser/linear-gradient-invalid.css
Normal file
39
testsuite/css/parser/linear-gradient-invalid.css
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
a {
|
||||||
|
background-image: linear-gradient(to top bottom, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to top bottom, red 0% blue 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
background-image: linear-gradient(to top left bottom, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to top left bottom, red 0% blue 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
c {
|
||||||
|
background-image: linear-gradient(to top top, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to top top, red 0% blue 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
d {
|
||||||
|
background-image: linear-gradient(to top to left, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to top to left, red 0% blue 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
e {
|
||||||
|
background-image: linear-gradient(to top left 0turn, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to top left 0turn, red 0% blue 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
f {
|
||||||
|
background-image: linear-gradient(in swishy, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(in swishy, red 0% blue 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
g {
|
||||||
|
background-image: linear-gradient(in srgb longer hue, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(in srgb longer hue, red 0% blue 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
h {
|
||||||
|
background-image: linear-gradient(in srgb in srgb, red 0% blue 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(in srgb in srgb, red 0% blue 100%);
|
||||||
|
}
|
16
testsuite/css/parser/linear-gradient-invalid.errors
Normal file
16
testsuite/css/parser/linear-gradient-invalid.errors
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
linear-gradient-invalid.css:2:44-50: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:3:57-63: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:7:49-55: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:8:62-68: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:12:44-47: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:13:57-60: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:17:44-46: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:18:57-59: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:22:49-54: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:23:62-67: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:27:40-46: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:28:53-59: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:32:45-51: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:33:58-64: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:37:45-47: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
||||||
|
linear-gradient-invalid.css:38:58-60: error: GTK_CSS_PARSER_ERROR_SYNTAX
|
@ -102,3 +102,23 @@ u {
|
|||||||
background-image: linear-gradient(red -5px, green 20em, blue, purple -42%, pink 3pt);
|
background-image: linear-gradient(red -5px, green 20em, blue, purple -42%, pink 3pt);
|
||||||
border-image-source: repeating-linear-gradient(red -5px, green 20em, blue, purple -42%, pink 3pt);
|
border-image-source: repeating-linear-gradient(red -5px, green 20em, blue, purple -42%, pink 3pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v {
|
||||||
|
background-image: linear-gradient(to left top in srgb, red 0, green 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to left top in srgb, red 0, green 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
w {
|
||||||
|
background-image: linear-gradient(to left top in hsl longer hue, red 0, green 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to left top in hsl longer hue, red 0, green 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
x {
|
||||||
|
background-image: linear-gradient(25deg in rec2020, red 0, green 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(25deg in rec2020, red 0, green 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
y {
|
||||||
|
background-image: linear-gradient(in hwb to bottom, red 0, green 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(in hwb to bottom, red 0, green 100%);
|
||||||
|
}
|
||||||
|
@ -102,3 +102,23 @@ u {
|
|||||||
background-image: linear-gradient(rgb(255,0,0) -5px, rgb(0,128,0) 20em, rgb(0,0,255), rgb(128,0,128) -42%, rgb(255,192,203) 3pt);
|
background-image: linear-gradient(rgb(255,0,0) -5px, rgb(0,128,0) 20em, rgb(0,0,255), rgb(128,0,128) -42%, rgb(255,192,203) 3pt);
|
||||||
border-image-source: repeating-linear-gradient(rgb(255,0,0) -5px, rgb(0,128,0) 20em, rgb(0,0,255), rgb(128,0,128) -42%, rgb(255,192,203) 3pt);
|
border-image-source: repeating-linear-gradient(rgb(255,0,0) -5px, rgb(0,128,0) 20em, rgb(0,0,255), rgb(128,0,128) -42%, rgb(255,192,203) 3pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v {
|
||||||
|
background-image: linear-gradient(to top left, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to top left, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
w {
|
||||||
|
background-image: linear-gradient(to top left in hsl longer hue, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(to top left in hsl longer hue, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
x {
|
||||||
|
background-image: linear-gradient(25deg in rec2020, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(25deg in rec2020, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
y {
|
||||||
|
background-image: linear-gradient(in hwb, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
border-image-source: repeating-linear-gradient(in hwb, rgb(255,0,0) 0, rgb(0,128,0) 100%);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user