Merge branch 'css-color-hookup-6' into 'main'

Make non-srgb css colors work for gradients

See merge request GNOME/gtk!7584
This commit is contained in:
Matthias Clasen 2024-10-12 18:29:31 +00:00
commit d754f5c1b4
29 changed files with 1831 additions and 419 deletions

View File

@ -181,15 +181,21 @@ matrix3d() production to specify all 16 values individually.
### conic-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25, 25 | always |
| rotation | `<number>` | 0 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | --------------- | -------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25, 25 | always |
| rotation | `<number>` | 0 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| interpolation | `<color-state>` | srgb | non-default |
| hue-interpolation | `<hue-interp>` | shorter | non-default |
Creates a node like `gsk_conic_gradient_node_new()` with the given properties.
Possible values for the hue-interpolation property are:
hue-interpolation: shorter | longer | increasing | decreasing
### cross-fade
| property | syntax | default | printed |
@ -258,12 +264,14 @@ Creates a node like `gsk_inset_shadow_node_new()` with the given properties.
### linear-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| start | `<point>` | 0 0 | always |
| end | `<point>` | 0 50 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | --------------- | -------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| start | `<point>` | 0 0 | always |
| end | `<point>` | 0 50 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| interpolation | `<color-state>` | srgb | non-default |
| hue-interpolation | `<hue-interp>` | shorter | non-default |
Creates a node like `gsk_linear_gradient_node_new()` with the given properties.
@ -305,15 +313,17 @@ Creates a node like `gsk_outset_shadow_node_new()` with the given properties.
### radial-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25 25 | always |
| hradius | `<number>` | 25 | always |
| vradius | `<number>` | 25 | always |
| start | `<number>` | 0 | always |
| end | `<number>` | 1 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | --------------- | -------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25 25 | always |
| hradius | `<number>` | 25 | always |
| vradius | `<number>` | 25 | always |
| start | `<number>` | 0 | always |
| end | `<number>` | 1 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| interpolation | `<color-state>` | srgb | non-default |
| hue-interpolation | `<hue-interp>` | shorter | non-default |
Creates a node like `gsk_radial_gradient_node_new()` with the given properties.

View File

@ -122,6 +122,18 @@ gdk_cairo_pattern_add_color_stop_rgba_ccs (cairo_pattern_t *pattern,
cairo_pattern_add_color_stop_rgba (pattern, offset, color[0], color[1], color[2], color[3]);
}
static inline void
gdk_cairo_pattern_add_color_stop_color (cairo_pattern_t *pattern,
GdkColorState *ccs,
double offset,
const GdkColor *color)
{
float values[4];
gdk_color_to_float (color, ccs, values);
cairo_pattern_add_color_stop_rgba (pattern, offset, values[0], values[1], values[2], values[3]);
}
static inline void
gdk_cairo_rect (cairo_t *cr,
const graphene_rect_t *rect)

View File

@ -27,12 +27,12 @@ gsk_gpu_color_states_create (GdkColorState *output_color_state,
GdkColorState *alt_color_state,
gboolean alt_is_premultiplied)
{
g_assert (GDK_IS_DEFAULT_COLOR_STATE (output_color_state));
g_assert (GDK_IS_DEFAULT_COLOR_STATE (alt_color_state));
if (gdk_color_state_equal (output_color_state, alt_color_state))
return gsk_gpu_color_states_create_equal (output_is_premultiplied, alt_is_premultiplied);
g_assert (GDK_IS_DEFAULT_COLOR_STATE (output_color_state));
g_assert (GDK_IS_DEFAULT_COLOR_STATE (alt_color_state));
return (GDK_DEFAULT_COLOR_STATE_ID (output_color_state) << COLOR_SPACE_OUTPUT_SHIFT) |
(output_is_premultiplied ? COLOR_SPACE_OUTPUT_PREMULTIPLIED : 0) |
(GDK_DEFAULT_COLOR_STATE_ID (alt_color_state) << COLOR_SPACE_ALT_SHIFT) |

View File

@ -52,24 +52,28 @@ static const GskGpuShaderOpClass GSK_GPU_CONIC_GRADIENT_OP_CLASS = {
void
gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
GdkColorState *ics,
GskHueInterpolation hue_interp,
const graphene_rect_t *rect,
const graphene_point_t *center,
float angle,
const graphene_point_t *offset,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops)
{
GskGpuConicgradientInstance *instance;
GdkColorState *color_state = gsk_gpu_color_states_get_alt (color_states);
g_assert (n_stops > 1);
g_assert (n_stops <= 7);
g_assert (gsk_gpu_color_states_is_alt_premultiplied (color_states));
/* Note: we pass TRUE for alt-premultiplied because the
* vertex shader applies the alpha to the colors.
*/
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_CONIC_GRADIENT_OP_CLASS,
color_states,
gsk_gpu_color_states_create (ccs, TRUE, ics, TRUE),
(gsk_gpu_frame_should_optimize (frame, GSK_GPU_OPTIMIZE_GRADIENTS) ? VARIATION_SUPERSAMPLING : 0),
clip,
NULL,
@ -79,18 +83,18 @@ gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_point_to_float (center, offset, instance->center);
instance->angle = angle;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 6)].color, instance->color6);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 6)].color, ics, opacity, instance->color6);
instance->offsets1[2] = stops[MIN (n_stops - 1, 6)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 5)].color, instance->color5);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 5)].color, ics, opacity, instance->color5);
instance->offsets1[1] = stops[MIN (n_stops - 1, 5)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 4)].color, instance->color4);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 4)].color, ics, opacity, instance->color4);
instance->offsets1[0] = stops[MIN (n_stops - 1, 4)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 3)].color, instance->color3);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 3)].color, ics, opacity, instance->color3);
instance->offsets0[3] = stops[MIN (n_stops - 1, 3)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 2)].color, instance->color2);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 2)].color, ics, opacity, instance->color2);
instance->offsets0[2] = stops[MIN (n_stops - 1, 2)].offset;
gdk_color_state_from_rgba (color_state, &stops[1].color, instance->color1);
gsk_gpu_color_to_float (&stops[1].color, ics, opacity, instance->color1);
instance->offsets0[1] = stops[1].offset;
gdk_color_state_from_rgba (color_state, &stops[0].color, instance->color0);
gsk_gpu_color_to_float (&stops[0].color, ics, opacity, instance->color0);
instance->offsets0[0] = stops[0].offset;
}

View File

@ -2,7 +2,7 @@
#include "gskgpushaderopprivate.h"
#include "gskrendernode.h"
#include "gskrendernodeprivate.h"
#include <graphene.h>
@ -10,12 +10,15 @@ G_BEGIN_DECLS
void gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
GdkColorState *ics,
GskHueInterpolation hue_interp,
const graphene_rect_t *rect,
const graphene_point_t *center,
float angle,
const graphene_point_t *offset,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops);

View File

@ -55,25 +55,29 @@ static const GskGpuShaderOpClass GSK_GPU_LINEAR_GRADIENT_OP_CLASS = {
void
gsk_gpu_linear_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
GdkColorState *ics,
GskHueInterpolation hue_interp,
gboolean repeating,
const graphene_rect_t *rect,
const graphene_point_t *start,
const graphene_point_t *end,
const graphene_point_t *offset,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops)
{
GskGpuLineargradientInstance *instance;
GdkColorState *color_state = gsk_gpu_color_states_get_alt (color_states);
g_assert (n_stops > 1);
g_assert (n_stops <= 7);
g_assert (gsk_gpu_color_states_is_alt_premultiplied (color_states));
/* Note: we pass TRUE for alt-premultiplied because the
* vertex shader applies the alpha to the colors.
*/
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_LINEAR_GRADIENT_OP_CLASS,
color_states,
gsk_gpu_color_states_create (ccs, TRUE, ics, TRUE),
(repeating ? VARIATION_REPEATING : 0) |
(gsk_gpu_frame_should_optimize (frame, GSK_GPU_OPTIMIZE_GRADIENTS) ? VARIATION_SUPERSAMPLING : 0),
clip,
@ -84,18 +88,18 @@ gsk_gpu_linear_gradient_op (GskGpuFrame *frame,
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_point_to_float (start, offset, instance->startend);
gsk_gpu_point_to_float (end, offset, &instance->startend[2]);
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 6)].color, instance->color6);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 6)].color, ics, opacity, instance->color6);
instance->offsets1[2] = stops[MIN (n_stops - 1, 6)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 5)].color, instance->color5);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 5)].color, ics, opacity, instance->color5);
instance->offsets1[1] = stops[MIN (n_stops - 1, 5)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 4)].color, instance->color4);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 4)].color, ics, opacity, instance->color4);
instance->offsets1[0] = stops[MIN (n_stops - 1, 4)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 3)].color, instance->color3);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 3)].color, ics, opacity, instance->color3);
instance->offsets0[3] = stops[MIN (n_stops - 1, 3)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 2)].color, instance->color2);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 2)].color, ics, opacity, instance->color2);
instance->offsets0[2] = stops[MIN (n_stops - 1, 2)].offset;
gdk_color_state_from_rgba (color_state, &stops[1].color, instance->color1);
gsk_gpu_color_to_float (&stops[1].color, ics, opacity, instance->color1);
instance->offsets0[1] = stops[1].offset;
gdk_color_state_from_rgba (color_state, &stops[0].color, instance->color0);
gsk_gpu_color_to_float (&stops[0].color, ics, opacity, instance->color0);
instance->offsets0[0] = stops[0].offset;
}

View File

@ -2,7 +2,7 @@
#include "gskgpushaderopprivate.h"
#include "gskrendernode.h"
#include "gskrendernodeprivate.h"
#include <graphene.h>
@ -10,13 +10,16 @@ G_BEGIN_DECLS
void gsk_gpu_linear_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
GdkColorState *ics,
GskHueInterpolation hue_interp,
gboolean repeating,
const graphene_rect_t *rect,
const graphene_point_t *start,
const graphene_point_t *end,
const graphene_point_t *offset,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops);

View File

@ -2464,37 +2464,34 @@ gsk_gpu_node_processor_add_outset_shadow_node (GskGpuNodeProcessor *self,
}
typedef void (* GradientOpFunc) (GskGpuNodeProcessor *self,
GdkColorState *target,
GskRenderNode *node,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops);
static void
gsk_gpu_node_processor_add_gradient_node (GskGpuNodeProcessor *self,
GskRenderNode *node,
const GskColorStop *stops,
GdkColorState *ics,
const GskColorStop2 *stops,
gsize n_stops,
GradientOpFunc func)
{
GskColorStop real_stops[7];
GskColorStop2 real_stops[7];
GskGpuNodeProcessor other;
graphene_rect_t bounds;
gsize i, j;
GskGpuImage *image;
GdkColorState *target;
if (n_stops < 8)
if (GDK_IS_DEFAULT_COLOR_STATE (ics))
target = self->ccs;
else
target = ics;
if (n_stops < 8 && GDK_IS_DEFAULT_COLOR_STATE (ics))
{
if (self->opacity < 1.0)
{
for (i = 0; i < n_stops; i++)
{
real_stops[i].offset = stops[i].offset;
real_stops[i].color = GDK_RGBA_INIT_ALPHA (&stops[i].color, self->opacity);
}
stops = real_stops;
}
func (self, node, stops, n_stops);
func (self, target, node, stops, n_stops);
return;
}
@ -2513,73 +2510,102 @@ gsk_gpu_node_processor_add_gradient_node (GskGpuNodeProcessor *self,
other.blend = GSK_GPU_BLEND_ADD;
other.pending_globals |= GSK_GPU_GLOBAL_BLEND;
gsk_gpu_node_processor_sync_globals (&other, 0);
for (i = 0; i < n_stops; /* happens inside the loop */)
{
if (i == 0)
{
real_stops[0].offset = stops[i].offset;
real_stops[0].color = GDK_RGBA_INIT_ALPHA (&stops[i].color, self->opacity);
gdk_color_init_copy (&real_stops[i].color, &stops[i].color);
i++;
}
else
{
real_stops[0].offset = stops[i-1].offset;
real_stops[0].color = GDK_RGBA_INIT_ALPHA (&stops[i-1].color, 0);
gdk_color_init_copy (&real_stops[0].color, &stops[i - 1].color);
real_stops[0].color.alpha *= 0;
}
for (j = 1; j < 6 && i < n_stops; j++)
{
real_stops[j].offset = stops[i].offset;
real_stops[j].color = GDK_RGBA_INIT_ALPHA (&stops[i].color, self->opacity);
gdk_color_init_copy (&real_stops[j].color, &stops[i].color);
i++;
}
if (i == n_stops - 1)
{
g_assert (j == 6);
real_stops[j].offset = stops[i].offset;
real_stops[j].color = GDK_RGBA_INIT_ALPHA (&stops[i].color, self->opacity);
gdk_color_init_copy (&real_stops[j].color, &stops[i].color);
j++;
i++;
}
else if (i < n_stops)
{
real_stops[j].offset = stops[i].offset;
real_stops[j].color = GDK_RGBA_INIT_ALPHA (&stops[i].color, 0);
gdk_color_init_copy (&real_stops[j].color, &stops[i].color);
real_stops[j].color.alpha *= 0;
j++;
}
func (&other, node, real_stops, j);
func (&other, target, node, real_stops, j);
}
gsk_gpu_node_processor_finish_draw (&other, image);
gsk_gpu_texture_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &bounds),
&self->offset,
&(GskGpuShaderImage) {
image,
GSK_GPU_SAMPLER_DEFAULT,
&node->bounds,
&bounds
});
if (GDK_IS_DEFAULT_COLOR_STATE (ics))
{
gsk_gpu_texture_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &bounds),
&self->offset,
&(GskGpuShaderImage) {
image,
GSK_GPU_SAMPLER_DEFAULT,
&node->bounds,
&bounds
});
}
else
{
const GdkCicp *cicp = gdk_color_state_get_cicp (ics);
g_assert (cicp != NULL);
gsk_gpu_convert_from_cicp_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &bounds),
cicp,
gsk_gpu_color_states_create_cicp (self->ccs, TRUE, TRUE),
1,
TRUE,
&self->offset,
&(GskGpuShaderImage) {
image,
GSK_GPU_SAMPLER_DEFAULT,
&node->bounds,
&bounds
});
}
g_object_unref (image);
}
static void
gsk_gpu_node_processor_linear_gradient_op (GskGpuNodeProcessor *self,
GdkColorState *target,
GskRenderNode *node,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops)
{
gsk_gpu_linear_gradient_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_gpu_node_processor_color_states_explicit (self, GDK_COLOR_STATE_SRGB, TRUE),
target,
self->opacity,
&self->offset,
gsk_linear_gradient_node_get_interpolation_color_state (node),
gsk_linear_gradient_node_get_hue_interpolation (node),
GSK_RENDER_NODE_TYPE (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE,
&node->bounds,
gsk_linear_gradient_node_get_start (node),
gsk_linear_gradient_node_get_end (node),
&self->offset,
stops,
n_stops);
}
@ -2590,20 +2616,26 @@ gsk_gpu_node_processor_add_linear_gradient_node (GskGpuNodeProcessor *self,
{
gsk_gpu_node_processor_add_gradient_node (self,
node,
gsk_linear_gradient_node_get_color_stops (node, NULL),
gsk_linear_gradient_node_get_interpolation_color_state (node),
gsk_linear_gradient_node_get_color_stops2 (node),
gsk_linear_gradient_node_get_n_color_stops (node),
gsk_gpu_node_processor_linear_gradient_op);
}
static void
gsk_gpu_node_processor_radial_gradient_op (GskGpuNodeProcessor *self,
GdkColorState *target,
GskRenderNode *node,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops)
{
gsk_gpu_radial_gradient_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_gpu_node_processor_color_states_explicit (self, GDK_COLOR_STATE_SRGB, TRUE),
target,
self->opacity,
&self->offset,
gsk_radial_gradient_node_get_interpolation_color_state (node),
gsk_radial_gradient_node_get_hue_interpolation (node),
GSK_RENDER_NODE_TYPE (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE,
&node->bounds,
gsk_radial_gradient_node_get_center (node),
@ -2613,7 +2645,6 @@ gsk_gpu_node_processor_radial_gradient_op (GskGpuNodeProcessor *self,
),
gsk_radial_gradient_node_get_start (node),
gsk_radial_gradient_node_get_end (node),
&self->offset,
stops,
n_stops);
}
@ -2624,24 +2655,29 @@ gsk_gpu_node_processor_add_radial_gradient_node (GskGpuNodeProcessor *self,
{
gsk_gpu_node_processor_add_gradient_node (self,
node,
gsk_radial_gradient_node_get_color_stops (node, NULL),
gsk_radial_gradient_node_get_interpolation_color_state (node),
gsk_radial_gradient_node_get_color_stops2 (node),
gsk_radial_gradient_node_get_n_color_stops (node),
gsk_gpu_node_processor_radial_gradient_op);
}
static void
gsk_gpu_node_processor_conic_gradient_op (GskGpuNodeProcessor *self,
GdkColorState *target,
GskRenderNode *node,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops)
{
gsk_gpu_conic_gradient_op (self->frame,
gsk_gpu_clip_get_shader_clip (&self->clip, &self->offset, &node->bounds),
gsk_gpu_node_processor_color_states_explicit (self, GDK_COLOR_STATE_SRGB, TRUE),
target,
self->opacity,
&self->offset,
gsk_conic_gradient_node_get_interpolation_color_state (node),
gsk_conic_gradient_node_get_hue_interpolation (node),
&node->bounds,
gsk_conic_gradient_node_get_center (node),
gsk_conic_gradient_node_get_angle (node),
&self->offset,
stops,
n_stops);
}
@ -2652,7 +2688,8 @@ gsk_gpu_node_processor_add_conic_gradient_node (GskGpuNodeProcessor *self,
{
gsk_gpu_node_processor_add_gradient_node (self,
node,
gsk_conic_gradient_node_get_color_stops (node, NULL),
gsk_conic_gradient_node_get_interpolation_color_state (node),
gsk_conic_gradient_node_get_color_stops2 (node),
gsk_conic_gradient_node_get_n_color_stops (node),
gsk_gpu_node_processor_conic_gradient_op);
}
@ -4498,4 +4535,3 @@ gsk_gpu_node_processor_convert_image (GskGpuFrame *frame,
return converted;
}

View File

@ -55,27 +55,31 @@ static const GskGpuShaderOpClass GSK_GPU_RADIAL_GRADIENT_OP_CLASS = {
void
gsk_gpu_radial_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
GdkColorState *ics,
GskHueInterpolation hue_interp,
gboolean repeating,
const graphene_rect_t *rect,
const graphene_point_t *center,
const graphene_point_t *radius,
float start,
float end,
const graphene_point_t *offset,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops)
{
GskGpuRadialgradientInstance *instance;
GdkColorState *color_state = gsk_gpu_color_states_get_alt (color_states);
g_assert (n_stops > 1);
g_assert (n_stops <= 7);
g_assert (gsk_gpu_color_states_is_alt_premultiplied (color_states));
/* Note: we pass TRUE for alt-premultiplied because the
* vertex shader applies the alpha to the colors.
*/
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_RADIAL_GRADIENT_OP_CLASS,
color_states,
gsk_gpu_color_states_create (ccs, TRUE, ics, TRUE),
(repeating ? VARIATION_REPEATING : 0) |
(gsk_gpu_frame_should_optimize (frame, GSK_GPU_OPTIMIZE_GRADIENTS) ? VARIATION_SUPERSAMPLING : 0),
clip,
@ -88,18 +92,18 @@ gsk_gpu_radial_gradient_op (GskGpuFrame *frame,
gsk_gpu_point_to_float (radius, graphene_point_zero(), &instance->center_radius[2]);
instance->startend[0] = start;
instance->startend[1] = end;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 6)].color, instance->color6);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 6)].color, ics, opacity, instance->color6);
instance->offsets1[2] = stops[MIN (n_stops - 1, 6)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 5)].color, instance->color5);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 5)].color, ics, opacity, instance->color5);
instance->offsets1[1] = stops[MIN (n_stops - 1, 5)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 4)].color, instance->color4);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 4)].color, ics, opacity, instance->color4);
instance->offsets1[0] = stops[MIN (n_stops - 1, 4)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 3)].color, instance->color3);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 3)].color, ics, opacity, instance->color3);
instance->offsets0[3] = stops[MIN (n_stops - 1, 3)].offset;
gdk_color_state_from_rgba (color_state, &stops[MIN (n_stops - 1, 2)].color, instance->color2);
gsk_gpu_color_to_float (&stops[MIN (n_stops - 1, 2)].color, ics, opacity, instance->color2);
instance->offsets0[2] = stops[MIN (n_stops - 1, 2)].offset;
gdk_color_state_from_rgba (color_state, &stops[1].color, instance->color1);
gsk_gpu_color_to_float (&stops[1].color, ics, opacity, instance->color1);
instance->offsets0[1] = stops[1].offset;
gdk_color_state_from_rgba (color_state, &stops[0].color, instance->color0);
gsk_gpu_color_to_float (&stops[0].color, ics, opacity, instance->color0);
instance->offsets0[0] = stops[0].offset;
}

View File

@ -2,7 +2,7 @@
#include "gskgpushaderopprivate.h"
#include "gskrendernode.h"
#include "gskrendernodeprivate.h"
#include <graphene.h>
@ -10,15 +10,18 @@ G_BEGIN_DECLS
void gsk_gpu_radial_gradient_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GskGpuColorStates color_states,
GdkColorState *ccs,
float opacity,
const graphene_point_t *offset,
GdkColorState *ics,
GskHueInterpolation hue_interp,
gboolean repeating,
const graphene_rect_t *rect,
const graphene_point_t *center,
const graphene_point_t *radius,
float start,
float end,
const graphene_point_t *offset,
const GskColorStop *stops,
const GskColorStop2 *stops,
gsize n_stops);

File diff suppressed because it is too large Load Diff

View File

@ -654,6 +654,18 @@ parse_color_state (GtkCssParser *parser,
return TRUE;
}
static void
clear_color_state (gpointer inout_color_state)
{
GdkColorState **cs = inout_color_state;
if (*cs)
{
gdk_color_state_unref (*cs);
*cs = NULL;
}
}
typedef struct {
Context *context;
GdkColor *color;
@ -743,25 +755,25 @@ parse_stops (GtkCssParser *parser,
gpointer out_stops)
{
GArray *stops;
GskColorStop stop;
GskColorStop2 stop;
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop));
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop2));
for (;;)
{
double dval;
double dval;
if (!gtk_css_parser_consume_number (parser, &dval))
goto error;
stop.offset = dval;
if (!gdk_rgba_parser_parse (parser, &stop.color))
if (!parse_color (parser, context, &stop.color))
goto error;
if (stops->len == 0 && stop.offset < 0)
gtk_css_parser_error_value (parser, "Color stop offset must be >= 0");
else if (stops->len > 0 && stop.offset < g_array_index (stops, GskColorStop, stops->len - 1).offset)
else if (stops->len > 0 && stop.offset < g_array_index (stops, GskColorStop2, stops->len - 1).offset)
gtk_css_parser_error_value (parser, "Color stop offset must be >= previous value");
else if (stop.offset > 1)
gtk_css_parser_error_value (parser, "Color stop offset must be <= 1");
@ -777,8 +789,7 @@ parse_stops (GtkCssParser *parser,
if (stops->len < 2)
{
gtk_css_parser_error_value (parser, "At least 2 color stops need to be specified");
g_array_free (stops, TRUE);
return FALSE;
goto error;
}
if (*(GArray **) out_stops)
@ -799,6 +810,12 @@ clear_stops (gpointer inout_stops)
if (*stops)
{
for (int i = 0; i < (*stops)->len; i++)
{
GskColorStop2 *stop = &g_array_index (*stops, GskColorStop2, i);
gdk_color_finish (&stop->color);
}
g_array_free (*stops, TRUE);
*stops = NULL;
}
@ -1685,6 +1702,28 @@ parse_color_state_rule (GtkCssParser *parser,
return TRUE;
}
static gboolean
parse_hue_interpolation (GtkCssParser *parser,
Context *context,
gpointer out_value)
{
GskHueInterpolation interpolation;
if (gtk_css_parser_try_ident (parser, "shorter"))
interpolation = GSK_HUE_INTERPOLATION_SHORTER;
else if (gtk_css_parser_try_ident (parser, "longer"))
interpolation = GSK_HUE_INTERPOLATION_LONGER;
else if (gtk_css_parser_try_ident (parser, "increasing"))
interpolation = GSK_HUE_INTERPOLATION_INCREASING;
else if (gtk_css_parser_try_ident (parser, "decreasing"))
interpolation = GSK_HUE_INTERPOLATION_DECREASING;
else
return FALSE;
*((GskHueInterpolation *)out_value) = interpolation;
return TRUE;
}
static gboolean
parse_colors4 (GtkCssParser *parser,
Context *context,
@ -1743,31 +1782,49 @@ parse_linear_gradient_node_internal (GtkCssParser *parser,
graphene_point_t start = GRAPHENE_POINT_INIT (0, 0);
graphene_point_t end = GRAPHENE_POINT_INIT (0, 50);
GArray *stops = NULL;
GdkColorState *interpolation = NULL;
GskHueInterpolation hue_interpolation = GSK_HUE_INTERPOLATION_SHORTER;
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "start", parse_point, NULL, &start },
{ "end", parse_point, NULL, &end },
{ "stops", parse_stops, clear_stops, &stops },
{ "interpolation", parse_color_state, &clear_color_state, &interpolation },
{ "hue-interpolation", parse_hue_interpolation, NULL, &hue_interpolation },
};
GskRenderNode *result;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
if (stops == NULL)
{
GskColorStop from = { 0.0, GDK_RGBA("AAFF00") };
GskColorStop to = { 1.0, GDK_RGBA("FF00CC") };
GskColorStop2 from = { 0.0, GDK_COLOR_SRGB (0.667, 1, 0, 1) };
GskColorStop2 to = { 1.0, GDK_COLOR_SRGB (1, 0, 0.8, 1) };
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop));
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop2));
g_array_append_val (stops, from);
g_array_append_val (stops, to);
}
if (repeating)
result = gsk_repeating_linear_gradient_node_new (&bounds, &start, &end, (GskColorStop *) stops->data, stops->len);
else
result = gsk_linear_gradient_node_new (&bounds, &start, &end, (GskColorStop *) stops->data, stops->len);
if (interpolation == NULL)
interpolation = GDK_COLOR_STATE_SRGB;
g_array_free (stops, TRUE);
if (repeating)
result = gsk_repeating_linear_gradient_node_new2 (&bounds,
&start, &end,
interpolation,
hue_interpolation,
(GskColorStop2 *) stops->data,
stops->len);
else
result = gsk_linear_gradient_node_new2 (&bounds,
&start, &end,
interpolation,
hue_interpolation,
(GskColorStop2 *) stops->data,
stops->len);
clear_stops (&stops);
clear_color_state (&interpolation);
return result;
}
@ -1798,6 +1855,8 @@ parse_radial_gradient_node_internal (GtkCssParser *parser,
double start = 0;
double end = 1.0;
GArray *stops = NULL;
GdkColorState *interpolation = NULL;
GskHueInterpolation hue_interpolation = GSK_HUE_INTERPOLATION_SHORTER;
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "center", parse_point, NULL, &center },
@ -1806,20 +1865,25 @@ parse_radial_gradient_node_internal (GtkCssParser *parser,
{ "start", parse_positive_double, NULL, &start },
{ "end", parse_positive_double, NULL, &end },
{ "stops", parse_stops, clear_stops, &stops },
{ "interpolation", parse_color_state, &clear_color_state, &interpolation },
{ "hue-interpolation", parse_hue_interpolation, NULL, &hue_interpolation },
};
GskRenderNode *result;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
if (stops == NULL)
{
GskColorStop from = { 0.0, GDK_RGBA("AAFF00") };
GskColorStop to = { 1.0, GDK_RGBA("FF00CC") };
GskColorStop2 from = { 0.0, GDK_COLOR_SRGB (0.667, 1, 0, 1) };
GskColorStop2 to = { 1.0, GDK_COLOR_SRGB (1, 0, 0.8, 1) };
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop));
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop2));
g_array_append_val (stops, from);
g_array_append_val (stops, to);
}
if (interpolation == NULL)
interpolation = GDK_COLOR_STATE_SRGB;
if (end <= start)
{
gtk_css_parser_error (parser,
@ -1830,13 +1894,24 @@ parse_radial_gradient_node_internal (GtkCssParser *parser,
result = NULL;
}
else if (repeating)
result = gsk_repeating_radial_gradient_node_new (&bounds, &center, hradius, vradius, start, end,
(GskColorStop *) stops->data, stops->len);
result = gsk_repeating_radial_gradient_node_new2 (&bounds, &center,
hradius, vradius,
start, end,
interpolation,
hue_interpolation,
(GskColorStop2 *) stops->data,
stops->len);
else
result = gsk_radial_gradient_node_new (&bounds, &center, hradius, vradius, start, end,
(GskColorStop *) stops->data, stops->len);
result = gsk_radial_gradient_node_new2 (&bounds, &center,
hradius, vradius,
start, end,
interpolation,
hue_interpolation,
(GskColorStop2 *) stops->data,
stops->len);
g_array_free (stops, TRUE);
clear_stops (&stops);
clear_color_state (&interpolation);
return result;
}
@ -1863,29 +1938,41 @@ parse_conic_gradient_node (GtkCssParser *parser,
graphene_point_t center = GRAPHENE_POINT_INIT (25, 25);
double rotation = 0.0;
GArray *stops = NULL;
GdkColorState *interpolation = NULL;
GskHueInterpolation hue_interpolation = GSK_HUE_INTERPOLATION_SHORTER;
const Declaration declarations[] = {
{ "bounds", parse_rect, NULL, &bounds },
{ "center", parse_point, NULL, &center },
{ "rotation", parse_double, NULL, &rotation },
{ "stops", parse_stops, clear_stops, &stops },
{ "interpolation", parse_color_state, &clear_color_state, &interpolation },
{ "hue-interpolation", parse_hue_interpolation, NULL, &hue_interpolation },
};
GskRenderNode *result;
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
if (stops == NULL)
{
GskColorStop from = { 0.0, GDK_RGBA("AAFF00") };
GskColorStop to = { 1.0, GDK_RGBA("FF00CC") };
GskColorStop2 from = { 0.0, GDK_COLOR_SRGB (0.667, 1, 0, 1) };
GskColorStop2 to = { 1.0, GDK_COLOR_SRGB (1, 0, 0.8, 1) };
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop));
stops = g_array_new (FALSE, FALSE, sizeof (GskColorStop2));
g_array_append_val (stops, from);
g_array_append_val (stops, to);
}
result = gsk_conic_gradient_node_new (&bounds, &center, rotation,
(GskColorStop *) stops->data, stops->len);
if (interpolation == NULL)
interpolation = GDK_COLOR_STATE_SRGB;
g_array_free (stops, TRUE);
result = gsk_conic_gradient_node_new2 (&bounds,
&center, rotation,
interpolation,
hue_interpolation,
(GskColorStop2 *) stops->data,
stops->len);
clear_stops (&stops);
clear_color_state (&interpolation);
return result;
}
@ -3363,12 +3450,36 @@ printer_init_duplicates_for_node (Printer *printer,
printer_init_check_color_state (printer, gsk_outset_shadow_node_get_color2 (node)->color_state);
break;
case GSK_CAIRO_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
{
const GskColorStop2 *stops = gsk_linear_gradient_node_get_color_stops2 (node);
for (int i = 0; i < gsk_linear_gradient_node_get_n_color_stops (node); i++)
printer_init_check_color_state (printer, stops[i].color.color_state);
printer_init_check_color_state (printer, gsk_linear_gradient_node_get_interpolation_color_state (node));
}
break;
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
{
const GskColorStop2 *stops = gsk_radial_gradient_node_get_color_stops2 (node);
for (int i = 0; i < gsk_radial_gradient_node_get_n_color_stops (node); i++)
printer_init_check_color_state (printer, stops[i].color.color_state);
printer_init_check_color_state (printer, gsk_radial_gradient_node_get_interpolation_color_state (node));
}
break;
case GSK_CONIC_GRADIENT_NODE:
{
const GskColorStop2 *stops = gsk_conic_gradient_node_get_color_stops2 (node);
for (int i = 0; i < gsk_conic_gradient_node_get_n_color_stops (node); i++)
printer_init_check_color_state (printer, stops[i].color.color_state);
printer_init_check_color_state (printer, gsk_conic_gradient_node_get_interpolation_color_state (node));
}
break;
case GSK_CAIRO_NODE:
/* no children */
break;
@ -3673,6 +3784,26 @@ append_unsigned_param (Printer *p,
g_string_append_printf (p->str, "%s: %u;\n", param_name, value);
}
static void
print_color_state (Printer *p,
GdkColorState *color_state)
{
if (GDK_IS_DEFAULT_COLOR_STATE (color_state))
{
g_string_append (p->str, gdk_color_state_get_name (color_state));
}
else
{
const char *name;
name = g_hash_table_lookup (p->named_color_states, color_state);
g_assert (name != NULL);
g_string_append_c (p->str, '"');
g_string_append (p->str, name);
g_string_append_c (p->str, '"');
}
}
static void
print_color (Printer *p,
const GdkColor *color)
@ -3686,19 +3817,9 @@ print_color (Printer *p,
}
else
{
if (GDK_IS_DEFAULT_COLOR_STATE (color->color_state))
{
g_string_append_printf (p->str, "color(%s ",
gdk_color_state_get_name (color->color_state));
}
else
{
const char *name = g_hash_table_lookup (p->named_color_states,
color->color_state);
g_assert (name != NULL);
g_string_append_printf (p->str, "color(\"%s\" ", name);
}
g_string_append (p->str, "color(");
print_color_state (p, color->color_state);
g_string_append_c (p->str, ' ');
string_append_double (p->str, color->r);
g_string_append_c (p->str, ' ');
string_append_double (p->str, color->g);
@ -3856,10 +3977,10 @@ append_node_param (Printer *p,
}
static void
append_stops_param (Printer *p,
const char *param_name,
const GskColorStop *stops,
gsize n_stops)
append_stops_param (Printer *p,
const char *param_name,
const GskColorStop2 *stops,
gsize n_stops)
{
gsize i;
@ -3874,11 +3995,27 @@ append_stops_param (Printer *p,
string_append_double (p->str, stops[i].offset);
g_string_append_c (p->str, ' ');
gdk_rgba_print (&stops[i].color, p->str);
print_color (p, &stops[i].color);
}
g_string_append (p->str, ";\n");
}
static void
append_color_state_param (Printer *p,
const char *param_name,
GdkColorState *color_state,
GdkColorState *default_value)
{
if (gdk_color_state_equal (color_state, default_value))
return;
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
print_color_state (p, color_state);
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
static cairo_status_t
cairo_write_array (void *closure,
const unsigned char *data,
@ -4232,6 +4369,29 @@ append_dash_param (Printer *p,
g_string_append (p->str, ";\n");
}
static const char *
hue_interpolation_to_string (GskHueInterpolation value)
{
const char *name[] = { "shorter", "longer", "increasing", "decreasing" };
return name[value];
}
static void
append_hue_interpolation_param (Printer *p,
const char *param_name,
GskHueInterpolation value,
GskHueInterpolation default_value)
{
if (value == default_value)
return;
_indent (p);
g_string_append_printf (p->str, "%s: ", param_name);
g_string_append (p->str, hue_interpolation_to_string (value));
g_string_append_c (p->str, ';');
g_string_append_c (p->str, '\n');
}
static void
render_node_print (Printer *p,
GskRenderNode *node)
@ -4302,6 +4462,8 @@ render_node_print (Printer *p,
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_LINEAR_GRADIENT_NODE:
{
GdkColorState *interpolation;
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
start_node (p, "repeating-linear-gradient", node_name);
else
@ -4310,9 +4472,15 @@ render_node_print (Printer *p,
append_rect_param (p, "bounds", &node->bounds);
append_point_param (p, "start", gsk_linear_gradient_node_get_start (node));
append_point_param (p, "end", gsk_linear_gradient_node_get_end (node));
append_stops_param (p, "stops", gsk_linear_gradient_node_get_color_stops (node, NULL),
append_stops_param (p, "stops", gsk_linear_gradient_node_get_color_stops2 (node),
gsk_linear_gradient_node_get_n_color_stops (node));
interpolation = gsk_linear_gradient_node_get_interpolation_color_state (node);
append_color_state_param (p, "interpolation", interpolation, GDK_COLOR_STATE_SRGB);
append_hue_interpolation_param (p, "hue-interpolation",
gsk_linear_gradient_node_get_hue_interpolation (node),
GSK_HUE_INTERPOLATION_SHORTER);
end_node (p);
}
break;
@ -4320,6 +4488,8 @@ render_node_print (Printer *p,
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
{
GdkColorState *interpolation;
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE)
start_node (p, "repeating-radial-gradient", node_name);
else
@ -4332,24 +4502,38 @@ render_node_print (Printer *p,
append_float_param (p, "start", gsk_radial_gradient_node_get_start (node), 0.0f);
append_float_param (p, "end", gsk_radial_gradient_node_get_end (node), 1.0f);
append_stops_param (p, "stops", gsk_radial_gradient_node_get_color_stops (node, NULL),
append_stops_param (p, "stops", gsk_radial_gradient_node_get_color_stops2 (node),
gsk_radial_gradient_node_get_n_color_stops (node));
interpolation = gsk_radial_gradient_node_get_interpolation_color_state (node);
append_color_state_param (p, "interpolation", interpolation, GDK_COLOR_STATE_SRGB);
append_hue_interpolation_param (p, "hue-interpolation",
gsk_radial_gradient_node_get_hue_interpolation (node),
GSK_HUE_INTERPOLATION_SHORTER);
end_node (p);
}
break;
case GSK_CONIC_GRADIENT_NODE:
{
GdkColorState *interpolation;
start_node (p, "conic-gradient", node_name);
append_rect_param (p, "bounds", &node->bounds);
append_point_param (p, "center", gsk_conic_gradient_node_get_center (node));
append_float_param (p, "rotation", gsk_conic_gradient_node_get_rotation (node), 0.0f);
append_stops_param (p, "stops", gsk_conic_gradient_node_get_color_stops (node, NULL),
append_stops_param (p, "stops", gsk_conic_gradient_node_get_color_stops2 (node),
gsk_conic_gradient_node_get_n_color_stops (node));
interpolation = gsk_conic_gradient_node_get_interpolation_color_state (node);
append_color_state_param (p, "interpolation", interpolation, GDK_COLOR_STATE_SRGB);
append_hue_interpolation_param (p, "hue-interpolation",
gsk_conic_gradient_node_get_hue_interpolation (node),
GSK_HUE_INTERPOLATION_SHORTER);
end_node (p);
}
break;

View File

@ -128,7 +128,6 @@ _gsk_render_node_ref (GskRenderNode *node)
GskRenderNode * gsk_color_node_new2 (const GdkColor *color,
const graphene_rect_t *bounds);
const GdkColor * gsk_color_node_get_color2 (const GskRenderNode *node);
GskRenderNode * gsk_border_node_new2 (const GskRoundedRect *outline,
@ -173,6 +172,7 @@ GskRenderNode * gsk_text_node_new2 (PangoFont
const graphene_point_t *offset);
const GdkColor *gsk_text_node_get_color2 (const GskRenderNode *node);
#define GSK_RENDER_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_RENDER_NODE, GskRenderNodeClass))
#define gsk_render_node_get_node_type(node) _gsk_render_node_get_node_type (node)
@ -184,5 +184,82 @@ _gsk_render_node_get_node_type (const GskRenderNode *node)
return GSK_RENDER_NODE_GET_CLASS (node)->node_type;
}
G_END_DECLS
typedef struct _GskColorStop2 GskColorStop2;
struct _GskColorStop2
{
float offset;
GdkColor color;
};
typedef enum
{
GSK_HUE_INTERPOLATION_SHORTER,
GSK_HUE_INTERPOLATION_LONGER,
GSK_HUE_INTERPOLATION_INCREASING,
GSK_HUE_INTERPOLATION_DECREASING,
} GskHueInterpolation;
GskRenderNode * gsk_linear_gradient_node_new2 (const graphene_rect_t *bounds,
const graphene_point_t *start,
const graphene_point_t *end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *color_stops,
gsize n_color_stops);
GskRenderNode * gsk_repeating_linear_gradient_node_new2 (const graphene_rect_t *bounds,
const graphene_point_t *start,
const graphene_point_t *end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *color_stops,
gsize n_color_stops);
const GskColorStop2 *gsk_linear_gradient_node_get_color_stops2
(const GskRenderNode *node);
GdkColorState * gsk_linear_gradient_node_get_interpolation_color_state
(const GskRenderNode *node);
GskHueInterpolation gsk_linear_gradient_node_get_hue_interpolation
(const GskRenderNode *node);
GskRenderNode * gsk_radial_gradient_node_new2 (const graphene_rect_t *bounds,
const graphene_point_t *center,
float hradius,
float vradius,
float start,
float end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *color_stops,
gsize n_color_stops);
GskRenderNode * gsk_repeating_radial_gradient_node_new2 (const graphene_rect_t *bounds,
const graphene_point_t *center,
float hradius,
float vradius,
float start,
float end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *color_stops,
gsize n_color_stops);
const GskColorStop2 *gsk_radial_gradient_node_get_color_stops2
(const GskRenderNode *node);
GdkColorState * gsk_radial_gradient_node_get_interpolation_color_state
(const GskRenderNode *node);
GskHueInterpolation gsk_radial_gradient_node_get_hue_interpolation
(const GskRenderNode *node);
GskRenderNode * gsk_conic_gradient_node_new2 (const graphene_rect_t *bounds,
const graphene_point_t *center,
float rotation,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *color_stops,
gsize n_color_stops);
const GskColorStop2 *gsk_conic_gradient_node_get_color_stops2
(const GskRenderNode *node);
GdkColorState * gsk_conic_gradient_node_get_interpolation_color_state
(const GskRenderNode *node);
GskHueInterpolation gsk_conic_gradient_node_get_hue_interpolation
(const GskRenderNode *node);
G_END_DECLS

View File

@ -1167,6 +1167,46 @@ gtk_css_color_interpolation_method_print (GtkCssColorSpace in,
/* }}} */
/* {{{ GdkColor conversion */
/*< private >
* gtk_css_color_space_get_color_state:
* @color_space: a CSS color space
*
* Returns the best-matching GdkColorState for a given CSS color
* space.
*
* Note that we don't guarantee a 1:1 match between CSS color
* spaces and color states, so conversion of the color may
* still be necessary.
*
* Returns: (transfer none): the `GdkColorState`
*/
GdkColorState *
gtk_css_color_space_get_color_state (GtkCssColorSpace color_space)
{
switch (color_space)
{
case GTK_CSS_COLOR_SPACE_SRGB:
case GTK_CSS_COLOR_SPACE_HSL:
case GTK_CSS_COLOR_SPACE_HWB:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_OKLCH:
return GDK_COLOR_STATE_SRGB;
case GTK_CSS_COLOR_SPACE_SRGB_LINEAR:
return GDK_COLOR_STATE_SRGB_LINEAR;
case GTK_CSS_COLOR_SPACE_REC2020:
case GTK_CSS_COLOR_SPACE_DISPLAY_P3:
case GTK_CSS_COLOR_SPACE_XYZ:
case GTK_CSS_COLOR_SPACE_REC2100_PQ:
return GDK_COLOR_STATE_REC2100_PQ;
break;
default:
g_assert_not_reached ();
}
}
void
gtk_css_color_to_color (const GtkCssColor *css,
GdkColor *color)
@ -1211,5 +1251,11 @@ gtk_css_color_to_color (const GtkCssColor *css,
}
}
GskHueInterpolation
gtk_css_hue_interpolation_to_hue_interpolation (GtkCssHueInterpolation interp)
{
return (GskHueInterpolation) interp;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@ -23,6 +23,7 @@
#include "gtk/css/gtkcssparserprivate.h"
#include "gtkcsstypesprivate.h"
#include "gdk/gdkcolorprivate.h"
#include "gsk/gskrendernodeprivate.h"
G_BEGIN_DECLS
@ -106,6 +107,8 @@ void gtk_css_color_space_get_coord_range (GtkCssColorSpace color_space,
float *lower,
float *upper);
GdkColorState *gtk_css_color_space_get_color_state (GtkCssColorSpace color_space);
gboolean gtk_css_color_interpolation_method_can_parse (GtkCssParser *parser);
gboolean gtk_css_color_interpolation_method_parse (GtkCssParser *parser,
@ -116,6 +119,8 @@ void gtk_css_color_interpolation_method_print (GtkCssColorSpace in,
GtkCssHueInterpolation interp,
GString *string);
GskHueInterpolation gtk_css_hue_interpolation_to_hue_interpolation (GtkCssHueInterpolation interp);
static inline gboolean
gtk_css_color_is_clear (const GtkCssColor *color)
{

View File

@ -27,6 +27,7 @@
#include "gtkcssnumbervalueprivate.h"
#include "gtkcsspositionvalueprivate.h"
#include "gtkcssprovider.h"
#include "gtksnapshotprivate.h"
G_DEFINE_TYPE (GtkCssImageConic, gtk_css_image_conic, GTK_TYPE_CSS_IMAGE)
@ -37,11 +38,11 @@ gtk_css_image_conic_snapshot (GtkCssImage *image,
double height)
{
GtkCssImageConic *self = GTK_CSS_IMAGE_CONIC (image);
GskColorStop *stops;
GskColorStop2 *stops;
int i, last;
double offset;
stops = g_newa (GskColorStop, self->n_stops);
stops = g_newa (GskColorStop2, self->n_stops);
last = -1;
offset = 0;
@ -74,7 +75,7 @@ gtk_css_image_conic_snapshot (GtkCssImage *image,
offset += step;
stops[last].offset = offset;
stops[last].color = *gtk_css_color_value_get_rgba (stop->color);
gtk_css_color_to_color (gtk_css_color_value_get_color (stop->color), &stops[last].color);
}
offset = pos;
@ -84,14 +85,18 @@ gtk_css_image_conic_snapshot (GtkCssImage *image,
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 (
gtk_snapshot_append_conic_gradient2 (
snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (_gtk_css_position_value_get_x (self->center, width),
_gtk_css_position_value_get_y (self->center, height)),
gtk_css_number_value_get (self->rotation, 360),
stops,
self->n_stops);
gtk_css_color_space_get_color_state (self->color_space),
gtk_css_hue_interpolation_to_hue_interpolation (self->hue_interp),
stops, self->n_stops);
for (i = 0; i < self->n_stops; i++)
gdk_color_finish (&stops[i].color);
}
static gboolean
@ -100,7 +105,7 @@ parse_angles (GtkCssParser *parser,
gpointer unused)
{
GtkCssValue **angles = option_data;
angles[0] = gtk_css_number_value_parse (parser, GTK_CSS_PARSE_ANGLE | GTK_CSS_PARSE_PERCENT);
if (angles[0] == NULL)
return FALSE;
@ -121,7 +126,7 @@ parse_color (GtkCssParser *parser,
gpointer unused)
{
GtkCssValue **color = option_data;
*color = gtk_css_color_value_parse (parser);
if (*color == NULL)
return FALSE;

View File

@ -27,6 +27,7 @@
#include "gtkcssnumbervalueprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssprovider.h"
#include "gtksnapshotprivate.h"
G_DEFINE_TYPE (GtkCssImageLinear, _gtk_css_image_linear, GTK_TYPE_CSS_IMAGE)
@ -140,7 +141,7 @@ gtk_css_image_linear_snapshot (GtkCssImage *image,
double height)
{
GtkCssImageLinear *linear = GTK_CSS_IMAGE_LINEAR (image);
GskColorStop *stops;
GskColorStop2 *stops;
double angle; /* actual angle of the gradient line in degrees */
double x, y; /* coordinates of start point */
double length; /* distance in pixels for 100% */
@ -192,13 +193,15 @@ gtk_css_image_linear_snapshot (GtkCssImage *image,
* get the color of the last color stop
*/
const GtkCssImageLinearColorStop *stop = &linear->color_stops[linear->n_stops - 1];
const GdkRGBA *color;
GdkColor color;
color = gtk_css_color_value_get_rgba (stop->color);
gtk_css_color_to_color (gtk_css_color_value_get_color (stop->color), &color);
gtk_snapshot_append_color (snapshot,
color,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gtk_snapshot_append_color2 (snapshot,
&color,
&GRAPHENE_RECT_INIT (0, 0, width, height));
gdk_color_finish (&color);
return;
}
}
@ -210,7 +213,7 @@ gtk_css_image_linear_snapshot (GtkCssImage *image,
offset = start;
last = -1;
stops = g_newa (GskColorStop, linear->n_stops);
stops = g_newa (GskColorStop2, linear->n_stops);
for (i = 0; i < linear->n_stops; i++)
{
@ -240,7 +243,7 @@ gtk_css_image_linear_snapshot (GtkCssImage *image,
offset += step;
stops[last].color = *gtk_css_color_value_get_rgba (stop->color);
gtk_css_color_to_color (gtk_css_color_value_get_color (stop->color), &stops[last].color);
stops[last].offset = (offset - start) / (end - start);
}
@ -253,25 +256,26 @@ gtk_css_image_linear_snapshot (GtkCssImage *image,
g_warning_once ("Gradient interpolation color spaces are not supported yet");
if (linear->repeating)
{
gtk_snapshot_append_repeating_linear_gradient (
snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (width / 2 + x * (start - 0.5), height / 2 + y * (start - 0.5)),
&GRAPHENE_POINT_INIT (width / 2 + x * (end - 0.5), height / 2 + y * (end - 0.5)),
stops,
linear->n_stops);
}
gtk_snapshot_append_repeating_linear_gradient2 (
snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (width / 2 + x * (start - 0.5), height / 2 + y * (start - 0.5)),
&GRAPHENE_POINT_INIT (width / 2 + x * (end - 0.5), height / 2 + y * (end - 0.5)),
gtk_css_color_space_get_color_state (linear->color_space),
gtk_css_hue_interpolation_to_hue_interpolation (linear->hue_interp),
stops, linear->n_stops);
else
{
gtk_snapshot_append_linear_gradient (
snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (width / 2 + x * (start - 0.5), height / 2 + y * (start - 0.5)),
&GRAPHENE_POINT_INIT (width / 2 + x * (end - 0.5), height / 2 + y * (end - 0.5)),
stops,
linear->n_stops);
}
gtk_snapshot_append_linear_gradient2 (
snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (width / 2 + x * (start - 0.5), height / 2 + y * (start - 0.5)),
&GRAPHENE_POINT_INIT (width / 2 + x * (end - 0.5), height / 2 + y * (end - 0.5)),
gtk_css_color_space_get_color_state (linear->color_space),
gtk_css_hue_interpolation_to_hue_interpolation (linear->hue_interp),
stops, linear->n_stops);
for (i = 0; i < linear->n_stops; i++)
gdk_color_finish (&stops[i].color);
}
static guint

View File

@ -28,6 +28,7 @@
#include "gtkcsspositionvalueprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssprovider.h"
#include "gtksnapshotprivate.h"
G_DEFINE_TYPE (GtkCssImageRadial, _gtk_css_image_radial, GTK_TYPE_CSS_IMAGE)
@ -80,7 +81,7 @@ gtk_css_image_radial_snapshot (GtkCssImage *image,
double height)
{
GtkCssImageRadial *radial = GTK_CSS_IMAGE_RADIAL (image);
GskColorStop *stops;
GskColorStop2 *stops;
double x, y;
double hradius, vradius;
double start, end;
@ -159,7 +160,7 @@ gtk_css_image_radial_snapshot (GtkCssImage *image,
offset = start;
last = -1;
stops = g_newa (GskColorStop, radial->n_stops);
stops = g_newa (GskColorStop2, radial->n_stops);
for (i = 0; i < radial->n_stops; i++)
{
@ -187,7 +188,7 @@ gtk_css_image_radial_snapshot (GtkCssImage *image,
offset += step;
stops[last].offset = (offset - start) / (end - start);
stops[last].color = *gtk_css_color_value_get_rgba (stop->color);
gtk_css_color_to_color (gtk_css_color_value_get_color (stop->color), &stops[last].color);
}
offset = pos;
@ -198,25 +199,26 @@ gtk_css_image_radial_snapshot (GtkCssImage *image,
g_warning_once ("Gradient interpolation color spaces are not supported yet");
if (radial->repeating)
gtk_snapshot_append_repeating_radial_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (x, y),
hradius,
vradius,
start,
end,
stops,
radial->n_stops);
gtk_snapshot_append_repeating_radial_gradient2 (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (x, y),
hradius, vradius,
start, end,
gtk_css_color_space_get_color_state (radial->color_space),
gtk_css_hue_interpolation_to_hue_interpolation (radial->hue_interp),
stops, radial->n_stops);
else
gtk_snapshot_append_radial_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (x, y),
hradius,
vradius,
start,
end,
stops,
radial->n_stops);
gtk_snapshot_append_radial_gradient2 (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (x, y),
hradius, vradius,
start, end,
gtk_css_color_space_get_color_state (radial->color_space),
gtk_css_hue_interpolation_to_hue_interpolation (radial->hue_interp),
stops, radial->n_stops);
for (i = 0; i < radial->n_stops; i++)
gdk_color_finish (&stops[i].color);
}
static guint

View File

@ -2522,11 +2522,55 @@ gtk_snapshot_append_linear_gradient (GtkSnapshot *snapshot,
const graphene_point_t *end_point,
const GskColorStop *stops,
gsize n_stops)
{
GskColorStop2 *stops2;
stops2 = g_new (GskColorStop2, n_stops);
for (gsize i = 0; i < n_stops; i++)
{
stops2[i].offset = stops[i].offset;
gdk_color_init_from_rgba (&stops2[i].color, &stops[i].color);
}
gtk_snapshot_append_linear_gradient2 (snapshot, bounds,
start_point, end_point,
GDK_COLOR_STATE_SRGB,
GSK_HUE_INTERPOLATION_SHORTER,
stops2, n_stops);
for (gsize i = 0; i < n_stops; i++)
gdk_color_finish (&stops2[i].color);
g_free (stops2);
}
/*< private >
* gtk_snapshot_append_linear_gradient2:
* @snapshot: a `GtkSnapshot`
* @bounds: the rectangle to render the linear gradient into
* @start_point: the point at which the linear gradient will begin
* @end_point: the point at which the linear gradient will finish
* @interpolation: the color state to interpolate in
* @hue_interpolation: how to interpolate if @interpolation is polar
* @stops: (array length=n_stops): the color stops defining the gradient
* @n_stops: the number of elements in @stops
*
* Appends a linear gradient node with the given stops to @snapshot.
*/
void
gtk_snapshot_append_linear_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *start_point,
const graphene_point_t *end_point,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops)
{
GskRenderNode *node;
graphene_rect_t real_bounds;
float scale_x, scale_y, dx, dy;
const GdkRGBA *first_color;
const GdkColor *first_color;
gboolean need_gradient = FALSE;
g_return_if_fail (snapshot != NULL);
@ -2542,9 +2586,9 @@ gtk_snapshot_append_linear_gradient (GtkSnapshot *snapshot,
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &real_bounds);
first_color = &stops[0].color;
for (gsize i = 0; i < n_stops; i ++)
for (gsize i = 1; i < n_stops; i ++)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
@ -2560,15 +2604,16 @@ gtk_snapshot_append_linear_gradient (GtkSnapshot *snapshot,
real_end_point.x = scale_x * end_point->x + dx;
real_end_point.y = scale_y * end_point->y + dy;
node = gsk_linear_gradient_node_new (&real_bounds,
&real_start_point,
&real_end_point,
stops,
n_stops);
node = gsk_linear_gradient_node_new2 (&real_bounds,
&real_start_point,
&real_end_point,
interpolation,
hue_interpolation,
stops, n_stops);
}
else
{
node = gsk_color_node_new (first_color, &real_bounds);
node = gsk_color_node_new2 (first_color, &real_bounds);
}
gtk_snapshot_append_node_internal (snapshot, node);
@ -2592,12 +2637,56 @@ gtk_snapshot_append_repeating_linear_gradient (GtkSnapshot *snapshot,
const graphene_point_t *end_point,
const GskColorStop *stops,
gsize n_stops)
{
GskColorStop2 *stops2;
stops2 = g_new (GskColorStop2, n_stops);
for (gsize i = 0; i < n_stops; i++)
{
stops2[i].offset = stops[i].offset;
gdk_color_init_from_rgba (&stops2[i].color, &stops[i].color);
}
gtk_snapshot_append_repeating_linear_gradient2 (snapshot, bounds,
start_point, end_point,
GDK_COLOR_STATE_SRGB,
GSK_HUE_INTERPOLATION_SHORTER,
stops2, n_stops);
for (gsize i = 0; i < n_stops; i++)
gdk_color_finish (&stops2[i].color);
g_free (stops2);
}
/*< private >
* gtk_snapshot_append_repeating_linear_gradient2:
* @snapshot: a `GtkSnapshot`
* @bounds: the rectangle to render the linear gradient into
* @start_point: the point at which the linear gradient will begin
* @end_point: the point at which the linear gradient will finish
* @interpolation: the color state to interpolate in
* @hue_interpolation: how to interpolate if @interpolation is polar
* @stops: (array length=n_stops): the color stops defining the gradient
* @n_stops: the number of elements in @stops
*
* Appends a repeating linear gradient node with the given stops to @snapshot.
*/
void
gtk_snapshot_append_repeating_linear_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *start_point,
const graphene_point_t *end_point,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops)
{
GskRenderNode *node;
graphene_rect_t real_bounds;
float scale_x, scale_y, dx, dy;
gboolean need_gradient = FALSE;
const GdkRGBA *first_color;
const GdkColor *first_color;
g_return_if_fail (snapshot != NULL);
g_return_if_fail (start_point != NULL);
@ -2609,9 +2698,9 @@ gtk_snapshot_append_repeating_linear_gradient (GtkSnapshot *snapshot,
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &real_bounds);
first_color = &stops[0].color;
for (gsize i = 0; i < n_stops; i ++)
for (gsize i = 1; i < n_stops; i ++)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
@ -2627,15 +2716,16 @@ gtk_snapshot_append_repeating_linear_gradient (GtkSnapshot *snapshot,
real_end_point.x = scale_x * end_point->x + dx;
real_end_point.y = scale_y * end_point->y + dy;
node = gsk_repeating_linear_gradient_node_new (&real_bounds,
&real_start_point,
&real_end_point,
stops,
n_stops);
node = gsk_repeating_linear_gradient_node_new2 (&real_bounds,
&real_start_point,
&real_end_point,
interpolation,
hue_interpolation,
stops, n_stops);
}
else
{
node = gsk_color_node_new (first_color, &real_bounds);
node = gsk_color_node_new2 (first_color, &real_bounds);
}
gtk_snapshot_append_node_internal (snapshot, node);
@ -2660,11 +2750,56 @@ gtk_snapshot_append_conic_gradient (GtkSnapshot *snapshot,
float rotation,
const GskColorStop *stops,
gsize n_stops)
{
GskColorStop2 *stops2;
stops2 = g_new (GskColorStop2, n_stops);
for (gsize i = 0; i < n_stops; i++)
{
stops2[i].offset = stops[i].offset;
gdk_color_init_from_rgba (&stops2[i].color, &stops[i].color);
}
gtk_snapshot_append_conic_gradient2 (snapshot, bounds,
center, rotation,
GDK_COLOR_STATE_SRGB,
GSK_HUE_INTERPOLATION_SHORTER,
stops2, n_stops);
for (gsize i = 0; i < n_stops; i++)
gdk_color_finish (&stops2[i].color);
g_free (stops2);
}
/*< private >
* gtk_snapshot_append_conic_gradient2:
* @snapshot: a `GtkSnapshot`
* @bounds: the rectangle to render the gradient into
* @center: the center point of the conic gradient
* @rotation: the clockwise rotation in degrees of the starting angle.
* 0 means the starting angle is the top.
* @interpolate: the color state to interpolate in
* @hue_interpolation: how to interpolate if @interpolation is polar
* @stops: (array length=n_stops): the color stops defining the gradient
* @n_stops: the number of elements in @stops
*
* Appends a conic gradient node with the given stops to @snapshot.
*/
void
gtk_snapshot_append_conic_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *center,
float rotation,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops)
{
GskRenderNode *node;
graphene_rect_t real_bounds;
float dx, dy;
const GdkRGBA *first_color;
const GdkColor *first_color;
gboolean need_gradient = FALSE;
int i;
@ -2677,9 +2812,9 @@ gtk_snapshot_append_conic_gradient (GtkSnapshot *snapshot,
graphene_rect_offset_r (bounds, dx, dy, &real_bounds);
first_color = &stops[0].color;
for (i = 0; i < n_stops; i ++)
for (i = 1; i < n_stops; i ++)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
@ -2687,16 +2822,17 @@ gtk_snapshot_append_conic_gradient (GtkSnapshot *snapshot,
}
if (need_gradient)
node = gsk_conic_gradient_node_new (&real_bounds,
&GRAPHENE_POINT_INIT(
center->x + dx,
center->y + dy
),
rotation,
stops,
n_stops);
node = gsk_conic_gradient_node_new2 (&real_bounds,
&GRAPHENE_POINT_INIT(
center->x + dx,
center->y + dy
),
rotation,
interpolation,
hue_interpolation,
stops, n_stops);
else
node = gsk_color_node_new (first_color, &real_bounds);
node = gsk_color_node_new2 (first_color, &real_bounds);
gtk_snapshot_append_node_internal (snapshot, node);
}
@ -2725,12 +2861,64 @@ gtk_snapshot_append_radial_gradient (GtkSnapshot *snapshot,
float end,
const GskColorStop *stops,
gsize n_stops)
{
GskColorStop2 *stops2;
stops2 = g_new (GskColorStop2, n_stops);
for (gsize i = 0; i < n_stops; i++)
{
stops2[i].offset = stops[i].offset;
gdk_color_init_from_rgba (&stops2[i].color, &stops[i].color);
}
gtk_snapshot_append_radial_gradient2 (snapshot,
bounds, center,
hradius, vradius,
start, end,
GDK_COLOR_STATE_SRGB,
GSK_HUE_INTERPOLATION_SHORTER,
stops2, n_stops);
for (gsize i = 0; i < n_stops; i++)
gdk_color_finish (&stops2[i].color);
g_free (stops2);
}
/*< private>
* gtk_snapshot_append_radial_gradient2:
* @snapshot: a `GtkSnapshot`
* @bounds: the rectangle to render the readial gradient into
* @center: the center point for the radial gradient
* @hradius: the horizontal radius
* @vradius: the vertical radius
* @start: the start position (on the horizontal axis)
* @end: the end position (on the horizontal axis)
* @interpolation: the color state to interpolate in
* @hue_interpolation: how to interpolate if @interpolation is polar
* @stops: (array length=n_stops): the color stops defining the gradient
* @n_stops: the number of elements in @stops
*
* Appends a radial gradient node with the given stops to @snapshot.
*/
void
gtk_snapshot_append_radial_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *center,
float hradius,
float vradius,
float start,
float end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops)
{
GskRenderNode *node;
graphene_rect_t real_bounds;
float scale_x, scale_y, dx, dy;
gboolean need_gradient = FALSE;
const GdkRGBA *first_color;
const GdkColor *first_color;
g_return_if_fail (snapshot != NULL);
g_return_if_fail (center != NULL);
@ -2741,9 +2929,9 @@ gtk_snapshot_append_radial_gradient (GtkSnapshot *snapshot,
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &real_bounds);
first_color = &stops[0].color;
for (gsize i = 0; i < n_stops; i ++)
for (gsize i = 1; i < n_stops; i ++)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
@ -2757,18 +2945,18 @@ gtk_snapshot_append_radial_gradient (GtkSnapshot *snapshot,
real_center.x = scale_x * center->x + dx;
real_center.y = scale_y * center->y + dy;
node = gsk_radial_gradient_node_new (&real_bounds,
&real_center,
hradius * scale_x,
vradius * scale_y,
start,
end,
stops,
n_stops);
node = gsk_radial_gradient_node_new2 (&real_bounds,
&real_center,
hradius * scale_x,
vradius * scale_y,
start, end,
interpolation,
hue_interpolation,
stops, n_stops);
}
else
{
node = gsk_color_node_new (first_color, &real_bounds);
node = gsk_color_node_new2 (first_color, &real_bounds);
}
gtk_snapshot_append_node_internal (snapshot, node);
@ -2798,12 +2986,64 @@ gtk_snapshot_append_repeating_radial_gradient (GtkSnapshot *snapshot,
float end,
const GskColorStop *stops,
gsize n_stops)
{
GskColorStop2 *stops2;
stops2 = g_new (GskColorStop2, n_stops);
for (gsize i = 0; i < n_stops; i++)
{
stops2[i].offset = stops[i].offset;
gdk_color_init_from_rgba (&stops2[i].color, &stops[i].color);
}
gtk_snapshot_append_repeating_radial_gradient2 (snapshot,
bounds, center,
hradius, vradius,
start, end,
GDK_COLOR_STATE_SRGB,
GSK_HUE_INTERPOLATION_SHORTER,
stops2, n_stops);
for (gsize i = 0; i < n_stops; i++)
gdk_color_finish (&stops2[i].color);
g_free (stops2);
}
/*< private >
* gtk_snapshot_append_repeating_radial_gradient2:
* @snapshot: a `GtkSnapshot`
* @bounds: the rectangle to render the readial gradient into
* @center: the center point for the radial gradient
* @hradius: the horizontal radius
* @vradius: the vertical radius
* @start: the start position (on the horizontal axis)
* @end: the end position (on the horizontal axis)
* @interpolation: the color state to interpolate in
* @hue_interpolation: how to interpolate if @interpolation is polar
* @stops: (array length=n_stops): the color stops defining the gradient
* @n_stops: the number of elements in @stops
*
* Appends a repeating radial gradient node with the given stops to @snapshot.
*/
void
gtk_snapshot_append_repeating_radial_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *center,
float hradius,
float vradius,
float start,
float end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops)
{
GskRenderNode *node;
graphene_rect_t real_bounds;
float scale_x, scale_y, dx, dy;
gboolean need_gradient = FALSE;
const GdkRGBA *first_color;
const GdkColor *first_color;
g_return_if_fail (snapshot != NULL);
g_return_if_fail (center != NULL);
@ -2814,9 +3054,9 @@ gtk_snapshot_append_repeating_radial_gradient (GtkSnapshot *snapshot,
gtk_graphene_rect_scale_affine (bounds, scale_x, scale_y, dx, dy, &real_bounds);
first_color = &stops[0].color;
for (gsize i = 0; i < n_stops; i ++)
for (gsize i = 1; i < n_stops; i ++)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
@ -2829,18 +3069,18 @@ gtk_snapshot_append_repeating_radial_gradient (GtkSnapshot *snapshot,
real_center.x = scale_x * center->x + dx;
real_center.y = scale_y * center->y + dy;
node = gsk_repeating_radial_gradient_node_new (&real_bounds,
&real_center,
hradius * scale_x,
vradius * scale_y,
start,
end,
stops,
n_stops);
node = gsk_repeating_radial_gradient_node_new2 (&real_bounds,
&real_center,
hradius * scale_x,
vradius * scale_y,
start, end,
interpolation,
hue_interpolation,
stops, n_stops);
}
else
{
node = gsk_color_node_new (first_color, &real_bounds);
node = gsk_color_node_new2 (first_color, &real_bounds);
}
gtk_snapshot_append_node_internal (snapshot, node);

View File

@ -73,5 +73,54 @@ void gtk_snapshot_push_shadow2 (GtkSnapshot
const GskShadow2 *shadow,
gsize n_shadows);
G_END_DECLS
void gtk_snapshot_append_linear_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *start_point,
const graphene_point_t *end_point,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops);
void gtk_snapshot_append_repeating_linear_gradient2
(GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *start_point,
const graphene_point_t *end_point,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops);
void gtk_snapshot_append_radial_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *center,
float hradius,
float vradius,
float start,
float end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops);
void gtk_snapshot_append_repeating_radial_gradient2
(GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *center,
float hradius,
float vradius,
float start,
float end,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops);
void gtk_snapshot_append_conic_gradient2 (GtkSnapshot *snapshot,
const graphene_rect_t *bounds,
const graphene_point_t *center,
float rotation,
GdkColorState *interpolation,
GskHueInterpolation hue_interpolation,
const GskColorStop2 *stops,
gsize n_stops);
G_END_DECLS

View File

@ -60,6 +60,7 @@
#include "gtk/gtkdebug.h"
#include "gtk/gtkbuiltiniconprivate.h"
#include "gtk/gtkrendernodepaintableprivate.h"
#include "gdk/gdkcairoprivate.h"
#include "recording.h"
#include "renderrecording.h"
@ -845,7 +846,7 @@ get_color2_texture (const GdkColor *color)
}
static GdkTexture *
get_linear_gradient_texture (gsize n_stops, const GskColorStop *stops)
get_linear_gradient_texture (gsize n_stops, const GskColorStop2 *stops)
{
cairo_surface_t *surface;
cairo_t *cr;
@ -858,14 +859,7 @@ get_linear_gradient_texture (gsize n_stops, const GskColorStop *stops)
pattern = cairo_pattern_create_linear (0, 0, 90, 0);
for (i = 0; i < n_stops; i++)
{
cairo_pattern_add_color_stop_rgba (pattern,
stops[i].offset,
stops[i].color.red,
stops[i].color.green,
stops[i].color.blue,
stops[i].color.alpha);
}
gdk_cairo_pattern_add_color_stop_color (pattern, GDK_COLOR_STATE_SRGB, stops[i].offset, &stops[i].color);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
@ -972,6 +966,14 @@ enum_to_nick (GType type,
return v->value_nick;
}
static const char *
hue_interpolation_to_string (GskHueInterpolation value)
{
const char *name[] = { "shorter", "longer", "increasing", "decreasing" };
return name[value];
}
static void
add_texture_rows (GListStore *store,
GdkTexture *texture)
@ -1115,18 +1117,22 @@ populate_render_node_properties (GListStore *store,
const graphene_point_t *start = gsk_linear_gradient_node_get_start (node);
const graphene_point_t *end = gsk_linear_gradient_node_get_end (node);
const gsize n_stops = gsk_linear_gradient_node_get_n_color_stops (node);
const GskColorStop *stops = gsk_linear_gradient_node_get_color_stops (node, NULL);
const GskColorStop2 *stops = gsk_linear_gradient_node_get_color_stops2 (node);
GdkColorState *interpolation = gsk_linear_gradient_node_get_interpolation_color_state (node);
GskHueInterpolation hue_interpolation = gsk_linear_gradient_node_get_hue_interpolation (node);
int i;
GString *s;
GdkTexture *texture;
add_text_row (store, "Direction", "%.2f %.2f ⟶ %.2f %.2f", start->x, start->y, end->x, end->y);
add_text_row (store, "Interpolation", "%s", gdk_color_state_get_name (interpolation));
add_text_row (store, "Hue Interpolation", "%s", hue_interpolation_to_string (hue_interpolation));
s = g_string_new ("");
for (i = 0; i < n_stops; i++)
{
g_string_append_printf (s, "%.2f, ", stops[i].offset);
gdk_rgba_print (&stops[i].color, s);
gdk_color_print (&stops[i].color, s);
g_string_append_c (s, '\n');
}
@ -1147,7 +1153,9 @@ populate_render_node_properties (GListStore *store,
const float hradius = gsk_radial_gradient_node_get_hradius (node);
const float vradius = gsk_radial_gradient_node_get_vradius (node);
const gsize n_stops = gsk_radial_gradient_node_get_n_color_stops (node);
const GskColorStop *stops = gsk_radial_gradient_node_get_color_stops (node, NULL);
const GskColorStop2 *stops = gsk_radial_gradient_node_get_color_stops2 (node);
GdkColorState *interpolation = gsk_radial_gradient_node_get_interpolation_color_state (node);
GskHueInterpolation hue_interpolation = gsk_radial_gradient_node_get_hue_interpolation (node);
int i;
GString *s;
GdkTexture *texture;
@ -1155,12 +1163,14 @@ populate_render_node_properties (GListStore *store,
add_text_row (store, "Center", "%.2f, %.2f", center->x, center->y);
add_text_row (store, "Direction", "%.2f ⟶ %.2f", start, end);
add_text_row (store, "Radius", "%.2f, %.2f", hradius, vradius);
add_text_row (store, "Interpolation", "%s", gdk_color_state_get_name (interpolation));
add_text_row (store, "Hue Interpolation", "%s", hue_interpolation_to_string (hue_interpolation));
s = g_string_new ("");
for (i = 0; i < n_stops; i++)
{
g_string_append_printf (s, "%.2f, ", stops[i].offset);
gdk_rgba_print (&stops[i].color, s);
gdk_color_print (&stops[i].color, s);
g_string_append_c (s, '\n');
}
@ -1177,19 +1187,23 @@ populate_render_node_properties (GListStore *store,
const graphene_point_t *center = gsk_conic_gradient_node_get_center (node);
const float rotation = gsk_conic_gradient_node_get_rotation (node);
const gsize n_stops = gsk_conic_gradient_node_get_n_color_stops (node);
const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node, NULL);
const GskColorStop2 *stops = gsk_conic_gradient_node_get_color_stops2 (node);
GdkColorState *interpolation = gsk_conic_gradient_node_get_interpolation_color_state (node);
GskHueInterpolation hue_interpolation = gsk_conic_gradient_node_get_hue_interpolation (node);
gsize i;
GString *s;
GdkTexture *texture;
add_text_row (store, "Center", "%.2f, %.2f", center->x, center->y);
add_text_row (store, "Rotation", "%.2f", rotation);
add_text_row (store, "Interpolation", "%s", gdk_color_state_get_name (interpolation));
add_text_row (store, "Hue Interpolation", "%s", hue_interpolation_to_string (hue_interpolation));
s = g_string_new ("");
for (i = 0; i < n_stops; i++)
{
g_string_append_printf (s, "%.2f, ", stops[i].offset);
gdk_rgba_print (&stops[i].color, s);
gdk_color_print (&stops[i].color, s);
g_string_append_c (s, '\n');
}

View File

@ -0,0 +1,19 @@
color-matrix {
matrix: matrix3d(255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0, 1);
child: blend {
mode: difference;
bottom: linear-gradient {
bounds: 0 0 50 50;
start: 0 -25;
end: 0 75;
stops: 0 rgb(255,0,0), 1 rgb(255,255,0);
}
top: linear-gradient {
bounds: 0 0 50 50;
start: 0 -25;
end: 0 75;
stops: 0 rgb(255,0,0), 1 rgb(255,255,0);
interpolation: srgb-linear;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

View File

@ -100,6 +100,7 @@ compare_render_tests = [
'inset-shadow-multiple',
'invalid-transform',
'issue-3615',
'linear-gradient-interpolation-nogl-nocairo',
'linear-gradient-3d-nocairo',
'linear-gradient-nonorthogonal-scale-nogl',
'linear-gradient-premultiplied-nocairo',
@ -404,6 +405,8 @@ node_parser_tests = [
'gradient-fail.node',
'gradient-fail.ref.node',
'gradient-fail.errors',
'gradients.node',
'gradients.ref.node',
'mask-modes.node',
'mask-modes.ref.node',
'node-names.node',

View File

@ -2,5 +2,5 @@ linear-gradient {
bounds: 0 0 50 50;
start: 0 0;
end: 0 50;
stops: 0 rgb(170,255,0), 1 rgb(255,0,204);
stops: 0 color(srgb 0.667 1 0), 1 rgb(255,0,204);
}

View File

@ -0,0 +1,35 @@
@cicp "cicp1" {
primaries: 6;
transfer: 6;
matrix: 0;
range: full;
}
linear-gradient {
bounds: 10 10 100 100;
start: 2 3;
end: 20 40;
stops: 0 rgb(0, 0, 0), 0.5 color(rec2100-pq 0.4 0.5 0.6), 1 #AF0;
interpolation: srgb;
hue-interpolation: longer;
}
radial-gradient {
bounds: 10 10 100 100;
center: 25 26;
hradius: 10;
vradius: 20;
start: 0.1;
end: 0.9;
stops: 0 rgb(0, 0, 0), 0.5 color(rec2100-pq 0.4 0.5 0.6), 1 #AF0;
interpolation: rec2100-pq;
hue-interpolation: increasing;
}
conic-gradient {
bounds: 10 10 100 100;
center: 25 26;
rotation: 200;
stops: 0 rgb(0, 0, 0), 0.5 color(rec2100-pq 0.4 0.5 0.6), 1 #AF0;
interpolation: "cicp1";
}

View File

@ -0,0 +1,30 @@
@cicp "cicp1" {
primaries: 6;
transfer: 6;
matrix: 0;
}
linear-gradient {
bounds: 10 10 100 100;
start: 2 3;
end: 20 40;
stops: 0 rgb(0,0,0), 0.5 color(rec2100-pq 0.4 0.5 0.6), 1 rgb(170,255,0);
hue-interpolation: longer;
}
radial-gradient {
bounds: 10 10 100 100;
center: 25 26;
hradius: 10;
vradius: 20;
start: 0.1;
end: 0.9;
stops: 0 rgb(0,0,0), 0.5 color(rec2100-pq 0.4 0.5 0.6), 1 rgb(170,255,0);
interpolation: rec2100-pq;
hue-interpolation: increasing;
}
conic-gradient {
bounds: 10 10 100 100;
center: 25 26;
rotation: 200;
stops: 0 rgb(0,0,0), 0.5 color(rec2100-pq 0.4 0.5 0.6), 1 rgb(170,255,0);
interpolation: "cicp1";
}

View File

@ -3,12 +3,12 @@ radial-gradient {
center: 25 25;
hradius: 25;
vradius: 25;
stops: 0 rgb(170,255,0), 1 rgb(255,0,204);
stops: 0 color(srgb 0.667 1 0), 1 rgb(255,0,204);
}
radial-gradient {
bounds: 0 0 50 50;
center: 25 25;
hradius: 25;
vradius: 25;
stops: 0 rgb(170,255,0), 1 rgb(255,0,204);
stops: 0 color(srgb 0.667 1 0), 1 rgb(255,0,204);
}

View File

@ -40,22 +40,29 @@ replay_linear_gradient_node (GskRenderNode *node, GtkSnapshot *snapshot)
{
graphene_rect_t bounds;
const graphene_point_t *start_point, *end_point;
const GskColorStop *stops;
gsize n_stops = 0;
const GskColorStop2 *stops;
gsize n_stops;
GskHueInterpolation hue;
GdkColorState *interp;
gsk_render_node_get_bounds (node, &bounds);
start_point = gsk_linear_gradient_node_get_start (node);
end_point = gsk_linear_gradient_node_get_end (node);
stops = gsk_linear_gradient_node_get_color_stops (node, &n_stops);
n_stops = gsk_linear_gradient_node_get_n_color_stops (node);
stops = gsk_linear_gradient_node_get_color_stops2 (node);
interp = gsk_linear_gradient_node_get_interpolation_color_state (node);
hue = gsk_linear_gradient_node_get_hue_interpolation (node);
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_LINEAR_GRADIENT_NODE)
gtk_snapshot_append_repeating_linear_gradient (snapshot, &bounds,
start_point, end_point,
stops, n_stops);
gtk_snapshot_append_repeating_linear_gradient2 (snapshot, &bounds,
start_point, end_point,
interp, hue,
stops, n_stops);
else
gtk_snapshot_append_linear_gradient (snapshot, &bounds,
start_point, end_point,
stops, n_stops);
gtk_snapshot_append_linear_gradient2 (snapshot, &bounds,
start_point, end_point,
interp, hue,
stops, n_stops);
}
static void
@ -68,18 +75,21 @@ replay_radial_gradient_node (GskRenderNode *node, GtkSnapshot *snapshot)
float vradius = gsk_radial_gradient_node_get_vradius (node);
float start = gsk_radial_gradient_node_get_start (node);
float end = gsk_radial_gradient_node_get_end (node);
gsize n_stops = 0;
const GskColorStop *stops = gsk_radial_gradient_node_get_color_stops (node,
&n_stops);
gsize n_stops = gsk_radial_gradient_node_get_n_color_stops (node);
const GskColorStop2 *stops = gsk_radial_gradient_node_get_color_stops2 (node);
GskHueInterpolation hue = gsk_radial_gradient_node_get_hue_interpolation (node);
GdkColorState *interp = gsk_radial_gradient_node_get_interpolation_color_state (node);
if (gsk_render_node_get_node_type (node) == GSK_REPEATING_RADIAL_GRADIENT_NODE)
gtk_snapshot_append_repeating_radial_gradient (snapshot, &bounds, center,
hradius, vradius, start, end,
stops, n_stops);
gtk_snapshot_append_repeating_radial_gradient2 (snapshot, &bounds, center,
hradius, vradius, start, end,
interp, hue,
stops, n_stops);
else
gtk_snapshot_append_radial_gradient (snapshot, &bounds, center,
hradius, vradius, start, end,
stops, n_stops);
gtk_snapshot_append_radial_gradient2 (snapshot, &bounds, center,
hradius, vradius, start, end,
interp, hue,
stops, n_stops);
}
static void
@ -89,12 +99,15 @@ replay_conic_gradient_node (GskRenderNode *node, GtkSnapshot *snapshot)
gsk_render_node_get_bounds (node, &bounds);
const graphene_point_t *center = gsk_conic_gradient_node_get_center (node);
float rotation = gsk_conic_gradient_node_get_rotation (node);
gsize n_stops = 0;
const GskColorStop *stops = gsk_conic_gradient_node_get_color_stops (node,
&n_stops);
gsize n_stops = gsk_conic_gradient_node_get_n_color_stops (node);
const GskColorStop2 *stops = gsk_conic_gradient_node_get_color_stops2 (node);
GskHueInterpolation hue = gsk_conic_gradient_node_get_hue_interpolation (node);
GdkColorState *interp = gsk_conic_gradient_node_get_interpolation_color_state (node);
gtk_snapshot_append_conic_gradient (snapshot, &bounds, center,
rotation, stops, n_stops);
gtk_snapshot_append_conic_gradient2 (snapshot, &bounds, center,
rotation,
interp, hue,
stops, n_stops);
}
static void