mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-23 12:20:08 +00:00
Merge branch 'oklab-support' into 'main'
oklab and oklch support See merge request GNOME/gtk!7801
This commit is contained in:
commit
06b8863bf7
@ -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,
|
||||
};
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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])
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskgpuconicgradientopprivate.h"
|
||||
#include "gskgpulineargradientopprivate.h"
|
||||
|
||||
#include "gskgpuframeprivate.h"
|
||||
#include "gskgpuprintprivate.h"
|
||||
@ -97,4 +98,11 @@ gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
|
||||
instance->offsets0[1] = stops[1].offset;
|
||||
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);
|
||||
}
|
||||
|
@ -52,6 +52,78 @@ 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,
|
||||
@ -102,4 +174,11 @@ gsk_gpu_linear_gradient_op (GskGpuFrame *frame,
|
||||
instance->offsets0[1] = stops[1].offset;
|
||||
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);
|
||||
}
|
||||
|
@ -23,5 +23,10 @@ void gsk_gpu_linear_gradient_op (GskGpuF
|
||||
gsize n_stops);
|
||||
|
||||
|
||||
void gsk_adjust_hue (GdkColorState *ics,
|
||||
GskHueInterpolation interp,
|
||||
const float color1[4],
|
||||
float color2[4]);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gskgpuradialgradientopprivate.h"
|
||||
#include "gskgpulineargradientopprivate.h"
|
||||
|
||||
#include "gskgpuframeprivate.h"
|
||||
#include "gskgpuprintprivate.h"
|
||||
@ -106,4 +107,11 @@ gsk_gpu_radial_gradient_op (GskGpuFrame *frame,
|
||||
instance->offsets0[1] = stops[1].offset;
|
||||
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);
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -358,6 +358,140 @@ gsk_linear_gradient_node_finalize (GskRenderNode *node)
|
||||
parent_class->finalize (node);
|
||||
}
|
||||
|
||||
static float
|
||||
adjust_hue (GskHueInterpolation interp,
|
||||
float h1,
|
||||
float h2)
|
||||
{
|
||||
float d;
|
||||
|
||||
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 ();
|
||||
}
|
||||
|
||||
return h2;
|
||||
}
|
||||
|
||||
#define lerp(t,a,b) ((a) + (t) * ((b) - (a)))
|
||||
|
||||
typedef void (* ColorStopCallback) (float offset,
|
||||
GdkColorState *ccs,
|
||||
float values[4],
|
||||
gpointer data);
|
||||
|
||||
static void
|
||||
interpolate_color_stops (GdkColorState *ccs,
|
||||
GdkColorState *interpolation,
|
||||
GskHueInterpolation hue_interpolation,
|
||||
float offset1,
|
||||
GdkColor *color1,
|
||||
float offset2,
|
||||
GdkColor *color2,
|
||||
ColorStopCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
float values1[4];
|
||||
float values2[4];
|
||||
int n;
|
||||
|
||||
gdk_color_to_float (color1, interpolation, values1);
|
||||
gdk_color_to_float (color2, interpolation, values2);
|
||||
|
||||
if (gdk_color_state_equal (interpolation, GDK_COLOR_STATE_OKLCH))
|
||||
{
|
||||
values2[2] = adjust_hue (hue_interpolation, values1[2], values2[2]);
|
||||
/* don't make hue steps larger than 30° */
|
||||
n = ceilf (fabsf (values2[2] - values1[2]) / 30);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* just some steps */
|
||||
n = 4;
|
||||
}
|
||||
|
||||
for (int k = 1; k < n; k++)
|
||||
{
|
||||
float f = k / (float) n;
|
||||
float values[4];
|
||||
float offset;
|
||||
GdkColor c;
|
||||
|
||||
values[0] = lerp (f, values1[0], values2[0]);
|
||||
values[1] = lerp (f, values1[1], values2[1]);
|
||||
values[2] = lerp (f, values1[2], values2[2]);
|
||||
values[3] = lerp (f, values1[3], values2[3]);
|
||||
offset = lerp (f, offset1, offset2);
|
||||
|
||||
gdk_color_init (&c, interpolation, values);
|
||||
gdk_color_to_float (&c, ccs, values);
|
||||
|
||||
callback (offset, ccs, values, data);
|
||||
|
||||
gdk_color_finish (&c);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_color_stop_to_pattern (float offset,
|
||||
GdkColorState *ccs,
|
||||
float values[4],
|
||||
gpointer data)
|
||||
{
|
||||
cairo_pattern_t *pattern = data;
|
||||
|
||||
cairo_pattern_add_color_stop_rgba (pattern, offset, values[0], values[1], values[2], values[3]);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_linear_gradient_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr,
|
||||
@ -378,18 +512,42 @@ gsk_linear_gradient_node_draw (GskRenderNode *node,
|
||||
ccs,
|
||||
0.0,
|
||||
&self->stops[0].color);
|
||||
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
if (!gdk_color_state_equal (self->interpolation, ccs))
|
||||
interpolate_color_stops (ccs,
|
||||
self->interpolation, self->hue_interpolation,
|
||||
i > 0 ? self->stops[i-1].offset : 0,
|
||||
i > 0 ? &self->stops[i-1].color : &self->stops[i].color,
|
||||
self->stops[i].offset,
|
||||
&self->stops[i].color,
|
||||
add_color_stop_to_pattern,
|
||||
pattern);
|
||||
|
||||
gdk_cairo_pattern_add_color_stop_color (pattern,
|
||||
ccs,
|
||||
self->stops[i].offset,
|
||||
&self->stops[i].color);
|
||||
}
|
||||
|
||||
if (self->stops[self->n_stops-1].offset < 1.0)
|
||||
gdk_cairo_pattern_add_color_stop_color (pattern,
|
||||
ccs,
|
||||
1.0,
|
||||
&self->stops[self->n_stops - 1].color);
|
||||
{
|
||||
if (!gdk_color_state_equal (self->interpolation, ccs))
|
||||
interpolate_color_stops (ccs,
|
||||
self->interpolation, self->hue_interpolation,
|
||||
self->stops[self->n_stops-1].offset,
|
||||
&self->stops[self->n_stops-1].color,
|
||||
1,
|
||||
&self->stops[self->n_stops-1].color,
|
||||
add_color_stop_to_pattern,
|
||||
pattern);
|
||||
|
||||
gdk_cairo_pattern_add_color_stop_color (pattern,
|
||||
ccs,
|
||||
1.0,
|
||||
&self->stops[self->n_stops-1].color);
|
||||
}
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_pattern_destroy (pattern);
|
||||
@ -925,18 +1083,42 @@ gsk_radial_gradient_node_draw (GskRenderNode *node,
|
||||
ccs,
|
||||
0.0,
|
||||
&self->stops[0].color);
|
||||
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
if (!gdk_color_state_equal (self->interpolation, ccs))
|
||||
interpolate_color_stops (ccs,
|
||||
self->interpolation, self->hue_interpolation,
|
||||
i > 0 ? self->stops[i-1].offset : 0,
|
||||
i > 0 ? &self->stops[i-1].color : &self->stops[i].color,
|
||||
self->stops[i].offset,
|
||||
&self->stops[i].color,
|
||||
add_color_stop_to_pattern,
|
||||
pattern);
|
||||
|
||||
gdk_cairo_pattern_add_color_stop_color (pattern,
|
||||
ccs,
|
||||
self->stops[i].offset,
|
||||
&self->stops[i].color);
|
||||
}
|
||||
|
||||
if (self->stops[self->n_stops-1].offset < 1.0)
|
||||
gdk_cairo_pattern_add_color_stop_color (pattern,
|
||||
ccs,
|
||||
1.0,
|
||||
&self->stops[self->n_stops-1].color);
|
||||
{
|
||||
if (!gdk_color_state_equal (self->interpolation, ccs))
|
||||
interpolate_color_stops (ccs,
|
||||
self->interpolation, self->hue_interpolation,
|
||||
self->stops[self->n_stops-1].offset,
|
||||
&self->stops[self->n_stops-1].color,
|
||||
1,
|
||||
&self->stops[self->n_stops-1].color,
|
||||
add_color_stop_to_pattern,
|
||||
pattern);
|
||||
|
||||
gdk_cairo_pattern_add_color_stop_color (pattern,
|
||||
ccs,
|
||||
1.0,
|
||||
&self->stops[self->n_stops-1].color);
|
||||
}
|
||||
|
||||
gdk_cairo_rect (cr, &node->bounds);
|
||||
cairo_translate (cr, self->center.x, self->center.y);
|
||||
@ -1623,6 +1805,29 @@ gdk_rgba_color_interpolate (GdkRGBA *dest,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_color_stop_to_array (float offset,
|
||||
GdkColorState *ccs,
|
||||
float values[4],
|
||||
gpointer data)
|
||||
{
|
||||
GArray *stops = data;
|
||||
GskColorStop2 stop;
|
||||
|
||||
stop.offset = offset;
|
||||
gdk_color_init (&stop.color, ccs, values);
|
||||
|
||||
g_array_append_val (stops, stop);
|
||||
}
|
||||
|
||||
static void
|
||||
clear_stop (gpointer data)
|
||||
{
|
||||
GskColorStop2 *stop = data;
|
||||
|
||||
gdk_color_finish (&stop->color);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr,
|
||||
@ -1633,6 +1838,7 @@ gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
graphene_point_t corner;
|
||||
float radius;
|
||||
gsize i;
|
||||
GArray *stops;
|
||||
|
||||
pattern = cairo_pattern_create_mesh ();
|
||||
graphene_rect_get_top_right (&node->bounds, &corner);
|
||||
@ -1644,10 +1850,41 @@ gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
graphene_rect_get_top_left (&node->bounds, &corner);
|
||||
radius = MAX (radius, graphene_point_distance (&self->center, &corner, NULL, NULL));
|
||||
|
||||
for (i = 0; i <= self->n_stops; i++)
|
||||
stops = g_array_new (FALSE, TRUE, sizeof (GskColorStop2));
|
||||
g_array_set_clear_func (stops, clear_stop);
|
||||
|
||||
if (gdk_color_state_equal (self->interpolation, ccs))
|
||||
{
|
||||
GskColorStop2 *stop1 = &self->stops[MAX (i, 1) - 1];
|
||||
GskColorStop2 *stop2 = &self->stops[MIN (i, self->n_stops - 1)];
|
||||
for (i = 0; i < self->n_stops; i++)
|
||||
{
|
||||
GskColorStop2 *stop = &self->stops[i];
|
||||
g_array_append_val (stops, *stop);
|
||||
/* take a ref, since clear_stop removes one */
|
||||
gdk_color_state_ref (stop->color.color_state);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
g_array_append_val (stops, self->stops[0]);
|
||||
|
||||
for (i = 1; i < self->n_stops; i++)
|
||||
{
|
||||
interpolate_color_stops (ccs,
|
||||
self->interpolation, self->hue_interpolation,
|
||||
self->stops[i-1].offset, &self->stops[i-1].color,
|
||||
self->stops[i].offset, &self->stops[i].color,
|
||||
add_color_stop_to_array,
|
||||
stops);
|
||||
g_array_append_val (stops, self->stops[i]);
|
||||
/* take a ref, since clear_stop removes one */
|
||||
gdk_color_state_ref (self->stops[i].color.color_state);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i <= stops->len; i++)
|
||||
{
|
||||
GskColorStop2 *stop1 = &g_array_index (stops, GskColorStop2, MAX (i, 1) - 1);
|
||||
GskColorStop2 *stop2 = &g_array_index (stops, GskColorStop2, MIN (i, stops->len - 1));
|
||||
double offset1 = i > 0 ? stop1->offset : 0;
|
||||
double offset2 = i < self->n_stops ? stop2->offset : 1;
|
||||
double start_angle, end_angle;
|
||||
@ -1683,6 +1920,8 @@ gsk_conic_gradient_node_draw (GskRenderNode *node,
|
||||
}
|
||||
}
|
||||
|
||||
g_array_unref (stops);
|
||||
|
||||
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
|
||||
|
||||
gdk_cairo_rect (cr, &node->bounds);
|
||||
|
@ -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);
|
||||
|
@ -1188,10 +1188,14 @@ gtk_css_color_space_get_color_state (GtkCssColorSpace color_space)
|
||||
case GTK_CSS_COLOR_SPACE_SRGB:
|
||||
case GTK_CSS_COLOR_SPACE_HSL:
|
||||
case GTK_CSS_COLOR_SPACE_HWB:
|
||||
case GTK_CSS_COLOR_SPACE_OKLAB:
|
||||
case GTK_CSS_COLOR_SPACE_OKLCH:
|
||||
return GDK_COLOR_STATE_SRGB;
|
||||
|
||||
case GTK_CSS_COLOR_SPACE_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;
|
||||
|
||||
@ -1225,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);
|
||||
|
@ -2571,7 +2571,7 @@ gtk_snapshot_append_linear_gradient2 (GtkSnapshot *snapshot,
|
||||
graphene_rect_t real_bounds;
|
||||
float scale_x, scale_y, dx, dy;
|
||||
const GdkColor *first_color;
|
||||
gboolean need_gradient = FALSE;
|
||||
gboolean need_gradient = TRUE;
|
||||
|
||||
g_return_if_fail (snapshot != NULL);
|
||||
g_return_if_fail (start_point != NULL);
|
||||
@ -2585,13 +2585,17 @@ gtk_snapshot_append_linear_gradient2 (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 = 1; i < n_stops; i ++)
|
||||
if (hue_interpolation != GSK_HUE_INTERPOLATION_LONGER)
|
||||
{
|
||||
if (!gdk_color_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2685,7 +2689,7 @@ gtk_snapshot_append_repeating_linear_gradient2 (GtkSnapshot *snapsho
|
||||
GskRenderNode *node;
|
||||
graphene_rect_t real_bounds;
|
||||
float scale_x, scale_y, dx, dy;
|
||||
gboolean need_gradient = FALSE;
|
||||
gboolean need_gradient = TRUE;
|
||||
const GdkColor *first_color;
|
||||
|
||||
g_return_if_fail (snapshot != NULL);
|
||||
@ -2697,13 +2701,17 @@ gtk_snapshot_append_repeating_linear_gradient2 (GtkSnapshot *snapsho
|
||||
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 = 1; i < n_stops; i ++)
|
||||
if (hue_interpolation != GSK_HUE_INTERPOLATION_LONGER)
|
||||
{
|
||||
if (!gdk_color_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2800,7 +2808,7 @@ gtk_snapshot_append_conic_gradient2 (GtkSnapshot *snapshot,
|
||||
graphene_rect_t real_bounds;
|
||||
float dx, dy;
|
||||
const GdkColor *first_color;
|
||||
gboolean need_gradient = FALSE;
|
||||
gboolean need_gradient = TRUE;
|
||||
int i;
|
||||
|
||||
g_return_if_fail (snapshot != NULL);
|
||||
@ -2811,13 +2819,17 @@ gtk_snapshot_append_conic_gradient2 (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 = 1; i < n_stops; i ++)
|
||||
if (hue_interpolation != GSK_HUE_INTERPOLATION_LONGER)
|
||||
{
|
||||
if (!gdk_color_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user