css: Parse interpolation for conic 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. This commit fixes preexisting brokenness in conic-gradient parsing and printing as well, and includes the relevant test changes. Tests included. Gradient interpolation color spaces aren't supported for rendering yet.
This commit is contained in:
@@ -81,7 +81,10 @@ gtk_css_image_conic_snapshot (GtkCssImage *image,
|
|||||||
last = i;
|
last = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_snapshot_append_conic_gradient (
|
if (self->color_space != GTK_CSS_COLOR_SPACE_SRGB)
|
||||||
|
g_warning_once ("Gradient interpolation color spaces are not supported yet");
|
||||||
|
|
||||||
|
gtk_snapshot_append_conic_gradient (
|
||||||
snapshot,
|
snapshot,
|
||||||
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
&GRAPHENE_RECT_INIT (0, 0, width, height),
|
||||||
&GRAPHENE_POINT_INIT (_gtk_css_position_value_get_x (self->center, width),
|
&GRAPHENE_POINT_INIT (_gtk_css_position_value_get_x (self->center, width),
|
||||||
@@ -172,37 +175,57 @@ gtk_css_image_conic_parse_first_arg (GtkCssImageConic *self,
|
|||||||
GtkCssParser *parser,
|
GtkCssParser *parser,
|
||||||
GArray *stop_array)
|
GArray *stop_array)
|
||||||
{
|
{
|
||||||
gboolean nothing_parsed = TRUE;
|
gboolean has_rotation = FALSE;
|
||||||
|
gboolean has_center = FALSE;
|
||||||
|
gboolean has_colorspace = FALSE;
|
||||||
|
int retval = 1;
|
||||||
|
|
||||||
if (gtk_css_parser_try_ident (parser, "from"))
|
do
|
||||||
{
|
{
|
||||||
self->rotation = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
|
if (!has_colorspace && gtk_css_color_interpolation_method_can_parse (parser))
|
||||||
if (self->rotation == NULL)
|
{
|
||||||
return 0;
|
if (!gtk_css_color_interpolation_method_parse (parser, &self->color_space, &self->hue_interp))
|
||||||
nothing_parsed = FALSE;
|
return 0;
|
||||||
}
|
has_colorspace = TRUE;
|
||||||
else
|
}
|
||||||
{
|
else if (!has_rotation && gtk_css_parser_try_ident (parser, "from"))
|
||||||
self->rotation = gtk_css_number_value_new (0, GTK_CSS_DEG);
|
{
|
||||||
|
self->rotation = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE);
|
||||||
|
if (self->rotation == NULL)
|
||||||
|
return 0;
|
||||||
|
has_rotation = TRUE;
|
||||||
|
}
|
||||||
|
else if (!has_center && gtk_css_parser_try_ident (parser, "at"))
|
||||||
|
{
|
||||||
|
self->center = _gtk_css_position_value_parse (parser);
|
||||||
|
if (self->center == NULL)
|
||||||
|
return 0;
|
||||||
|
has_center = 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_conic_parse_color_stop (self, parser, stop_array))
|
||||||
|
{
|
||||||
|
retval = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
while (!(has_colorspace && has_rotation && has_center));
|
||||||
|
|
||||||
if (gtk_css_parser_try_ident (parser, "at"))
|
if (!has_rotation)
|
||||||
{
|
self->rotation = gtk_css_number_value_new (0, GTK_CSS_DEG);
|
||||||
self->center = _gtk_css_position_value_parse (parser);
|
|
||||||
if (self->center == NULL)
|
|
||||||
return 0;
|
|
||||||
nothing_parsed = FALSE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
self->center = _gtk_css_position_value_new (gtk_css_number_value_new (50, GTK_CSS_PERCENT),
|
|
||||||
gtk_css_number_value_new (50, GTK_CSS_PERCENT));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nothing_parsed)
|
if (!has_center)
|
||||||
return 1;
|
self->center = _gtk_css_position_value_new (gtk_css_number_value_new (50, GTK_CSS_PERCENT),
|
||||||
|
gtk_css_number_value_new (50, GTK_CSS_PERCENT));
|
||||||
|
|
||||||
return 1 + gtk_css_image_conic_parse_color_stop (self, parser, stop_array);
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -265,7 +288,7 @@ gtk_css_image_conic_print (GtkCssImage *image,
|
|||||||
gboolean written = FALSE;
|
gboolean written = FALSE;
|
||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
g_string_append (string, "self-gradient(");
|
g_string_append (string, "conic-gradient(");
|
||||||
|
|
||||||
if (self->center)
|
if (self->center)
|
||||||
{
|
{
|
||||||
@@ -274,7 +297,7 @@ gtk_css_image_conic_print (GtkCssImage *image,
|
|||||||
|
|
||||||
if (!gtk_css_value_equal (self->center, compare))
|
if (!gtk_css_value_equal (self->center, compare))
|
||||||
{
|
{
|
||||||
g_string_append (string, "from ");
|
g_string_append (string, "at ");
|
||||||
gtk_css_value_print (self->center, string);
|
gtk_css_value_print (self->center, string);
|
||||||
written = TRUE;
|
written = TRUE;
|
||||||
}
|
}
|
||||||
@@ -286,8 +309,19 @@ gtk_css_image_conic_print (GtkCssImage *image,
|
|||||||
{
|
{
|
||||||
if (written)
|
if (written)
|
||||||
g_string_append_c (string, ' ');
|
g_string_append_c (string, ' ');
|
||||||
g_string_append (string, "at ");
|
g_string_append (string, "from ");
|
||||||
gtk_css_value_print (self->rotation, string);
|
gtk_css_value_print (self->rotation, string);
|
||||||
|
written = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->color_space != GTK_CSS_COLOR_SPACE_SRGB)
|
||||||
|
{
|
||||||
|
if (written)
|
||||||
|
g_string_append_c (string, ' ');
|
||||||
|
gtk_css_color_interpolation_method_print (self->color_space,
|
||||||
|
self->hue_interp,
|
||||||
|
string);
|
||||||
|
written = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (written)
|
if (written)
|
||||||
@@ -325,6 +359,8 @@ gtk_css_image_conic_compute (GtkCssImage *image,
|
|||||||
|
|
||||||
copy->center = gtk_css_value_compute (self->center, property_id, context);
|
copy->center = gtk_css_value_compute (self->center, property_id, context);
|
||||||
copy->rotation = gtk_css_value_compute (self->rotation, property_id, context);
|
copy->rotation = gtk_css_value_compute (self->rotation, property_id, context);
|
||||||
|
copy->color_space = self->color_space;
|
||||||
|
copy->hue_interp = self->hue_interp;
|
||||||
|
|
||||||
copy->n_stops = self->n_stops;
|
copy->n_stops = self->n_stops;
|
||||||
copy->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * copy->n_stops);
|
copy->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * copy->n_stops);
|
||||||
@@ -380,6 +416,9 @@ gtk_css_image_conic_transition (GtkCssImage *start_image,
|
|||||||
if (result->rotation == NULL)
|
if (result->rotation == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
result->color_space = start->color_space;
|
||||||
|
result->hue_interp = start->hue_interp;
|
||||||
|
|
||||||
result->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * start->n_stops);
|
result->color_stops = g_malloc (sizeof (GtkCssImageConicColorStop) * start->n_stops);
|
||||||
result->n_stops = 0;
|
result->n_stops = 0;
|
||||||
for (i = 0; i < start->n_stops; i++)
|
for (i = 0; i < start->n_stops; i++)
|
||||||
@@ -435,7 +474,9 @@ gtk_css_image_conic_equal (GtkCssImage *image1,
|
|||||||
guint i;
|
guint i;
|
||||||
|
|
||||||
if (!gtk_css_value_equal (conic1->center, conic2->center) ||
|
if (!gtk_css_value_equal (conic1->center, conic2->center) ||
|
||||||
!gtk_css_value_equal (conic1->rotation, conic2->rotation))
|
!gtk_css_value_equal (conic1->rotation, conic2->rotation) ||
|
||||||
|
conic1->color_space != conic2->color_space ||
|
||||||
|
conic1->hue_interp != conic2->hue_interp)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
for (i = 0; i < conic1->n_stops; i++)
|
for (i = 0; i < conic1->n_stops; i++)
|
||||||
|
|||||||
@@ -47,6 +47,9 @@ struct _GtkCssImageConic
|
|||||||
GtkCssValue *center;
|
GtkCssValue *center;
|
||||||
GtkCssValue *rotation;
|
GtkCssValue *rotation;
|
||||||
|
|
||||||
|
GtkCssColorSpace color_space;
|
||||||
|
GtkCssHueInterpolation hue_interp;
|
||||||
|
|
||||||
guint n_stops;
|
guint n_stops;
|
||||||
GtkCssImageConicColorStop *color_stops;
|
GtkCssImageConicColorStop *color_stops;
|
||||||
};
|
};
|
||||||
|
|||||||
43
testsuite/css/parser/conic.css
Normal file
43
testsuite/css/parser/conic.css
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
a {
|
||||||
|
background-image: conic-gradient(yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
background-image: conic-gradient(at center, yellow 0%, green 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
c {
|
||||||
|
background-image: conic-gradient(at 50% 50%, yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
d {
|
||||||
|
background-image: conic-gradient(at left top, yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
e {
|
||||||
|
background-image: conic-gradient(at 25% bottom, red, yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
f {
|
||||||
|
background-image: conic-gradient(from 20deg, red, yellow 50%, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
g {
|
||||||
|
background-image: conic-gradient(from 0.25turn at 20px 20px, red, yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
h {
|
||||||
|
background-image: conic-gradient(from 20deg in oklab, red, yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
background-image: conic-gradient(in rec2020 at center, red, yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
j {
|
||||||
|
background-image: conic-gradient(in hsl longer hue from 10deg, red, yellow, green);
|
||||||
|
}
|
||||||
|
|
||||||
|
k {
|
||||||
|
background-image: conic-gradient(in srgb from -10deg at 20px 20px, red, yellow);
|
||||||
|
}
|
||||||
43
testsuite/css/parser/conic.ref.css
Normal file
43
testsuite/css/parser/conic.ref.css
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
a {
|
||||||
|
background-image: conic-gradient(rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
b {
|
||||||
|
background-image: conic-gradient(rgb(255,255,0) 0, rgb(0,128,0) 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
c {
|
||||||
|
background-image: conic-gradient(rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
d {
|
||||||
|
background-image: conic-gradient(at left top, rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
e {
|
||||||
|
background-image: conic-gradient(at 25% bottom, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
f {
|
||||||
|
background-image: conic-gradient(from 20deg, rgb(255,0,0), rgb(255,255,0) 50%, rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
g {
|
||||||
|
background-image: conic-gradient(at 20px 20px from 0.25turn, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
h {
|
||||||
|
background-image: conic-gradient(from 20deg in oklab, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
background-image: conic-gradient(in rec2020, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
j {
|
||||||
|
background-image: conic-gradient(from 10deg in hsl longer hue, rgb(255,0,0), rgb(255,255,0), rgb(0,128,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
k {
|
||||||
|
background-image: conic-gradient(at 20px 20px from -10deg, rgb(255,0,0), rgb(255,255,0));
|
||||||
|
}
|
||||||
@@ -7,4 +7,4 @@ window.background:dir(ltr)
|
|||||||
label:dir(ltr)
|
label:dir(ltr)
|
||||||
background-image: radial-gradient(ellipse farthest-corner at center 30px, rgb(255,255,0), rgb(255,0,0) 30%, rgb(0,0,255)); /* gradient.css:10:3-89 */
|
background-image: radial-gradient(ellipse farthest-corner at center 30px, rgb(255,255,0), rgb(255,0,0) 30%, rgb(0,0,255)); /* gradient.css:10:3-89 */
|
||||||
image:dir(ltr)
|
image:dir(ltr)
|
||||||
background-image: self-gradient(from center 30px at 25deg, rgb(255,255,0), rgb(255,0,0) 30%, rgb(0,0,255)); /* gradient.css:14:3-83 */
|
background-image: conic-gradient(at center 30px from 25deg, rgb(255,255,0), rgb(255,0,0) 30%, rgb(0,0,255)); /* gradient.css:14:3-83 */
|
||||||
|
|||||||
Reference in New Issue
Block a user