diff options
author | Benjamin Otte <otte@redhat.com> | 2021-10-25 01:52:42 +0200 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2021-10-28 03:41:09 +0200 |
commit | c70a8def57de758d6a156e6fe71847017ad845a6 (patch) | |
tree | 8d0da301c3c0af951b6bdebee562c9274b19170d | |
parent | 37edec1dc87a9bdead5f64ccc9256fbacd2b2ca2 (diff) | |
download | gtk+-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.h | 1 | ||||
-rw-r--r-- | gdk/gdkcolor.c | 260 | ||||
-rw-r--r-- | gdk/gdkcolor.h | 70 | ||||
-rw-r--r-- | gdk/gdkcolorspace.c | 9 | ||||
-rw-r--r-- | gdk/gdkcolorspaceprivate.h | 11 | ||||
-rw-r--r-- | gdk/gdktypes.h | 3 | ||||
-rw-r--r-- | gdk/meson.build | 2 |
7 files changed, 355 insertions, 1 deletions
@@ -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', |