summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2021-10-25 01:52:42 +0200
committerBenjamin Otte <otte@redhat.com>2021-10-28 03:41:09 +0200
commitc70a8def57de758d6a156e6fe71847017ad845a6 (patch)
tree8d0da301c3c0af951b6bdebee562c9274b19170d
parent37edec1dc87a9bdead5f64ccc9256fbacd2b2ca2 (diff)
downloadgtk+-c70a8def57de758d6a156e6fe71847017ad845a6.tar.gz
gdk: Introduce GdkColor
GdkColor is our new immutable high-level color representation that carries a GdkColorSpace around with it. It is explicitly designed to be 2 things: 1. small 2. compatible with GdkRGBA. 3. extensible to all sorts of colorspaces. So the struct looks like: struct { GdkColorSpace *color_space; float components[colorspace->n_components]; float alpha; }; which for RGB colors literally maps to: struct { GdkColorSpace *color_space; GdkRGBA rgba; };
-rw-r--r--gdk/gdk.h1
-rw-r--r--gdk/gdkcolor.c260
-rw-r--r--gdk/gdkcolor.h70
-rw-r--r--gdk/gdkcolorspace.c9
-rw-r--r--gdk/gdkcolorspaceprivate.h11
-rw-r--r--gdk/gdktypes.h3
-rw-r--r--gdk/meson.build2
7 files changed, 355 insertions, 1 deletions
diff --git a/gdk/gdk.h b/gdk/gdk.h
index 34209bde5e..17ff86d6f8 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -31,6 +31,7 @@
#include <gdk/gdkcairo.h>
#include <gdk/gdkcairocontext.h>
#include <gdk/gdkclipboard.h>
+#include <gdk/gdkcolor.h>
#include <gdk/gdkcolorspace.h>
#include <gdk/gdkconfig.h>
#include <gdk/gdkcontentdeserializer.h>
diff --git a/gdk/gdkcolor.c b/gdk/gdkcolor.c
new file mode 100644
index 0000000000..8eeef26f4b
--- /dev/null
+++ b/gdk/gdkcolor.c
@@ -0,0 +1,260 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * Copyright (C) 2021 Benjamin Otte
+ *
+ * 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 "gdkcolor.h"
+
+#include "gdkcolorspaceprivate.h"
+#include "gdkrgba.h"
+
+/**
+ * GdkColor:
+ *
+ * GdkColor is a high level description of a color for use in a color managed context.
+ *
+ * FIXME: Add stuff about colors in the real world and looking at `GdkColorSpace` for
+ * how this is important.
+ *
+ * If you only want to use RGB colors, consider using `GdkRGBA` instead.
+ */
+
+#define GDK_IS_COLOR(self) ((self) != NULL)
+
+struct _GdkColor
+{
+ GdkColorSpace *color_space;
+ float components[]; /* alpha is last component, so that RGBA is in exactly that order */
+};
+
+G_DEFINE_BOXED_TYPE (GdkColor, gdk_color,
+ gdk_color_copy, gdk_color_free)
+
+static GdkColor *
+gdk_color_alloc (GdkColorSpace *space)
+{
+ gsize n_components = gdk_color_space_get_n_components (space);
+ GdkColor *self;
+
+ self = g_malloc (sizeof (GdkColor) + n_components * sizeof (float));
+
+ self->color_space = g_object_ref (space);
+
+ return self;
+}
+
+/**
+ * gdk_color_new:
+ * @space: the color space of the color
+ * @alpha: the alpha value for this color
+ * @components: (array length=n_components) (nullable): an array of
+ * component values for this color
+ * @n_components: number of components
+ *
+ * Creates a new GdkColor representing the color for the given component
+ * values in the given color space.
+ *
+ * The alpha value is independent of the component values (also known as
+ * "unassociated" or "component values are not premultiplied").
+ *
+ * If the number of components passed is larger than the color space's
+ * components, extra values will be discarded. If it is smaller, the
+ * remaining components will be initialized as 0.
+ *
+ * Returns: a new GdkColor.
+ **/
+GdkColor *
+gdk_color_new (GdkColorSpace *space,
+ float alpha,
+ float *components,
+ gsize n_components)
+{
+ gsize n_color_components;
+ GdkColor *self;
+
+ g_return_val_if_fail (GDK_IS_COLOR_SPACE (space), NULL);
+ g_return_val_if_fail (components != NULL || n_components == 0, NULL);
+
+ self = gdk_color_alloc (space);
+ n_color_components = gdk_color_space_get_n_components (space);
+ if (n_components)
+ memcpy (self->components, components, MIN (n_components, n_color_components));
+ if (n_components < n_color_components)
+ memset (&self->components[n_components], 0, sizeof (float) * (n_color_components - n_components));
+ self->components[n_color_components] = alpha;
+
+ return self;
+}
+
+G_STATIC_ASSERT (sizeof (GdkRGBA) == 4 * sizeof (float));
+
+/**
+ * gdk_color_new_from_rgba:
+ * @rgba: a GdkRGBA
+ *
+ * Creates a new GdkColor from the given GdkRGBA.
+ *
+ * Returns: a new GdkColor
+ **/
+GdkColor *
+gdk_color_new_from_rgba (const GdkRGBA *rgba)
+{
+ GdkColor *self;
+
+ g_return_val_if_fail (rgba != NULL, NULL);
+
+ self = gdk_color_alloc (gdk_color_space_get_srgb ());
+ memcpy (self->components, rgba, sizeof (GdkRGBA));
+
+ return self;
+}
+
+/**
+ * gdk_color_copy:
+ * @self: a `GdkColor`
+ *
+ * Copies the color.
+ *
+ * Returns: a copy of the color.
+ **/
+GdkColor *
+gdk_color_copy (const GdkColor *self)
+{
+ GdkColor *copy;
+
+ copy = gdk_color_alloc (self->color_space);
+ memcpy (copy->components,
+ self->components,
+ sizeof (float) * (gdk_color_space_get_n_components (self->color_space) + 1));
+
+ return copy;
+}
+
+/**
+ * gdk_color_free:
+ * @self: a #GdkColor
+ *
+ * Frees a `GdkColor`.
+ **/
+void
+gdk_color_free (GdkColor *self)
+{
+ g_object_unref (self->color_space);
+ g_free (self);
+}
+
+/**
+ * gdk_color_get_color_space:
+ * @self: a `GdkColor`
+ *
+ * Returns the color space that this color is defined in.
+ *
+ * Returns: the color space this color is defined in
+ **/
+GdkColorSpace *
+gdk_color_get_color_space (const GdkColor *self)
+{
+ g_return_val_if_fail (GDK_IS_COLOR (self), gdk_color_space_get_srgb ());
+
+ return self->color_space;
+}
+
+/**
+ * gdk_color_get_alpha:
+ * @self: a `GdkColor`
+ *
+ * Gets the alpha value of this color. Alpha values range from 0.0
+ * (fully translucent) to 1.0 (fully opaque).
+ *
+ * Returns: The alpha value
+ **/
+float
+gdk_color_get_alpha (const GdkColor *self)
+{
+ g_return_val_if_fail (GDK_IS_COLOR (self), 1.f);
+
+ return self->components[gdk_color_space_get_n_components (self->color_space)];
+}
+
+/**
+ * gdk_color_get_components:
+ * @self: a `GdkColor`
+ *
+ * Returns the array of component values for this color.
+ *
+ * For an RGB color, this will be an array of 3 values with intensities of
+ * the red, green and blue components, respectively, in a range from 0 to 1.
+ *
+ * Other color spaces that are not RGB colors can have a different amount of
+ * components with different meanings and different ranges.
+ *
+ * Returns: the component values
+ **/
+const float *
+gdk_color_get_components (const GdkColor *self)
+{
+ g_return_val_if_fail (GDK_IS_COLOR (self), NULL);
+
+ return self->components;
+}
+
+/**
+ * gdk_color_get_n_components:
+ * @self: a `GdkColor`
+ *
+ * Gets the number of components of this color. This will be the number of
+ * components returned by gdk_color_get_components().
+ *
+ * Returns: the number of components
+ **/
+gsize
+gdk_color_get_n_components (const GdkColor *self)
+{
+ g_return_val_if_fail (GDK_IS_COLOR (self), 3);
+
+ return gdk_color_space_get_n_components (self->color_space);
+}
+
+/**
+ * gdk_color_convert:
+ * @self: a `GdkColor`
+ * @space: the color space to convert to
+ *
+ * Converts a color into a different colorspace, potentially
+ * tone-mapping it if it is out of gamut.
+ *
+ * Returns: a new color in the new colorspace.
+ **/
+GdkColor *
+gdk_color_convert (const GdkColor *self,
+ GdkColorSpace *space)
+{
+ GdkColor *result;
+ gsize n_components;
+
+ g_return_val_if_fail (GDK_IS_COLOR (self), NULL);
+ g_return_val_if_fail (GDK_IS_COLOR_SPACE (space), NULL);
+
+ result = gdk_color_alloc (space);
+ n_components = gdk_color_space_get_n_components (self->color_space);
+ result->components[n_components] = self->components[n_components];
+ GDK_COLOR_SPACE_GET_CLASS (space)->convert_color (space, result->components, self);
+
+ return result;
+}
+
diff --git a/gdk/gdkcolor.h b/gdk/gdkcolor.h
new file mode 100644
index 0000000000..2cff4ebb20
--- /dev/null
+++ b/gdk/gdkcolor.h
@@ -0,0 +1,70 @@
+/* gdkcolor.h
+ *
+ * Copyright 2021 (c) Benjamin Otte
+ *
+ * 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/>.
+ */
+
+#ifndef __GDK_COLOR_H__
+#define __GDK_COLOR_H__
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdkversionmacros.h>
+#include <gdk/gdktypes.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_COLOR (gdk_color_get_type ())
+
+GDK_AVAILABLE_IN_4_6
+GType gdk_color_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_4_6
+GdkColor * gdk_color_new (GdkColorSpace *space,
+ float alpha,
+ float *components,
+ gsize n_components);
+GDK_AVAILABLE_IN_4_6
+GdkColor * gdk_color_new_from_rgba (const GdkRGBA *rgba);
+GDK_AVAILABLE_IN_4_6
+GdkColor * gdk_color_copy (const GdkColor *self);
+GDK_AVAILABLE_IN_4_6
+void gdk_color_free (GdkColor *self);
+
+GDK_AVAILABLE_IN_4_6
+GdkColorSpace * gdk_color_get_color_space (const GdkColor *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_6
+float gdk_color_get_alpha (const GdkColor *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_6
+const float * gdk_color_get_components (const GdkColor *self) G_GNUC_PURE;
+GDK_AVAILABLE_IN_4_6
+gsize gdk_color_get_n_components (const GdkColor *self) G_GNUC_PURE;
+
+GDK_AVAILABLE_IN_4_6
+GdkColor * gdk_color_convert (const GdkColor *self,
+ GdkColorSpace *space);
+/*
+GDK_AVAILABLE_IN_4_6
+GdkColor * gdk_color_mix (const GdkColor *self,
+ const GdkColor *other,
+ double progress,
+ GdkColorSpace *space);
+*/
+
+G_END_DECLS
+
+#endif /* __GDK_COLOR_H__ */
diff --git a/gdk/gdkcolorspace.c b/gdk/gdkcolorspace.c
index 5bf4f94593..4f8d9a74af 100644
--- a/gdk/gdkcolorspace.c
+++ b/gdk/gdkcolorspace.c
@@ -63,6 +63,14 @@ gdk_color_space_default_save_to_icc_profile (GdkColorSpace *self,
}
static void
+gdk_color_space_default_convert_color (GdkColorSpace *self,
+ float *components,
+ const GdkColor *source)
+{
+ g_assert_not_reached ();
+}
+
+static void
gdk_color_space_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
@@ -109,6 +117,7 @@ gdk_color_space_class_init (GdkColorSpaceClass *klass)
klass->supports_format = gdk_color_space_default_supports_format;
klass->save_to_icc_profile = gdk_color_space_default_save_to_icc_profile;
+ klass->convert_color = gdk_color_space_default_convert_color;
gobject_class->set_property = gdk_color_space_set_property;
gobject_class->get_property = gdk_color_space_get_property;
diff --git a/gdk/gdkcolorspaceprivate.h b/gdk/gdkcolorspaceprivate.h
index 06646c4394..f65c9b6bda 100644
--- a/gdk/gdkcolorspaceprivate.h
+++ b/gdk/gdkcolorspaceprivate.h
@@ -8,6 +8,8 @@ G_BEGIN_DECLS
struct _GdkColorSpace
{
GObject parent_instance;
+
+ gsize n_components;
};
struct _GdkColorSpaceClass
@@ -18,8 +20,17 @@ struct _GdkColorSpaceClass
GdkMemoryFormat format);
GBytes * (* save_to_icc_profile) (GdkColorSpace *self,
GError **error);
+
+ void (* convert_color) (GdkColorSpace *self,
+ float *components,
+ const GdkColor *source);
};
+static inline gsize
+gdk_color_space_get_n_components (GdkColorSpace *self)
+{
+ return self->n_components;
+}
G_END_DECLS
diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h
index 65be1075e3..18d04543d8 100644
--- a/gdk/gdktypes.h
+++ b/gdk/gdktypes.h
@@ -73,7 +73,8 @@ typedef cairo_rectangle_int_t GdkRectangle;
/* Forward declarations of commonly used types */
typedef struct _GdkRGBA GdkRGBA;
-typedef struct _GdkColorSpace GdkColorSpace;
+typedef struct _GdkColor GdkColor;
+typedef struct _GdkColorSpace GdkColorSpace;
typedef struct _GdkContentFormats GdkContentFormats;
typedef struct _GdkContentProvider GdkContentProvider;
typedef struct _GdkCursor GdkCursor;
diff --git a/gdk/meson.build b/gdk/meson.build
index d6384baee5..a17c9a068c 100644
--- a/gdk/meson.build
+++ b/gdk/meson.build
@@ -4,6 +4,7 @@ gdk_public_sources = files([
'gdkcairo.c',
'gdkcairocontext.c',
'gdkclipboard.c',
+ 'gdkcolor.c',
'gdkcolorspace.c',
'gdkcontentdeserializer.c',
'gdkcontentformats.c',
@@ -66,6 +67,7 @@ gdk_public_headers = files([
'gdkcairo.h',
'gdkcairocontext.h',
'gdkclipboard.h',
+ 'gdkcolor.h',
'gdkcolorspace.h',
'gdkcontentdeserializer.h',
'gdkcontentformats.h',