Compare commits

...

21 Commits

Author SHA1 Message Date
Matthias Clasen d14a5acd4e gsk: Support hue interpolation in cairo
Since cairos gradient code isn't flexible enough  to let us
interpolate in oklch, add additional color stops and let cairo
interpolate in the ccs. This isn't as accurate as interpolating
in oklch, but it gets an ok result for fallback situations.
2024-10-04 23:32:44 -04:00
Matthias Clasen 4de67b2fe5 gtk: Don't optimize gradients away too eagerly
Even if the stops are the same color, with hue interpolation,
it might still make a beautiful rainbow.
2024-10-04 21:21:32 -04:00
Matthias Clasen 6d878bd21c css: Pass oklab and oklch color states through 2024-10-04 21:16:36 -04:00
Matthias Clasen 965fd476a5 node parser: handle oklab and oklch 2024-10-04 21:16:36 -04:00
Matthias Clasen 3bce60c433 gsk: Handle hue-interpolation in ops
Make all our gradient ops adjust the hue according to
the hue interpolation.

This is currently modifying the values in the vertex array.
If reading those values back is bad, we may need to change that.
2024-10-04 21:16:36 -04:00
Matthias Clasen 8083456599 gsk: Handle oklab and oklch color states 2024-10-04 21:16:35 -04:00
Matthias Clasen 2a1b8c4fcc gdk: Add oklab and oklch color states
These are new default color states.

Tests for the tf and matrices included.
2024-10-04 20:37:09 -04:00
Matthias Clasen ed9e759917 Add a test for gradient rendering
This tests that gradients get interpolated differently in
srgb and rec2100-linear.
2024-10-04 17:13:27 -04:00
Matthias Clasen f69d7f804a tests: Use the new gradient node apis
Properly replay gradient nodes with color state information.
2024-10-04 17:13:27 -04:00
Matthias Clasen 4368583cbe gsk: Make non-default interpolation cs work
If the interpolation color state is not a default one, use the
offscreen we already for rendering big gradients, interpolate
the gradient into it, and then use a cicp convert shader to
convert the result to the ccs.
2024-10-04 15:08:34 -04:00
Matthias Clasen c44efc31ba inspector: Show full gradient information
Use the new gradient apis to show color stops, and show
interpolation color state and hue interpolation as well.
2024-10-04 15:08:34 -04:00
Matthias Clasen 3c6cc6c362 gtk: Use the new private snapshot api
Preserve color states from css as much as possible.
2024-10-04 15:08:34 -04:00
Matthias Clasen eff0d5b37b gtk: Add new snapshot api for gradients
These are private snapshot apis that uses the new gradient node
constructors to create nodes with the given color states.
2024-10-04 15:08:34 -04:00
Matthias Clasen 579878a855 css: Add helper functions
We need to be able to translate css color spaces into gdk color
states, and css hue interplation into gsk hue interpolation.
2024-10-04 15:08:34 -04:00
Matthias Clasen b43294c1c3 nodeparser: Handle color states for gradients
Test included.
2024-10-04 15:08:34 -04:00
Matthias Clasen 5d8e801d80 gsk: Use new gradient node apis
This requires changing the gradient ops again too,
so we can pass GskColorStop2 arrays to them.
2024-10-04 14:51:33 -04:00
Matthias Clasen 4c7631a645 gsk: Add new private gradient node api
These new apis take GskColorStop2 instead of GskColorStop.
2024-10-04 14:50:23 -04:00
Matthias Clasen 9fe78d9f75 cairo: Add gdk_cairo_pattern_add_color_stop_color
This is a generalization of gdk_cairo_pattern_add_color_stop_rgba_ccs
to allow non-sRGB sources.
2024-10-04 14:50:23 -04:00
Matthias Clasen 9a7d84b441 gsk: Change gradient op apis
Pass the ccs, opacity, interpolation color state and hue
interpolation explicitly, and change the argument order to
match other ops.

Since we now apply opacity in the op, change the node processor
to pass colors as-is. For now, it always passes GDK_COLOR_STATE_SRGB
for ics and GSK_HUE_INTERPOLATION_SHORTER for hue interpolation.
2024-10-04 14:50:11 -04:00
Matthias Clasen 1fe9918f3c gsk: Add GskHueInterpolation enum
This will be used in gradient-related apis.
2024-10-04 14:48:50 -04:00
Matthias Clasen cd04aa1cd4 gsk: Change a precondition
It is nicer if gsk_gpu_color_states_create_explicit (a, a) works
regardless of whether the two are default colorstates or not.

The gradient shaders will rely on this when the ics is a non-default
color state and we use ccs == ics.
2024-10-04 14:48:50 -04:00
36 changed files with 2544 additions and 506 deletions
+31 -21
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.
+12
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)
+50
View File
@@ -233,3 +233,53 @@ static const float srgb_to_rec2020[9] = {
0.069108, 0.919519, 0.011360,
0.016394, 0.088011, 0.895380,
};
/* oklab conversion */
static float
from_oklab_nl (float v)
{
return v * v * v;
}
static float
to_oklab_nl (float v)
{
return cbrtf (v);
}
static const float oklab_to_lms[9] = {
1, 0.3963377774, 0.2158037573,
1, -0.1055613458, -0.0638541728,
1, -0.0894841775, -1.2914855480
};
static const float lms_to_srgb[9] = {
4.0767416621, -3.3077115913, 0.2309699292,
-1.2684380046, 2.6097574011, -0.3413193965,
-0.0041960863, -0.7034186147, 1.7076147010,
};
static const float srgb_to_lms[9] = {
0.4122214708, 0.5363325363, 0.0514459929,
0.2119034982, 0.6806995451, 0.1073969566,
0.0883024619, 0.2817188376, 0.6299787005,
};
static const float lms_to_oklab[9] = {
0.2104542553, 0.7936177850, -0.0040720468,
1.9779984951, -2.4285922050, 0.4505937099,
0.0259040371, 0.7827717662, -0.8086757660,
};
static const float rec2020_to_lms[9] = {
0.616645, 0.360250, 0.023064,
0.265075, 0.635874, 0.099059,
0.100076, 0.203907, 0.696161,
};
static const float lms_to_rec2020[9] = {
2.140325, -1.246734, 0.106491,
-0.884665, 2.163141, -0.278489,
-0.048559, -0.454366, 1.502711,
};
+254 -67
View File
@@ -172,6 +172,18 @@ gdk_color_state_get_rec2100_linear (void)
return GDK_COLOR_STATE_REC2100_LINEAR;
}
GdkColorState *
gdk_color_state_get_oklab (void)
{
return GDK_COLOR_STATE_OKLAB;
}
GdkColorState *
gdk_color_state_get_oklch (void)
{
return GDK_COLOR_STATE_OKLCH;
}
/**
* gdk_color_state_equal:
* @self: a `GdkColorState`
@@ -223,56 +235,171 @@ gdk_color_state_create_cicp_params (GdkColorState *self)
/* {{{ Conversion functions */
typedef float (* GdkTransferFunc) (float v);
typedef void (* GdkConvertFunc) (GdkColorState *self,
float values[4]);
typedef const float GdkColorMatrix[9];
#define IDENTITY ((float*)0)
#define NONE ((GdkTransferFunc)0)
#define TRANSFORM(name, eotf, matrix, oetf) \
#define CONVERT_FUNC(name) \
static void \
name (GdkColorState *self, \
float (*values)[4], \
gsize n_values) \
gdk_convert_ ## name (GdkColorState *self, \
float (*values)[4], \
gsize n_values) \
{ \
for (gsize i = 0; i < n_values; i++) \
{ \
if (eotf != NONE) \
{ \
values[i][0] = eotf (values[i][0]); \
values[i][1] = eotf (values[i][1]); \
values[i][2] = eotf (values[i][2]); \
} \
if (matrix != IDENTITY) \
{ \
float res[3]; \
res[0] = matrix[0] * values[i][0] + matrix[1] * values[i][1] + matrix[2] * values[i][2]; \
res[1] = matrix[3] * values[i][0] + matrix[4] * values[i][1] + matrix[5] * values[i][2]; \
res[2] = matrix[6] * values[i][0] + matrix[7] * values[i][1] + matrix[8] * values[i][2]; \
values[i][0] = res[0]; \
values[i][1] = res[1]; \
values[i][2] = res[2]; \
} \
if (oetf != NONE) \
{ \
values[i][0] = oetf (values[i][0]); \
values[i][1] = oetf (values[i][1]); \
values[i][2] = oetf (values[i][2]); \
} \
name (self, values[i]); \
} \
}
TRANSFORM(gdk_default_srgb_to_srgb_linear, srgb_eotf, IDENTITY, NONE);
TRANSFORM(gdk_default_srgb_linear_to_srgb, NONE, IDENTITY, srgb_oetf)
TRANSFORM(gdk_default_rec2100_pq_to_rec2100_linear, pq_eotf, IDENTITY, NONE)
TRANSFORM(gdk_default_rec2100_linear_to_rec2100_pq, NONE, IDENTITY, pq_oetf)
TRANSFORM(gdk_default_srgb_linear_to_rec2100_linear, NONE, srgb_to_rec2020, NONE)
TRANSFORM(gdk_default_rec2100_linear_to_srgb_linear, NONE, rec2020_to_srgb, NONE)
TRANSFORM(gdk_default_srgb_to_rec2100_linear, srgb_eotf, srgb_to_rec2020, NONE)
TRANSFORM(gdk_default_rec2100_pq_to_srgb_linear, pq_eotf, rec2020_to_srgb, NONE)
TRANSFORM(gdk_default_srgb_linear_to_rec2100_pq, NONE, srgb_to_rec2020, pq_oetf)
TRANSFORM(gdk_default_rec2100_linear_to_srgb, NONE, rec2020_to_srgb, srgb_oetf)
TRANSFORM(gdk_default_srgb_to_rec2100_pq, srgb_eotf, srgb_to_rec2020, pq_oetf)
TRANSFORM(gdk_default_rec2100_pq_to_srgb, pq_eotf, rec2020_to_srgb, srgb_oetf)
#define TRANSFORM(name, eotf, matrix, nonlinear, matrix2, oetf) \
static inline void \
name (GdkColorState *self, \
float values[4]) \
{ \
if (eotf != NONE) \
{ \
values[0] = eotf (values[0]); \
values[1] = eotf (values[1]); \
values[2] = eotf (values[2]); \
} \
if (matrix != IDENTITY) \
{ \
float res[3]; \
res[0] = matrix[0] * values[0] + matrix[1] * values[1] + matrix[2] * values[2]; \
res[1] = matrix[3] * values[0] + matrix[4] * values[1] + matrix[5] * values[2]; \
res[2] = matrix[6] * values[0] + matrix[7] * values[1] + matrix[8] * values[2]; \
values[0] = res[0]; \
values[1] = res[1]; \
values[2] = res[2]; \
} \
if (nonlinear != NONE) \
{ \
values[0] = nonlinear (values[0]); \
values[1] = nonlinear (values[1]); \
values[2] = nonlinear (values[2]); \
} \
if (matrix2 != IDENTITY) \
{ \
float res[3]; \
res[0] = matrix2[0] * values[0] + matrix2[1] * values[1] + matrix2[2] * values[2]; \
res[1] = matrix2[3] * values[0] + matrix2[4] * values[1] + matrix2[5] * values[2]; \
res[2] = matrix2[6] * values[0] + matrix2[7] * values[1] + matrix2[8] * values[2]; \
values[0] = res[0]; \
values[1] = res[1]; \
values[2] = res[2]; \
} \
if (oetf != NONE) \
{ \
values[0] = oetf (values[0]); \
values[1] = oetf (values[1]); \
values[2] = oetf (values[2]); \
} \
} \
CONVERT_FUNC (name)
#define TRANSFORM_PAIR(name, func1, func2) \
static inline void \
name (GdkColorState *self, \
float values[4]) \
{ \
func1 (self, values); \
func2 (self, values); \
} \
CONVERT_FUNC (name)
TRANSFORM(srgb_to_srgb_linear, srgb_eotf, IDENTITY, NONE, IDENTITY, NONE)
TRANSFORM(srgb_linear_to_srgb, NONE, IDENTITY, NONE, IDENTITY, srgb_oetf)
TRANSFORM(rec2100_pq_to_rec2100_linear, pq_eotf, IDENTITY, NONE, IDENTITY, NONE)
TRANSFORM(rec2100_linear_to_rec2100_pq, NONE, IDENTITY, NONE, IDENTITY, pq_oetf)
TRANSFORM(srgb_linear_to_rec2100_linear, NONE, srgb_to_rec2020, NONE, IDENTITY, NONE)
TRANSFORM(rec2100_linear_to_srgb_linear, NONE, rec2020_to_srgb, NONE, IDENTITY, NONE)
TRANSFORM(srgb_to_rec2100_linear, srgb_eotf, srgb_to_rec2020, NONE, IDENTITY, NONE)
TRANSFORM(rec2100_pq_to_srgb_linear, pq_eotf, rec2020_to_srgb, NONE, IDENTITY, NONE)
TRANSFORM(srgb_linear_to_rec2100_pq, NONE, srgb_to_rec2020, NONE, IDENTITY, pq_oetf)
TRANSFORM(rec2100_linear_to_srgb, NONE, rec2020_to_srgb, NONE, IDENTITY, srgb_oetf)
TRANSFORM(srgb_to_rec2100_pq, srgb_eotf, srgb_to_rec2020, NONE, IDENTITY, pq_oetf)
TRANSFORM(rec2100_pq_to_srgb, pq_eotf, rec2020_to_srgb, NONE, IDENTITY, srgb_oetf)
TRANSFORM(oklab_to_srgb_linear, NONE, oklab_to_lms, from_oklab_nl, lms_to_srgb, NONE)
TRANSFORM(oklab_to_srgb, NONE, oklab_to_lms, from_oklab_nl, lms_to_srgb, srgb_oetf)
TRANSFORM(oklab_to_rec2100_linear, NONE, oklab_to_lms, from_oklab_nl, lms_to_rec2020, NONE)
TRANSFORM(oklab_to_rec2100_pq, NONE, oklab_to_lms, from_oklab_nl, lms_to_rec2020, pq_oetf)
TRANSFORM(srgb_linear_to_oklab, NONE, srgb_to_lms, to_oklab_nl, lms_to_oklab, NONE)
TRANSFORM(srgb_to_oklab, srgb_eotf, srgb_to_lms, to_oklab_nl, lms_to_oklab, NONE)
TRANSFORM(rec2100_linear_to_oklab, NONE, rec2020_to_lms, to_oklab_nl, lms_to_oklab, NONE)
TRANSFORM(rec2100_pq_to_oklab, pq_eotf, rec2020_to_lms, to_oklab_nl, lms_to_oklab, NONE)
#define DEG_TO_RAD(x) ((x) * G_PI / 180)
#define RAD_TO_DEG(x) ((x) * 180 / G_PI)
static inline void
_sincosf (float angle,
float *out_s,
float *out_c)
{
#ifdef HAVE_SINCOSF
sincosf (angle, out_s, out_c);
#else
*out_s = sinf (angle);
*out_c = cosf (angle);
#endif
}
static void
oklch_to_oklab (GdkColorState *self,
float values[4])
{
float L, C, H, a, b;
L = values[0];
C = values[1];
H = values[2];
_sincosf (DEG_TO_RAD (H), &b, &a);
a *= C;
b *= C;
values[0] = L;
values[1] = a;
values[2] = b;
}
static void
oklab_to_oklch (GdkColorState *self,
float values[4])
{
float L, a, b, C, H;
L = values[0];
a = values[1];
b = values[2];
C = hypotf (a, b);
H = RAD_TO_DEG (atan2 (b, a));
H = fmod (H, 360);
if (H < 0)
H += 360;
values[0] = L;
values[1] = C;
values[2] = H;
}
CONVERT_FUNC (oklch_to_oklab)
CONVERT_FUNC (oklab_to_oklch)
TRANSFORM_PAIR (srgb_to_oklch, srgb_to_oklab, oklab_to_oklch)
TRANSFORM_PAIR (srgb_linear_to_oklch, srgb_linear_to_oklab, oklab_to_oklch)
TRANSFORM_PAIR (rec2100_pq_to_oklch, rec2100_pq_to_oklab, oklab_to_oklch)
TRANSFORM_PAIR (rec2100_linear_to_oklch, rec2100_linear_to_oklab, oklab_to_oklch)
TRANSFORM_PAIR (oklch_to_srgb, oklch_to_oklab, oklab_to_srgb)
TRANSFORM_PAIR (oklch_to_srgb_linear, oklch_to_oklab, oklab_to_srgb_linear)
TRANSFORM_PAIR (oklch_to_rec2100_pq, oklch_to_oklab, oklab_to_rec2100_pq)
TRANSFORM_PAIR (oklch_to_rec2100_linear, oklch_to_oklab, oklab_to_rec2100_pq)
/* }}} */
/* {{{ Default implementation */
@@ -328,6 +455,9 @@ gdk_default_color_state_get_cicp (GdkColorState *color_state)
{
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
if (self->cicp.color_primaries == 0)
return NULL;
return &self->cicp;
}
@@ -419,9 +549,11 @@ GdkDefaultColorState gdk_default_color_states[] = {
.name = "srgb",
.no_srgb = GDK_COLOR_STATE_SRGB_LINEAR,
.convert_to = {
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_srgb_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_to_rec2100_linear,
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_convert_srgb_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_convert_srgb_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_convert_srgb_to_rec2100_linear,
[GDK_COLOR_STATE_ID_OKLAB] = gdk_convert_srgb_to_oklab,
[GDK_COLOR_STATE_ID_OKLCH] = gdk_convert_srgb_to_oklch,
},
.clamp = gdk_color_state_clamp_0_1,
.cicp = { 1, 13, 0, 1 },
@@ -437,9 +569,11 @@ GdkDefaultColorState gdk_default_color_states[] = {
.name = "srgb-linear",
.no_srgb = NULL,
.convert_to = {
[GDK_COLOR_STATE_ID_SRGB] = gdk_default_srgb_linear_to_srgb,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_srgb_linear_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_srgb_linear_to_rec2100_linear,
[GDK_COLOR_STATE_ID_SRGB] = gdk_convert_srgb_linear_to_srgb,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_convert_srgb_linear_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_convert_srgb_linear_to_rec2100_linear,
[GDK_COLOR_STATE_ID_OKLAB] = gdk_convert_srgb_linear_to_oklab,
[GDK_COLOR_STATE_ID_OKLCH] = gdk_convert_srgb_linear_to_oklch,
},
.clamp = gdk_color_state_clamp_0_1,
.cicp = { 1, 8, 0, 1 },
@@ -455,9 +589,11 @@ GdkDefaultColorState gdk_default_color_states[] = {
.name = "rec2100-pq",
.no_srgb = NULL,
.convert_to = {
[GDK_COLOR_STATE_ID_SRGB] = gdk_default_rec2100_pq_to_srgb,
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_pq_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_default_rec2100_pq_to_rec2100_linear,
[GDK_COLOR_STATE_ID_SRGB] = gdk_convert_rec2100_pq_to_srgb,
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_convert_rec2100_pq_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_convert_rec2100_pq_to_rec2100_linear,
[GDK_COLOR_STATE_ID_OKLAB] = gdk_convert_rec2100_pq_to_oklab,
[GDK_COLOR_STATE_ID_OKLCH] = gdk_convert_rec2100_pq_to_oklch,
},
.clamp = gdk_color_state_clamp_0_1,
.cicp = { 9, 16, 0, 1 },
@@ -473,16 +609,54 @@ GdkDefaultColorState gdk_default_color_states[] = {
.name = "rec2100-linear",
.no_srgb = NULL,
.convert_to = {
[GDK_COLOR_STATE_ID_SRGB] = gdk_default_rec2100_linear_to_srgb,
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_rec2100_linear_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_default_rec2100_linear_to_rec2100_pq,
[GDK_COLOR_STATE_ID_SRGB] = gdk_convert_rec2100_linear_to_srgb,
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_convert_rec2100_linear_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_convert_rec2100_linear_to_rec2100_pq,
[GDK_COLOR_STATE_ID_OKLAB] = gdk_convert_rec2100_linear_to_oklab,
[GDK_COLOR_STATE_ID_OKLCH] = gdk_convert_rec2100_linear_to_oklch,
},
.clamp = gdk_color_state_clamp_unbounded,
.cicp = { 9, 8, 0, 1 },
},
[GDK_COLOR_STATE_ID_OKLAB] = {
.parent = {
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
.ref_count = 0,
.depth = GDK_MEMORY_FLOAT16,
.rendering_color_state = GDK_COLOR_STATE_SRGB,
},
.name = "oklab",
.no_srgb = NULL,
.convert_to = {
[GDK_COLOR_STATE_ID_SRGB] = gdk_convert_oklab_to_srgb,
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_convert_oklab_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_convert_oklab_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_convert_oklab_to_rec2100_linear,
[GDK_COLOR_STATE_ID_OKLCH] = gdk_convert_oklab_to_oklch,
},
.cicp = { 0, 0, 0, 0 },
},
[GDK_COLOR_STATE_ID_OKLCH] = {
.parent = {
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
.ref_count = 0,
.depth = GDK_MEMORY_FLOAT16,
.rendering_color_state = GDK_COLOR_STATE_SRGB,
},
.name = "oklch",
.no_srgb = NULL,
.convert_to = {
[GDK_COLOR_STATE_ID_SRGB] = gdk_convert_oklch_to_srgb,
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_convert_oklch_to_srgb_linear,
[GDK_COLOR_STATE_ID_REC2100_PQ] = gdk_convert_oklch_to_rec2100_pq,
[GDK_COLOR_STATE_ID_REC2100_LINEAR] = gdk_convert_oklch_to_rec2100_linear,
[GDK_COLOR_STATE_ID_OKLAB] = gdk_convert_oklch_to_oklab,
},
.cicp = { 0, 0, 0, 0 },
},
};
/* }}} */
/* }}} */
/* {{{ Cicp implementation */
typedef struct _GdkCicpColorState GdkCicpColorState;
@@ -509,17 +683,22 @@ struct _GdkCicpColorState
#define cicp ((GdkCicpColorState *)self)
TRANSFORM(gdk_cicp_to_srgb, cicp->eotf, cicp->to_srgb, srgb_oetf)
TRANSFORM(gdk_cicp_to_srgb_linear, cicp->eotf, cicp->to_srgb, NONE)
TRANSFORM(gdk_cicp_to_rec2100_pq, cicp->eotf, cicp->to_rec2020, pq_oetf)
TRANSFORM(gdk_cicp_to_rec2100_linear, cicp->eotf, cicp->to_rec2020, NONE)
TRANSFORM(gdk_cicp_from_srgb, srgb_eotf, cicp->from_srgb, cicp->oetf)
TRANSFORM(gdk_cicp_from_srgb_linear, NONE, cicp->from_srgb, cicp->oetf)
TRANSFORM(gdk_cicp_from_rec2100_pq, pq_eotf, cicp->from_rec2020, cicp->oetf)
TRANSFORM(gdk_cicp_from_rec2100_linear, NONE, cicp->from_rec2020, cicp->oetf)
TRANSFORM(cicp_to_srgb, cicp->eotf, cicp->to_srgb, NONE, IDENTITY, srgb_oetf)
TRANSFORM(cicp_to_srgb_linear, cicp->eotf, cicp->to_srgb, NONE, IDENTITY, NONE)
TRANSFORM(cicp_to_rec2100_pq, cicp->eotf, cicp->to_rec2020, NONE, IDENTITY, pq_oetf)
TRANSFORM(cicp_to_rec2100_linear, cicp->eotf, cicp->to_rec2020, NONE, IDENTITY, NONE)
TRANSFORM(cicp_from_srgb, srgb_eotf, cicp->from_srgb, NONE, IDENTITY, cicp->oetf)
TRANSFORM(cicp_from_srgb_linear, NONE, cicp->from_srgb, NONE, IDENTITY, cicp->oetf)
TRANSFORM(cicp_from_rec2100_pq, pq_eotf, cicp->from_rec2020, NONE, IDENTITY, cicp->oetf)
TRANSFORM(cicp_from_rec2100_linear, NONE, cicp->from_rec2020, NONE, IDENTITY, cicp->oetf)
#undef cicp
TRANSFORM_PAIR (cicp_to_oklab, cicp_to_srgb_linear, srgb_linear_to_oklab)
TRANSFORM_PAIR (cicp_from_oklab, oklab_to_srgb_linear, cicp_from_srgb_linear)
TRANSFORM_PAIR (cicp_to_oklch, cicp_to_srgb_linear, srgb_linear_to_oklch)
TRANSFORM_PAIR (cicp_from_oklch, oklch_to_srgb_linear, cicp_from_srgb_linear)
/* }}} */
/* {{{ Vfuncs */
@@ -572,13 +751,17 @@ gdk_cicp_color_state_get_convert_to (GdkColorState *self,
switch (GDK_DEFAULT_COLOR_STATE_ID (target))
{
case GDK_COLOR_STATE_ID_SRGB:
return gdk_cicp_to_srgb;
return gdk_convert_cicp_to_srgb;
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
return gdk_cicp_to_srgb_linear;
return gdk_convert_cicp_to_srgb_linear;
case GDK_COLOR_STATE_ID_REC2100_PQ:
return gdk_cicp_to_rec2100_pq;
return gdk_convert_cicp_to_rec2100_pq;
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return gdk_cicp_to_rec2100_linear;
return gdk_convert_cicp_to_rec2100_linear;
case GDK_COLOR_STATE_ID_OKLAB:
return gdk_convert_cicp_to_oklab;
case GDK_COLOR_STATE_ID_OKLCH:
return gdk_convert_cicp_to_oklch;
case GDK_COLOR_STATE_N_IDS:
default:
@@ -598,13 +781,17 @@ gdk_cicp_color_state_get_convert_from (GdkColorState *self,
switch (GDK_DEFAULT_COLOR_STATE_ID (source))
{
case GDK_COLOR_STATE_ID_SRGB:
return gdk_cicp_from_srgb;
return gdk_convert_cicp_from_srgb;
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
return gdk_cicp_from_srgb_linear;
return gdk_convert_cicp_from_srgb_linear;
case GDK_COLOR_STATE_ID_REC2100_PQ:
return gdk_cicp_from_rec2100_pq;
return gdk_convert_cicp_from_rec2100_pq;
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return gdk_cicp_from_rec2100_linear;
return gdk_convert_cicp_from_rec2100_linear;
case GDK_COLOR_STATE_ID_OKLAB:
return gdk_convert_cicp_from_oklab;
case GDK_COLOR_STATE_ID_OKLCH:
return gdk_convert_cicp_from_oklch;
case GDK_COLOR_STATE_N_IDS:
default:
+6
View File
@@ -49,6 +49,12 @@ GdkColorState * gdk_color_state_get_rec2100_pq (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_rec2100_linear (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_oklab (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_oklch (void);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_state_equal (GdkColorState *self,
GdkColorState *other);
+4
View File
@@ -13,6 +13,8 @@ typedef enum
GDK_COLOR_STATE_ID_SRGB_LINEAR,
GDK_COLOR_STATE_ID_REC2100_PQ,
GDK_COLOR_STATE_ID_REC2100_LINEAR,
GDK_COLOR_STATE_ID_OKLAB,
GDK_COLOR_STATE_ID_OKLCH,
GDK_COLOR_STATE_N_IDS
} GdkColorStateId;
@@ -73,6 +75,8 @@ extern GdkDefaultColorState gdk_default_color_states[GDK_COLOR_STATE_N_IDS];
#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_SRGB_LINEAR])
#define GDK_COLOR_STATE_REC2100_PQ ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2100_PQ])
#define GDK_COLOR_STATE_REC2100_LINEAR ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_REC2100_LINEAR])
#define GDK_COLOR_STATE_OKLAB ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_OKLAB])
#define GDK_COLOR_STATE_OKLCH ((GdkColorState *) &gdk_default_color_states[GDK_COLOR_STATE_ID_OKLCH])
#define GDK_IS_DEFAULT_COLOR_STATE(c) ((GdkDefaultColorState *) (c) >= &gdk_default_color_states[0] && \
(GdkDefaultColorState *) (c) < &gdk_default_color_states[GDK_COLOR_STATE_N_IDS])
+3 -3
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) |
+25 -13
View File
@@ -1,6 +1,7 @@
#include "config.h"
#include "gskgpuconicgradientopprivate.h"
#include "gskgpulineargradientopprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
@@ -52,24 +53,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 +84,25 @@ 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;
gsk_adjust_hue (ics, hue_interp, instance->color0, instance->color1);
gsk_adjust_hue (ics, hue_interp, instance->color1, instance->color2);
gsk_adjust_hue (ics, hue_interp, instance->color2, instance->color3);
gsk_adjust_hue (ics, hue_interp, instance->color3, instance->color4);
gsk_adjust_hue (ics, hue_interp, instance->color4, instance->color5);
gsk_adjust_hue (ics, hue_interp, instance->color5, instance->color6);
}
+7 -4
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);
+96 -13
View File
@@ -52,28 +52,104 @@ static const GskGpuShaderOpClass GSK_GPU_LINEAR_GRADIENT_OP_CLASS = {
gsk_gpu_lineargradient_setup_vao
};
void
gsk_adjust_hue (GdkColorState *ics,
GskHueInterpolation interp,
const float color1[4],
float color2[4])
{
float h1, h2;
float d;
if (!gdk_color_state_equal (ics, GDK_COLOR_STATE_OKLCH))
return;
h1 = color1[2];
h2 = color2[2];
d = h2 - h1;
while (d > 360)
{
h2 -= 360;
d = h2 - h1;
}
while (d < -360)
{
h2 += 360;
d = h2 - h1;
}
g_assert (fabsf (d) <= 360);
switch (interp)
{
case GSK_HUE_INTERPOLATION_SHORTER:
{
if (d > 180)
h2 -= 360;
else if (d < -180)
h2 += 360;
}
g_assert (fabsf (h2 - h1) <= 180);
break;
case GSK_HUE_INTERPOLATION_LONGER:
{
if (0 < d && d < 180)
h2 -= 360;
else if (-180 < d && d <= 0)
h2 += 360;
g_assert (fabsf (h2 - h1) >= 180);
}
break;
case GSK_HUE_INTERPOLATION_INCREASING:
if (h2 < h1)
h2 += 360;
d = h2 - h1;
g_assert (h1 <= h2);
break;
case GSK_HUE_INTERPOLATION_DECREASING:
if (h1 < h2)
h2 -= 360;
d = h2 - h1;
g_assert (h1 >= h2);
break;
default:
g_assert_not_reached ();
}
color2[2] = h2;
}
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 +160,25 @@ 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;
gsk_adjust_hue (ics, hue_interp, instance->color0, instance->color1);
gsk_adjust_hue (ics, hue_interp, instance->color1, instance->color2);
gsk_adjust_hue (ics, hue_interp, instance->color2, instance->color3);
gsk_adjust_hue (ics, hue_interp, instance->color3, instance->color4);
gsk_adjust_hue (ics, hue_interp, instance->color4, instance->color5);
gsk_adjust_hue (ics, hue_interp, instance->color5, instance->color6);
}
+12 -4
View File
@@ -2,7 +2,7 @@
#include "gskgpushaderopprivate.h"
#include "gskrendernode.h"
#include "gskrendernodeprivate.h"
#include <graphene.h>
@@ -10,15 +10,23 @@ 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);
void gsk_adjust_hue (GdkColorState *ics,
GskHueInterpolation interp,
const float color1[4],
float color2[4]);
G_END_DECLS
+81 -45
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);
}
@@ -4499,4 +4536,3 @@ gsk_gpu_node_processor_convert_image (GskGpuFrame *frame,
return converted;
}
+25 -13
View File
@@ -1,6 +1,7 @@
#include "config.h"
#include "gskgpuradialgradientopprivate.h"
#include "gskgpulineargradientopprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
@@ -55,27 +56,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 +93,25 @@ 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;
gsk_adjust_hue (ics, hue_interp, instance->color0, instance->color1);
gsk_adjust_hue (ics, hue_interp, instance->color1, instance->color2);
gsk_adjust_hue (ics, hue_interp, instance->color2, instance->color3);
gsk_adjust_hue (ics, hue_interp, instance->color3, instance->color4);
gsk_adjust_hue (ics, hue_interp, instance->color4, instance->color5);
gsk_adjust_hue (ics, hue_interp, instance->color5, instance->color6);
}
+7 -4
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);
+129 -6
View File
@@ -111,6 +111,54 @@ const mat3 rec2020_from_srgb = mat3(
0.043303, 0.011360, 0.895380
);
const mat3 oklab_to_lms = mat3(
1.0, 1.0, 1.0,
0.3963377774, -0.1055613458, -0.0894841775,
0.2158037573, -0.0638541728, -1.2914855480
);
const mat3 lms_to_srgb = mat3(
4.0767416621, -1.2684380046, -0.0041960863,
-3.3077115913, 2.6097574011, -0.7034186147,
0.2309699292, -0.3413193965, 1.7076147010
);
const mat3 srgb_to_lms = mat3(
0.4122214708, 0.2119034982, 0.0883024619,
0.5363325363, 0.6806995451, 0.2817188376,
0.0514459929, 0.1073969566, 0.6299787005
);
const mat3 lms_to_oklab = mat3(
0.2104542553, 1.9779984951, 0.0259040371,
0.7936177850, -2.4285922050, 0.7827717662,
-0.0040720468, 0.4505937099, -0.8086757660
);
vec3
oklab_to_srgb_linear (vec3 color)
{
vec3 lms = oklab_to_lms * color;
lms = vec3 (pow (lms.r, 3.0),
pow (lms.g, 3.0),
pow (lms.b, 3.0));
return lms_to_srgb * lms;
}
vec3
srgb_linear_to_oklab (vec3 color)
{
vec3 lms = srgb_to_lms * color;
lms = vec3 (pow (lms.r, 1.0/3.0),
pow (lms.g, 1.0/3.0),
pow (lms.b, 1.0/3.0));
return lms_to_oklab * lms;
}
vec3
apply_eotf (vec3 color,
uint cs)
@@ -131,6 +179,9 @@ apply_eotf (vec3 color,
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return color;
case GDK_COLOR_STATE_ID_OKLAB:
return oklab_to_srgb_linear (color);
default:
return vec3(1.0, 0.0, 0.8);
}
@@ -156,6 +207,9 @@ apply_oetf (vec3 color,
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return color;
case GDK_COLOR_STATE_ID_OKLAB:
return srgb_linear_to_oklab (color);
default:
return vec3(0.0, 1.0, 0.8);
}
@@ -183,10 +237,71 @@ linear_color_space (uint cs)
case GDK_COLOR_STATE_ID_SRGB_LINEAR: return GDK_COLOR_STATE_ID_SRGB_LINEAR;
case GDK_COLOR_STATE_ID_REC2100_PQ: return GDK_COLOR_STATE_ID_REC2100_LINEAR;
case GDK_COLOR_STATE_ID_REC2100_LINEAR: return GDK_COLOR_STATE_ID_REC2100_LINEAR;
case GDK_COLOR_STATE_ID_OKLAB: return GDK_COLOR_STATE_ID_SRGB_LINEAR;
case GDK_COLOR_STATE_ID_OKLCH: return GDK_COLOR_STATE_ID_SRGB_LINEAR;
default: return 0u;
};
}
uint
rectangular_color_space (uint cs)
{
if (cs == GDK_COLOR_STATE_ID_OKLCH)
return GDK_COLOR_STATE_ID_OKLAB;
else
return cs;
}
#define M_PI 3.14159265358979323846
#define RAD_TO_DEG(x) ((x)*180.0/M_PI)
#define DEG_TO_RAD(x) ((x)*M_PI/180.0)
float
normalize_hue (float h)
{
while (h < 0.0)
h += 360.0;
while (h > 360.0)
h -= 360.0;
return h;
}
vec3
oklch_to_oklab (vec3 color)
{
color.z = normalize_hue (color.z);
return vec3 (color.x,
color.y * cos (DEG_TO_RAD (color.z)),
color.y * sin (DEG_TO_RAD (color.z)));
}
vec3
oklab_to_oklch (vec3 color)
{
return vec3 (color.x,
length (color.yz),
RAD_TO_DEG (atan (color.z, color.y)));
}
vec3
to_rect (vec3 color, uint from)
{
if (from == GDK_COLOR_STATE_ID_OKLCH)
return oklch_to_oklab (color);
else
return vec3(1, 0, 0.5);
}
vec3
to_polar (vec3 color, uint to)
{
if (to == GDK_COLOR_STATE_ID_OKLCH)
return oklab_to_oklch (color);
else
return vec3(1, 0, 0.5);
}
vec4
convert_color (vec4 color,
uint from,
@@ -199,17 +314,25 @@ convert_color (vec4 color,
if (from != to)
{
uint from_linear = linear_color_space (from);
uint to_linear = linear_color_space (to);
uint from_rectangular = rectangular_color_space (from);
uint to_rectangular = rectangular_color_space (to);
uint from_linear = linear_color_space (from_rectangular);
uint to_linear = linear_color_space (to_rectangular);
if (from_linear != from)
color.rgb = apply_eotf (color.rgb, from);
if (from_rectangular != from)
color.rgb = to_rect (color.rgb, from);
if (from_linear != from_rectangular)
color.rgb = apply_eotf (color.rgb, from_rectangular);
if (from_linear != to_linear)
color.rgb = convert_linear (color.rgb, from_linear, to_linear);
if (to_linear != to)
color.rgb = apply_oetf (color.rgb, to);
if (to_linear != to_rectangular)
color.rgb = apply_oetf (color.rgb, to_rectangular);
if (to_rectangular != to)
color.rgb = to_polar (color.rgb, to);
}
if (to_premul && (!from_premul || from != to))
+2
View File
@@ -56,6 +56,8 @@
#define GDK_COLOR_STATE_ID_SRGB_LINEAR 1u
#define GDK_COLOR_STATE_ID_REC2100_PQ 2u
#define GDK_COLOR_STATE_ID_REC2100_LINEAR 3u
#define GDK_COLOR_STATE_ID_OKLAB 4u
#define GDK_COLOR_STATE_ID_OKLCH 5u
#define TOP 0u
#define RIGHT 1u
+826 -95
View File
File diff suppressed because it is too large Load Diff
+239 -51
View File
@@ -628,6 +628,10 @@ parse_color_state (GtkCssParser *parser,
cs = gdk_color_state_get_rec2100_pq ();
else if (gtk_css_parser_try_ident (parser, "rec2100-linear"))
cs = gdk_color_state_get_rec2100_linear ();
else if (gtk_css_parser_try_ident (parser, "oklab"))
cs = gdk_color_state_get_oklab ();
else if (gtk_css_parser_try_ident (parser, "oklch"))
cs = gdk_color_state_get_oklch ();
else if (gtk_css_token_is (gtk_css_parser_get_token (parser), GTK_CSS_TOKEN_STRING))
{
char *name = gtk_css_parser_consume_string (parser);
@@ -654,6 +658,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 +759,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 +793,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 +814,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 +1706,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 +1786,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 +1859,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 +1869,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 +1898,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 +1942,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 +3454,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 +3788,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 +3821,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 +3981,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 +3999,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 +4373,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 +4466,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 +4476,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 +4492,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 +4506,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;
+79 -2
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
+59 -2
View File
@@ -1167,6 +1167,50 @@ 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:
return GDK_COLOR_STATE_SRGB;
case GTK_CSS_COLOR_SPACE_OKLAB:
return GDK_COLOR_STATE_OKLAB;
case GTK_CSS_COLOR_SPACE_OKLCH:
return GDK_COLOR_STATE_OKLCH;
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)
@@ -1185,10 +1229,17 @@ gtk_css_color_to_color (const GtkCssColor *css,
gdk_color_init (color, GDK_COLOR_STATE_REC2100_PQ, css->values);
break;
case GTK_CSS_COLOR_SPACE_OKLAB:
gdk_color_init (color, GDK_COLOR_STATE_OKLAB, css->values);
break;
case GTK_CSS_COLOR_SPACE_OKLCH:
gdk_color_init (color, GDK_COLOR_STATE_OKLCH, css->values);
break;
case GTK_CSS_COLOR_SPACE_HSL:
case GTK_CSS_COLOR_SPACE_HWB:
case GTK_CSS_COLOR_SPACE_OKLAB:
case GTK_CSS_COLOR_SPACE_OKLCH:
{
GtkCssColor tmp;
gtk_css_color_convert (css, GTK_CSS_COLOR_SPACE_SRGB, &tmp);
@@ -1211,5 +1262,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: */
+5
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)
{
+13 -8
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;
+30 -26
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
+23 -21
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
+318 -66
View File
@@ -2522,12 +2522,56 @@ 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;
gboolean need_gradient = FALSE;
const GdkColor *first_color;
gboolean need_gradient = TRUE;
g_return_if_fail (snapshot != NULL);
g_return_if_fail (start_point != NULL);
@@ -2541,13 +2585,17 @@ gtk_snapshot_append_linear_gradient (GtkSnapshot *snapshot,
&dx, &dy);
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 ++)
if (hue_interpolation != GSK_HUE_INTERPOLATION_LONGER)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
need_gradient = FALSE;
first_color = &stops[0].color;
for (gsize i = 1; i < n_stops; i ++)
{
need_gradient = TRUE;
break;
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
}
}
}
@@ -2560,15 +2608,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 +2641,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;
gboolean need_gradient = TRUE;
const GdkColor *first_color;
g_return_if_fail (snapshot != NULL);
g_return_if_fail (start_point != NULL);
@@ -2608,13 +2701,17 @@ gtk_snapshot_append_repeating_linear_gradient (GtkSnapshot *snapshot,
gtk_snapshot_ensure_affine (snapshot, &scale_x, &scale_y, &dx, &dy);
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 ++)
if (hue_interpolation != GSK_HUE_INTERPOLATION_LONGER)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
need_gradient = FALSE;
first_color = &stops[0].color;
for (gsize i = 1; i < n_stops; i ++)
{
need_gradient = TRUE;
break;
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
}
}
}
@@ -2627,15 +2724,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,12 +2758,57 @@ 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;
gboolean need_gradient = FALSE;
const GdkColor *first_color;
gboolean need_gradient = TRUE;
int i;
g_return_if_fail (snapshot != NULL);
@@ -2676,27 +2819,32 @@ gtk_snapshot_append_conic_gradient (GtkSnapshot *snapshot,
gtk_snapshot_ensure_translate (snapshot, &dx, &dy);
graphene_rect_offset_r (bounds, dx, dy, &real_bounds);
first_color = &stops[0].color;
for (i = 0; i < n_stops; i ++)
if (hue_interpolation != GSK_HUE_INTERPOLATION_LONGER)
{
if (!gdk_rgba_equal (first_color, &stops[i].color))
need_gradient = FALSE;
first_color = &stops[0].color;
for (i = 1; i < n_stops; i ++)
{
need_gradient = TRUE;
break;
if (!gdk_color_equal (first_color, &stops[i].color))
{
need_gradient = TRUE;
break;
}
}
}
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 +2873,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 +2941,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 +2957,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 +2998,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 +3066,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 +3081,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);
+50 -1
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
+29 -15
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');
}
+3
View File
@@ -23,6 +23,7 @@ TransferTest transfers[] = {
{ "hlg", hlg_oetf, hlg_eotf, { 0, 1}, { 0, 1} },
{ "gamma22", gamma22_oetf, gamma22_eotf, { 0, 1 }, { 0, 1 } },
{ "gamma28", gamma28_oetf, gamma28_eotf, { 0, 1 }, { 0, 1 } },
{ "oklab", to_oklab_nl, from_oklab_nl,{ 0, 1 }, { 0, 1 } },
};
#define LERP(t, a, b) ((a) + (t) * ((b) - (a)))
@@ -103,6 +104,8 @@ static MatrixTest matrices[] = {
{ "ntsc", ntsc_to_xyz, xyz_to_ntsc },
{ "p3", p3_to_xyz, xyz_to_p3 },
{ "srgb<>rec2020", rec2020_to_srgb, srgb_to_rec2020 },
{ "oklab<>lms", oklab_to_lms, lms_to_oklab },
{ "lms<>srgb", lms_to_srgb, srgb_to_lms },
};
#define IDX(i,j) 3*i+j
@@ -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

+3
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',
@@ -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);
}
+35
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";
}
@@ -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";
}
@@ -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);
}
+36 -23
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