mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-13 20:30:11 +00:00
e1031ac5ad
This allows in-place color state conversions.
286 lines
6.8 KiB
C
286 lines
6.8 KiB
C
/* gdkcolorstate.c
|
|
*
|
|
* Copyright 2024 Matthias Clasen
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gdkcolorstateprivate.h"
|
|
|
|
#include <math.h>
|
|
|
|
/**
|
|
* GdkColorState:
|
|
*
|
|
* A `GdkColorState` object provides the information to interpret
|
|
* colors and pixels in a variety of ways.
|
|
*
|
|
* They are also known as
|
|
* [*color spaces*](https://en.wikipedia.org/wiki/Color_space).
|
|
*
|
|
* Crucially, GTK knows how to convert colors from one color
|
|
* state to another.
|
|
*
|
|
* `GdkColorState objects are immutable and therefore threadsafe.
|
|
*
|
|
* Since 4.16
|
|
*/
|
|
|
|
G_DEFINE_BOXED_TYPE (GdkColorState, gdk_color_state,
|
|
gdk_color_state_ref, gdk_color_state_unref);
|
|
|
|
/* {{{ Public API */
|
|
|
|
/**
|
|
* gdk_color_state_ref:
|
|
* @self: a `GdkColorState`
|
|
*
|
|
* Increase the reference count of @self.
|
|
*
|
|
* Returns: the object that was passed in
|
|
*
|
|
* Since: 4.16
|
|
*/
|
|
GdkColorState *
|
|
(gdk_color_state_ref) (GdkColorState *self)
|
|
{
|
|
return _gdk_color_state_ref (self);
|
|
}
|
|
|
|
/**
|
|
* gdk_color_state_unref:
|
|
* @self:a `GdkColorState`
|
|
*
|
|
* Decrease the reference count of @self.
|
|
*
|
|
* Unless @self is static, it will be freed
|
|
* when the reference count reaches zero.
|
|
*
|
|
* Since: 4.16
|
|
*/
|
|
void
|
|
(gdk_color_state_unref) (GdkColorState *self)
|
|
{
|
|
_gdk_color_state_unref (self);
|
|
}
|
|
|
|
/**
|
|
* gdk_color_state_get_srgb:
|
|
*
|
|
* Returns the color state object representing the sRGB color space.
|
|
*
|
|
* Since: 4.16
|
|
*/
|
|
GdkColorState *
|
|
gdk_color_state_get_srgb (void)
|
|
{
|
|
return GDK_COLOR_STATE_SRGB;
|
|
}
|
|
|
|
/**
|
|
* gdk_color_state_get_srgb_linear:
|
|
*
|
|
* Returns the color state object representing the linearized sRGB color space.
|
|
*
|
|
* Since: 4.16
|
|
*/
|
|
GdkColorState *
|
|
gdk_color_state_get_srgb_linear (void)
|
|
{
|
|
return GDK_COLOR_STATE_SRGB_LINEAR;
|
|
}
|
|
|
|
/**
|
|
* gdk_color_state_equal:
|
|
* @self: a `GdkColorState`
|
|
* @other: another `GdkColorStatee`
|
|
*
|
|
* Compares two `GdkColorStates` for equality.
|
|
*
|
|
* Note that this function is not guaranteed to be perfect and two objects
|
|
* describing the same color state may compare not equal. However, different
|
|
* color states will never compare equal.
|
|
*
|
|
* Returns: %TRUE if the two color states compare equal
|
|
*
|
|
* Since: 4.16
|
|
*/
|
|
gboolean
|
|
(gdk_color_state_equal) (GdkColorState *self,
|
|
GdkColorState *other)
|
|
{
|
|
return _gdk_color_state_equal (self, other);
|
|
}
|
|
|
|
/* }}} */
|
|
/* {{{ Default implementation */
|
|
|
|
static gboolean
|
|
gdk_default_color_state_equal (GdkColorState *self,
|
|
GdkColorState *other)
|
|
{
|
|
return self == other;
|
|
}
|
|
|
|
static const char *
|
|
gdk_default_color_state_get_name (GdkColorState *color_state)
|
|
{
|
|
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
|
|
|
|
return self->name;
|
|
}
|
|
|
|
static GdkColorState *
|
|
gdk_default_color_state_get_no_srgb_tf (GdkColorState *color_state)
|
|
{
|
|
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
|
|
|
|
return self->no_srgb;
|
|
}
|
|
|
|
static inline float
|
|
srgb_oetf (float v)
|
|
{
|
|
if (v > 0.0031308f)
|
|
return 1.055f * powf (v, 1.f / 2.4f) - 0.055f;
|
|
else
|
|
return 12.92f * v;
|
|
}
|
|
|
|
static inline float
|
|
srgb_eotf (float v)
|
|
{
|
|
if (v >= 0.04045f)
|
|
return powf (((v + 0.055f) / (1.f + 0.055f)), 2.4f);
|
|
else
|
|
return v / 12.92f;
|
|
}
|
|
|
|
static void
|
|
gdk_default_srgb_to_linear_srgb (GdkColorState *self,
|
|
float (*values)[4],
|
|
gsize n_values)
|
|
{
|
|
gsize i;
|
|
|
|
for (i = 0; i < n_values; i++)
|
|
{
|
|
values[i][0] = srgb_eotf (values[i][0]);
|
|
values[i][1] = srgb_eotf (values[i][1]);
|
|
values[i][2] = srgb_eotf (values[i][2]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gdk_default_srgb_linear_to_srgb (GdkColorState *self,
|
|
float (*values)[4],
|
|
gsize n_values)
|
|
{
|
|
gsize i;
|
|
|
|
for (i = 0; i < n_values; i++)
|
|
{
|
|
values[i][0] = srgb_oetf (values[i][0]);
|
|
values[i][1] = srgb_oetf (values[i][1]);
|
|
values[i][2] = srgb_oetf (values[i][2]);
|
|
}
|
|
}
|
|
|
|
static GdkFloatColorConvert
|
|
gdk_default_color_state_get_convert_to (GdkColorState *color_state,
|
|
GdkColorState *target)
|
|
{
|
|
GdkDefaultColorState *self = (GdkDefaultColorState *) color_state;
|
|
|
|
if (!GDK_IS_DEFAULT_COLOR_STATE (target))
|
|
return NULL;
|
|
|
|
return self->convert_to[GDK_DEFAULT_COLOR_STATE_ID (target)];
|
|
}
|
|
|
|
static const
|
|
GdkColorStateClass GDK_DEFAULT_COLOR_STATE_CLASS = {
|
|
.free = NULL, /* crash here if this ever happens */
|
|
.equal = gdk_default_color_state_equal,
|
|
.get_name = gdk_default_color_state_get_name,
|
|
.get_no_srgb_tf = gdk_default_color_state_get_no_srgb_tf,
|
|
.get_convert_to = gdk_default_color_state_get_convert_to,
|
|
};
|
|
|
|
GdkDefaultColorState gdk_default_color_states[] = {
|
|
[GDK_COLOR_STATE_ID_SRGB] = {
|
|
.parent = {
|
|
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
|
.ref_count = 0,
|
|
.depth = GDK_MEMORY_U8_SRGB,
|
|
.rendering_color_state = GDK_COLOR_STATE_SRGB_LINEAR,
|
|
},
|
|
.name = "srgb",
|
|
.no_srgb = GDK_COLOR_STATE_SRGB_LINEAR,
|
|
.convert_to = {
|
|
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = gdk_default_srgb_to_linear_srgb,
|
|
},
|
|
},
|
|
[GDK_COLOR_STATE_ID_SRGB_LINEAR] = {
|
|
.parent = {
|
|
.klass = &GDK_DEFAULT_COLOR_STATE_CLASS,
|
|
.ref_count = 0,
|
|
.depth = GDK_MEMORY_U8,
|
|
.rendering_color_state = GDK_COLOR_STATE_SRGB_LINEAR,
|
|
},
|
|
.name = "srgb-linear",
|
|
.no_srgb = NULL,
|
|
.convert_to = {
|
|
[GDK_COLOR_STATE_ID_SRGB] = gdk_default_srgb_linear_to_srgb,
|
|
},
|
|
},
|
|
};
|
|
|
|
/* }}} */
|
|
/* {{{ Private API */
|
|
|
|
const char *
|
|
gdk_color_state_get_name (GdkColorState *self)
|
|
{
|
|
return self->klass->get_name (self);
|
|
}
|
|
|
|
/*<private>
|
|
* gdk_color_state_get_no_srgb_tf:
|
|
* @self: a colorstate
|
|
*
|
|
* This function checks if the colorstate uses an sRGB transfer function
|
|
* as final operation. In that case, it is suitable for use with GL_SRGB
|
|
* (and the Vulkan equivalents).
|
|
*
|
|
* If it is suitable, the colorstate without the transfer function is
|
|
* returned. Otherwise, this function returns NULL.
|
|
*
|
|
* Returns: (transfer none): the colorstate without sRGB transfer function.
|
|
**/
|
|
GdkColorState *
|
|
gdk_color_state_get_no_srgb_tf (GdkColorState *self)
|
|
{
|
|
if (!GDK_DEBUG_CHECK (LINEAR))
|
|
return FALSE;
|
|
|
|
return self->klass->get_no_srgb_tf (self);
|
|
}
|
|
|
|
/* }}} */
|
|
|
|
/* vim:set foldmethod=marker expandtab: */
|