[gtk/wip/otte/colorspace: 49/50] gdk: Introduce GdkColor




commit c70a8def57de758d6a156e6fe71847017ad845a6
Author: Benjamin Otte <otte redhat com>
Date:   Mon Oct 25 01:52:42 2021 +0200

    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;
      };

 gdk/gdk.h                  |   1 +
 gdk/gdkcolor.c             | 260 +++++++++++++++++++++++++++++++++++++++++++++
 gdk/gdkcolor.h             |  70 ++++++++++++
 gdk/gdkcolorspace.c        |   9 ++
 gdk/gdkcolorspaceprivate.h |  11 ++
 gdk/gdktypes.h             |   3 +-
 gdk/meson.build            |   2 +
 7 files changed, 355 insertions(+), 1 deletion(-)
---
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
@@ -62,6 +62,14 @@ gdk_color_space_default_save_to_icc_profile (GdkColorSpace  *self,
   return NULL;
 }
 
+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,
@@ -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',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]