Compare commits

...

70 Commits

Author SHA1 Message Date
Matthias Clasen
8b3957f20f css: Port border rendering 2024-06-16 17:05:31 -04:00
Matthias Clasen
12e67c644c css: Port the rest of background rendering
Now that gradients are handled, pass background color along
properly to gsk as well.
2024-06-16 16:12:41 -04:00
Matthias Clasen
f94bdbeedb css: Implement gradient interpolation
Pass the interpolation color space down to gsk.
2024-06-16 16:12:41 -04:00
Matthias Clasen
8dc4faac96 Start porting the inspector to new snapshot apis 2024-06-16 16:10:25 -04:00
Matthias Clasen
6aeb0ef751 Port GtkIconTheme to new snapshot apis 2024-06-16 16:10:25 -04:00
Matthias Clasen
f622f21c0f Port GtkGraphicsOffload to new snapshot apis: 2024-06-16 16:10:25 -04:00
Matthias Clasen
74ad081dd8 Port GtkCssShadowValue to new snapshot apis 2024-06-16 16:10:25 -04:00
Matthias Clasen
b3aff6570d Port gtkCssImageFfallback to new snapshot apis 2024-06-16 16:10:25 -04:00
Matthias Clasen
fcffe94259 Port GtkColorSwatch to new snapshot apis 2024-06-16 16:10:25 -04:00
Matthias Clasen
37e12d1fa1 Port GtkColorPlane to new snapshot apis 2024-06-16 16:10:25 -04:00
Matthias Clasen
e083ff1fed css: Add some utilities
Add functions to translate from css types to gdk and gsk ones
for colors and color spaces.
2024-06-16 16:10:10 -04:00
Matthias Clasen
6d2f311942 snapshot: Port to GdkColor
Add a full family of -2 apis that replace GdkRGBA, GskColorStop
and GskShadow with GdkColor, GskColorStop2 and GskShadow2.

The implementation of gtk_snapshot_append_layout() is not
completely converted yet.
2024-06-16 16:05:49 -04:00
Matthias Clasen
5765b0d795 testsuite: Ignore deprecations
Not porting these tests to -2 apis right now, let them continue
to test the old apis.
2024-06-16 16:05:49 -04:00
Matthias Clasen
8eec8f8234 gl: Ignore deprecations
Not going to fix up all this code right now.
2024-06-16 16:05:49 -04:00
Matthias Clasen
7d62a85825 Deprecate all the old rendernode apis
Deprecate everything where we added a -2 version recently.
2024-06-16 16:05:49 -04:00
Matthias Clasen
e444cdae9d Try a new approach
Instead of caching converted textures and maintaining color state
information in the cache, always store textures as-is, and give
all shaders that operate on images variations to deal with color
state conversion.
2024-06-16 15:58:27 -04:00
Matthias Clasen
fd17c4a425 Fix gradients
Now that we allow different color states in color stops, we need
to take care of converting them.
2024-06-16 15:57:26 -04:00
Matthias Clasen
c3cc3cdacc gpu: Improve texture caching
Keep up to two different images per texture - that is enough to
keep the original uploaded image and the one that has been converted
to the compositing colorstate.
2024-06-16 15:57:26 -04:00
Matthias Clasen
0402a350e7 Make display colorstate settable
Just for debugging
2024-06-16 15:57:25 -04:00
Matthias Clasen
74460f148b gpu: Complete porting away from GdkRGBA apis 2024-06-16 15:57:25 -04:00
Matthias Clasen
89609ec412 inspector: Port to GdkColor 2024-06-16 15:57:25 -04:00
Matthias Clasen
598874dc7b More conversion work
Move from GdkRGBA to GdkColor in many places.
2024-06-16 15:57:25 -04:00
Matthias Clasen
ea6b5b4425 Allow border nodes to carry color states 2024-06-16 15:57:25 -04:00
Matthias Clasen
b415e74dbd Allow shadow nodes to carry a color state 2024-06-16 15:57:25 -04:00
Matthias Clasen
8d9532d204 Fix patterns for color and text nodes 2024-06-16 15:57:25 -04:00
Matthias Clasen
0764cfe566 Gradients for the pattern shader 2024-06-16 15:57:25 -04:00
Matthias Clasen
1f1e41bdaa Introduce GskColorStop2 2024-06-16 15:57:25 -04:00
Matthias Clasen
c690079ee5 Let text nodes carry a color state
We use the same approach as for color nodes, and make a union
of GdkRGBA and GdkColor.
2024-06-16 15:57:25 -04:00
Matthias Clasen
c59b7bde2a Let color nodes carry a color state
We make a union of GdkRGBA and GdkColor, and add new getters.
2024-06-16 15:57:25 -04:00
Matthias Clasen
74f5bcdd4a rendernodeparser: Allow more colors
Parse colors like color(XXX x y z / alpha). Unlike css, we allow
all our named color spaces here, with the same ranges as defined
for css. Percentages are allowed, but things like currentcolor,
relative colors, missing components, calc() are not.
2024-06-16 15:57:25 -04:00
Matthias Clasen
a7c2c7c041 gpu: Handle color states for gradients
The plan is to convert the color stops into the interpolation
color state, let the shader to the interpolation, and convert
from the interpolation color state to the compositing color
state afterwards. This isn't hooked up yet, since we don't have
interpolation color states in the render nodes yet.
2024-06-16 15:57:25 -04:00
Matthias Clasen
537f8ec69b gpu: Use the clip for color conversion
When creating the offscreen for color conversion, take the clip
into account - we don't need a bigger offscreen than that.
2024-06-16 15:57:25 -04:00
Matthias Clasen
134ec9343d gpu: Avoid an offscreen when possible 2024-06-16 15:57:25 -04:00
Matthias Clasen
79c214e75d gpu: Convert colors to the right color state
Currently, all the colors in render nodes are srgb. Convert them
to the compositing color state before using them. We store the
converted colors in a GdkRGBA (somewhat against its definition),
since all the op apis are expecting GdkRGBA for colors. This should
be cleaned up later.
2024-06-16 15:57:25 -04:00
Matthias Clasen
f271049263 gpu: Use stem darkening for linear composited glyphs
When the compositing color state is linear, apply the freetype
stem darkening hack.
2024-06-16 15:57:25 -04:00
Matthias Clasen
fb5d69fc02 gpu: Take color state into account for glyph lookup
Add a 'linear' bit to the glyph cache key, so we can get have
separate cached images for the two cases. Note that the image
tagging with color state is ignored here - we simply copy the
glyph image out of the atlas as-is, and rely on the cache to
give use the right color state.
2024-06-16 15:57:25 -04:00
Matthias Clasen
b27eaa344b gpu: Track color state in the texture cache
Keep the color state information around for cached images and
handle the necessary conversions when using them.
2024-06-16 15:57:25 -04:00
Matthias Clasen
d245674c1f gpu: Use the right depth when creating offscreens 2024-06-16 15:57:25 -04:00
Matthias Clasen
4c7526ad99 gpu: Convert textures to the right color state
Add function to convert an image from one color state to another,
and call it whenever we upload a texture.
2024-06-16 15:57:25 -04:00
Matthias Clasen
d83643d6fc gpu: Add a color convert shader
This shader converts between named color states, by using the
same functions that we use on the cpu. The conversion to perform
is passed as an integer encoding the pair of color states. If
we don't have a direction function for going from the first to
the second, we go via XYZ.
2024-06-16 15:57:25 -04:00
Matthias Clasen
e979595280 Make compositing colorstate settable
This helps for debugging.
2024-06-16 15:57:25 -04:00
Matthias Clasen
6b76c13bcc gpu: Pass compositing color states around
Make the node processor and the pattern writer track the current
compositing color state. Color state nodes change it. We pass
the surface color state down via the frame apis.
2024-06-16 15:57:25 -04:00
Matthias Clasen
5ab831215e testsuite: Replay color state nodes 2024-06-16 15:57:25 -04:00
Matthias Clasen
1e404f6625 Add gtk_snapshot_push_color_state 2024-06-16 15:57:25 -04:00
Matthias Clasen
2dc85d7e5f Add a color state node 2024-06-16 15:57:25 -04:00
Matthias Clasen
5f706c73fd testsuite: Compare textures properly
When compoaring textures, we now need to look
at the colorspace as well.
2024-06-16 15:57:25 -04:00
Matthias Clasen
208e5a9931 gtk-demo: Add a color space demo
This is using test images from http://displaycal.net/.
2024-06-16 15:57:25 -04:00
Benjamin Otte
421e8dcbc8 widget-factory: Add gradient rendering test
Test how GTK draws gradients, by adding an sRGB and a linear colorspace
gradient and draw one with CSS.

Have a look which one (if any) matches.
2024-06-16 15:57:25 -04:00
Matthias Clasen
2bc12a8b27 cairo: Use stem darkening for glyphs
This involves tweaking a freetype driver property
directly, since cairo font options don't cover this.

So the code is a bit ugly, but it does make text
appear darker.
2024-06-16 15:57:25 -04:00
Matthias Clasen
bfca93eafc Port gsk_render_node_draw to GdkColor
Use GdkColor when using cairo for rendering. This makes it so that
the rendering happens in a color-managed way when a color state has
been attached to the target.
2024-06-16 15:57:25 -04:00
Matthias Clasen
bd2ac3e897 cairo: Use GdkColor 2024-06-16 15:57:25 -04:00
Matthias Clasen
1e1c8d1a6d Add crude color management impl for cairo
Use linear compositing with cairo if LINEAR_COMPOSITING=1 is
set in the environment.
2024-06-16 15:57:25 -04:00
Matthias Clasen
7b4f08eea6 Add gdk_cairo_set_source_color 2024-06-16 15:57:25 -04:00
Benjamin Otte
baefbc5259 Add color space get/set for cairo
Add a centralized place to attach color space to.

Nothing uses that information yet, but all the
backends do set it.
2024-06-16 15:57:25 -04:00
Matthias Clasen
81da727a9c gdk: Introduce GdkColor
GdkColor represents a color in the real world, by combining a color
profile, an alpha value and N component values.
2024-06-16 15:57:25 -04:00
Benjamin Otte
13e3242e7d gdk: Add GDK_DEBUG=srgb
Disables gdk_surface_set_color_profile() for backends and forces
sRGB.

This does not change any GSK renderers, it just turns off any backends
trying to hand us color profiles.
2024-06-16 15:57:25 -04:00
Benjamin Otte
afb02f2d54 x11: Implement support for color states
Stole the implementation from eog.

This doesn't yet update the color state when it changes though.
2024-06-16 15:57:25 -04:00
Matthias Clasen
c53772908c Give surfaces a color state
Add api to get the color state of a surface.
2024-06-16 15:57:25 -04:00
Matthias Clasen
83523d88f6 Add color state to texture download methods 2024-06-16 15:57:25 -04:00
Matthias Clasen
b5e4bf7a70 Add color states to gdk_memory_convert
This lets us perform color space conversions at the same time
as memory format changes.
2024-06-16 15:57:25 -04:00
Matthias Clasen
1c1d52cc59 pixbuf: Add color state support
When creating a GdkTexture from a GdkPixbuf, see if it has an
icc profile attached, and if so, use it.
2024-06-16 15:57:25 -04:00
Matthias Clasen
6b600a2bd8 tiff: Add color state support
When loading or saving tiff files, translate between embedded
icc profiles and color state objects.
2024-06-16 15:57:25 -04:00
Benjamin Otte
e3100bde3b png: Add color state support
When loading or saving png files, translate between embedded
icc profiles or cicp data and color state objects.
2024-06-16 15:57:25 -04:00
Benjamin Otte
5395e839a3 jpeg: Add color state support
When loading or saving jpeg files, translate between embedded
icc profiles and color state objects.
2024-06-16 15:57:25 -04:00
Matthias Clasen
9cbe82d7fe dmabuf texture: color state support 2024-06-16 15:57:25 -04:00
Matthias Clasen
8ed427dab9 gl texture: color state support 2024-06-16 15:57:25 -04:00
Matthias Clasen
47fe542e62 memory texture: color state support 2024-06-16 15:57:25 -04:00
Matthias Clasen
67e3afe42e Give textures a color state 2024-06-16 15:57:25 -04:00
Matthias Clasen
b2e72700e8 Add some colorstate tests
This is very minimal, but it is enough to do
a very basic check of the gdk_color_space_equal
implementation.
2024-06-16 15:57:25 -04:00
Matthias Clasen
ae1e2a13d1 Add GdkColorState
This is just an empty shell for now.
2024-06-16 15:57:25 -04:00
176 changed files with 8857 additions and 1002 deletions

View File

@@ -35,7 +35,11 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-python-gobject \
mingw-w64-$MSYS2_ARCH-shaderc \
mingw-w64-$MSYS2_ARCH-vulkan \
mingw-w64-$MSYS2_ARCH-vulkan-headers
mingw-w64-$MSYS2_ARCH-vulkan-headers \
mingw-w64-$MSYS2_ARCH-libpng \
mingw-w64-$MSYS2_ARCH-libjpeg-turbo \
mingw-w64-$MSYS2_ARCH-libtiff \
mingw-w64-$MSYS2_ARCH-lcms2
mkdir -p _ccache
export CCACHE_BASEDIR="$(pwd)"

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

View File

@@ -0,0 +1,86 @@
/* Color Spaces
*
* Demonstrates support for color spaces.
*
* The test images used here are taken from http://displaycal.net/icc-color-management-test/
* and are licensed under the Creative Commons BY-SA 4.0 International License
*/
#include <gtk/gtk.h>
static GtkWidget *jpeg;
static GtkWidget *png;
static GtkWidget *tiff;
static GtkWidget *noprofile;
static GtkWidget *test1;
static GtkWidget *test2;
static void
on_changed (GtkCheckButton *button,
gpointer user_data)
{
GdkTexture *texture;
const char *extension = NULL;
char *path;
if (!gtk_check_button_get_active (GTK_CHECK_BUTTON (button)))
return;
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (jpeg)))
extension = ".jpg";
else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (png)))
extension = ".png";
else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (tiff)))
extension = ".tif";
else if (gtk_check_button_get_active (GTK_CHECK_BUTTON (noprofile)))
extension = "-expected-result-no-cm.png";
path = g_strconcat ("/colorspaces/sRGB_Gray", extension, NULL);
texture = gdk_texture_new_from_resource (path);
gtk_picture_set_paintable (GTK_PICTURE (test1), GDK_PAINTABLE (texture));
g_object_unref (texture);
path = g_strconcat ("/colorspaces/ICC-Rendering-Intent-Test", extension, NULL);
texture = gdk_texture_new_from_resource (path);
gtk_picture_set_paintable (GTK_PICTURE (test2), GDK_PAINTABLE (texture));
g_object_unref (texture);
}
GtkWidget*
do_colorspaces (GtkWidget *do_widget)
{
static GtkWidget *window;
if (!window)
{
GtkBuilder *builder;
GtkBuilderScope *scope;
scope = gtk_builder_cscope_new ();
gtk_builder_cscope_add_callback_symbol (GTK_BUILDER_CSCOPE (scope),
"on_changed", G_CALLBACK (on_changed));
builder = gtk_builder_new ();
gtk_builder_set_scope (builder, scope);
gtk_builder_add_from_resource (builder, "/colorspaces/colorspaces.ui", NULL);
window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
jpeg = GTK_WIDGET (gtk_builder_get_object (builder, "jpeg"));
png = GTK_WIDGET (gtk_builder_get_object (builder, "png"));
tiff = GTK_WIDGET (gtk_builder_get_object (builder, "tiff"));
noprofile = GTK_WIDGET (gtk_builder_get_object (builder, "noprofile"));
test1 = GTK_WIDGET (gtk_builder_get_object (builder, "test1"));
test2 = GTK_WIDGET (gtk_builder_get_object (builder, "test2"));
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
g_object_unref (builder);
g_object_unref (scope);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -0,0 +1,94 @@
<interface>
<object class="GtkWindow" id="window">
<property name="default-width">660</property>
<property name="default-height">660</property>
<property name="resizable">false</property>
<property name="title">Color Profiles</property>
<child>
<object class="GtkScrolledWindow">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkLabel">
<property name="label">File format:</property>
</object>
</child>
<child>
<object class="GtkCheckButton" id="jpeg">
<property name="label">JPEG</property>
<property name="active">1</property>
<signal name="notify::active" handler="on_changed"/>
</object>
</child>
<child>
<object class="GtkCheckButton" id="png">
<property name="label">PNG</property>
<property name="group">jpeg</property>
<signal name="notify::active" handler="on_changed"/>
</object>
</child>
<child>
<object class="GtkCheckButton" id="tiff">
<property name="label">TIFF</property>
<property name="group">png</property>
<signal name="notify::active" handler="on_changed"/>
</object>
</child>
<child>
<object class="GtkCheckButton" id="noprofile">
<property name="label">No profile</property>
<property name="group">tiff</property>
<signal name="notify::active" handler="on_changed"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Test 1: Matrix-based profile</property>
<style>
<class name="title-3"/>
</style>
</object>
</child>
<child>
<object class="GtkPicture" id="test1">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="can-shrink">1</property>
<property name="keep-aspect-ratio">1</property>
<property name="file">resource:///colorprofiles/sRGB_Gray.jpg</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Test 2: Lookup table-based profile</property>
<style>
<class name="title-3"/>
</style>
</object>
</child>
<child>
<object class="GtkPicture" id="test2">
<property name="hexpand">1</property>
<property name="vexpand">1</property>
<property name="can-shrink">1</property>
<property name="keep-aspect-ratio">1</property>
<property name="file">resource:///colorprofiles/ICC-Rendering-Intent-Test.jpg</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -19,6 +19,17 @@
<file>demoimage.c</file>
<file>demoimage.h</file>
</gresource>
<gresource prefix="/colorspaces">
<file>colorspaces.ui</file>
<file>sRGB_Gray.jpg</file>
<file>sRGB_Gray.png</file>
<file>sRGB_Gray.tif</file>
<file>sRGB_Gray-expected-result-no-cm.png</file>
<file>ICC-Rendering-Intent-Test.png</file>
<file>ICC-Rendering-Intent-Test.jpg</file>
<file>ICC-Rendering-Intent-Test.tif</file>
<file>ICC-Rendering-Intent-Test-expected-result-no-cm.png</file>
</gresource>
<gresource prefix="/constraints_builder">
<file>constraints_builder.ui</file>
</gresource>
@@ -265,6 +276,7 @@
<file>assistant.c</file>
<file>builder.c</file>
<file>clipboard.c</file>
<file>colorspaces.c</file>
<file>combobox.c</file>
<file>constraints.c</file>
<file>constraints_interactive.c</file>

View File

@@ -5,6 +5,7 @@ demos = files([
'assistant.c',
'builder.c',
'clipboard.c',
'colorspaces.c',
'combobox.c',
'constraints.c',
'constraints_interactive.c',

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

View File

@@ -117,16 +117,27 @@ should be aware that the allowed values are meant to be used on 3D transformatio
so their naming might appear awkward. However, it is always possible to use the
matrix3d() production to specify all 16 values individually.
### color-state
| property | syntax | default | printed |
| ----------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| color-state | `<ident>|<url>` | srgb | always |
Creates a node like `gsk_color_state_node_new()` with the given properties.
### conic-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25, 25 | always |
| rotation | `<number>` | 0 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | ----------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25, 25 | always |
| rotation | `<number>` | 0 | always |
| color-state | `<ident>`|`<url>` | srgb | non-default |
| hue-interpolation | `<ident>` | shorter | non-default |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
Creates a node like `gsk_conic_gradient_node_new()` with the given properties.
Creates a node like `gsk_conic_gradient_node_new_in()` with the given properties.
### cross-fade
@@ -192,14 +203,16 @@ Creates a node like `gsk_inset_shadow_node_new()` with the given properties.
### linear-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| start | `<point>` | 0 0 | always |
| end | `<point>` | 0 50 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | ----------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| start | `<point>` | 0 0 | always |
| end | `<point>` | 0 50 | always |
| color-state | `<ident>`|`<url>` | srgb | non-default |
| hue-interpolation | `<ident>` | shorter | non-default |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
Creates a node like `gsk_linear_gradient_node_new()` with the given properties.
Creates a node like `gsk_linear_gradient_node_new_in()` with the given properties.
### mask
@@ -235,15 +248,17 @@ Creates a node like `gsk_outset_shadow_node_new()` with the given properties.
### radial-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25 25 | always |
| hradius | `<number>` | 25 | always |
| vradius | `<number>` | 25 | always |
| start | `<number>` | 0 | always |
| end | `<number>` | 1 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | ----------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25 25 | always |
| hradius | `<number>` | 25 | always |
| vradius | `<number>` | 25 | always |
| start | `<number>` | 0 | always |
| end | `<number>` | 1 | always |
| color-state | `<ident>`|`<url>` | srgb | non-default |
| hue-interpolation | `<ident>` | shorter | non-default |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
Creates a node like `gsk_radial_gradient_node_new()` with the given properties.
@@ -259,29 +274,33 @@ Creates a node like `gsk_repeat_node_new()` with the given properties.
### repeating-linear-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| start | `<point>` | 0 0 | always |
| end | `<point>` | 0 50 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | ----------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| start | `<point>` | 0 0 | always |
| end | `<point>` | 0 50 | always |
| color-state | `<ident>`|`<url>` | srgb | non-default |
| hue-interpolation | `<ident>` | shorter | non-default |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
Creates a node like `gsk_repeating_linear_gradient_node_new()` with the given
Creates a node like `gsk_repeating_linear_gradient_node_new_in()` with the given
properties.
### repeating radial-gradient
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25 25 | always |
| hradius | `<number>` | 25 | always |
| vradius | `<number>` | 25 | always |
| start | `<number>` | 0 | always |
| end | `<number>` | 1 | always |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
| property | syntax | default | printed |
| ----------------- | ----------------- | ---------------------- | ----------- |
| bounds | `<rect>` | 50 | always |
| center | `<point>` | 25 25 | always |
| hradius | `<number>` | 25 | always |
| vradius | `<number>` | 25 | always |
| start | `<number>` | 0 | always |
| end | `<number>` | 1 | always |
| color-state | `<ident>`|`<url>` | srgb | non-default |
| hue-interpolation | `<ident>` | shorter | non-default |
| stops | `<color-stop>` | 0 #AF0, 1 #F0C | always |
Creates a node like `gsk_repeating_radial_gradient_node_new()` with the given
Creates a node like `gsk_repeating_radial_gradient_node_new_in()` with the given
properties.
### rounded-clip

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

View File

@@ -6,3 +6,10 @@
.toolbar {
-gtk-icon-style: symbolic;
}
.gtk-gradient-color {
background: linear-gradient(to right, lime, red);
}
.gtk-gradient-monochrome {
background: linear-gradient(to right, black, white);
}

View File

@@ -117,5 +117,9 @@
<file>portland-rose.jpg</file>
<file>nyc.jpg</file>
<file>beach.jpg</file>
<file>linear-gradient-color.png</file>
<file>linear-gradient-monochrome.png</file>
<file>srgb-gradient-color.png</file>
<file>srgb-gradient-monochrome.png</file>
</gresource>
</gresources>

View File

@@ -1344,13 +1344,173 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<child>
<object class="GtkNotebookPage">
<property name="child">
<object class="GtkBox" id="box8">
<property name="orientation">1</property>
<object class="GtkGrid">
<property name="hexpand">0</property>
<property name="row-spacing">6</property>
<property name="column-spacing">6</property>
<property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="margin-top">6</property>
<property name="margin-bottom">6</property>
<property name="row-homogeneous">1</property>
<property name="valign">start</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">color</property>
<style>
<class name="caption-heading"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">sRGB</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/srgb-gradient-color.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">GTK</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="width-request">128</property>
<property name="keep-aspect-ratio">0</property>
<style>
<class name="gtk-gradient-color"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">linear</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/linear-gradient-color.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">monochrome</property>
<style>
<class name="caption-heading"/>
</style>
<layout>
<property name="column">0</property>
<property name="row">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">sRGB</property>
<layout>
<property name="column">0</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/srgb-gradient-monochrome.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">5</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">GTK</property>
<layout>
<property name="column">0</property>
<property name="row">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="width-request">128</property>
<property name="keep-aspect-ratio">0</property>
<style>
<class name="gtk-gradient-monochrome"/>
</style>
<layout>
<property name="column">1</property>
<property name="row">6</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">linear</property>
<layout>
<property name="column">0</property>
<property name="row">7</property>
</layout>
</object>
</child>
<child>
<object class="GtkPicture">
<property name="file">resource:///org/gtk/WidgetFactory4/linear-gradient-monochrome.png</property>
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">0</property>
<layout>
<property name="column">1</property>
<property name="row">7</property>
</layout>
</object>
</child>
</object>
</property>
<property name="tab">
<object class="GtkLabel" id="label8">
<property name="label" translatable="1">page 1</property>
<property name="label" translatable="1">Gradients</property>
</object>
</property>
</object>

View File

@@ -46,9 +46,10 @@ gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context,
width = gdk_surface_get_width (surface);
height = gdk_surface_get_height (surface);
scale = gdk_surface_get_scale_factor (surface);
self->paint_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
width * scale, height * scale);
cairo_surface_set_device_scale (self->paint_surface, scale, scale);
self->paint_surface = gdk_surface_create_similar_surface (surface,
CAIRO_CONTENT_COLOR_ALPHA,
width * scale, height *scale);
repaint_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { 0, 0, width, height });
cairo_region_union (region, repaint_region);

View File

@@ -19,7 +19,7 @@
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
@@ -138,6 +138,7 @@ static const GdkDebugKey gdk_debug_keys[] = {
{ "high-depth", GDK_DEBUG_HIGH_DEPTH, "Use high bit depth rendering if possible" },
{ "no-vsync", GDK_DEBUG_NO_VSYNC, "Repaint instantly (uses 100% CPU with animations)" },
{ "dmabuf-disable", GDK_DEBUG_DMABUF_DISABLE, "Disable dmabuf support" },
{ "srgb", GDK_DEBUG_SRGB, "Force sRRGB rendering and turn off color profiles" },
};

View File

@@ -30,6 +30,8 @@
#include <gdk/gdkcairo.h>
#include <gdk/gdkcairocontext.h>
#include <gdk/gdkclipboard.h>
#include <gdk/gdkcolor.h>
#include <gdk/gdkcolorstate.h>
#include <gdk/gdkconfig.h>
#include <gdk/gdkcontentdeserializer.h>
#include <gdk/gdkcontentformats.h>

View File

@@ -20,7 +20,11 @@
#include "gdkcairo.h"
#include "gdkrgba.h"
#include "gdkcolor.h"
#include "gdktexture.h"
#include "gdkcolorstate.h"
#include "gdkcolorprivate.h"
#include "gdkmemoryformatprivate.h"
#include <math.h>
@@ -35,14 +39,47 @@ void
gdk_cairo_set_source_rgba (cairo_t *cr,
const GdkRGBA *rgba)
{
GdkColor color;
const float *components;
g_return_if_fail (cr != NULL);
g_return_if_fail (rgba != NULL);
gdk_color_convert_rgba (&color, gdk_cairo_get_color_state (cr), rgba);
components = gdk_color_get_components (&color);
cairo_set_source_rgba (cr,
rgba->red,
rgba->green,
rgba->blue,
rgba->alpha);
components[0],
components[1],
components[2],
components[3]);
}
/**
* gdk_cairo_set_source_color:
* @cr: a cairo contet
* @rgba: a `GdkColor`
*
* Sets the specified `GdkColor` as the source color of @cr.
*
* Since: 4.16
*/
void
gdk_cairo_set_source_color (cairo_t *cr,
const GdkColor *color)
{
GdkColor c;
const float *components;
g_return_if_fail (cr != NULL);
g_return_if_fail (color != NULL);
gdk_color_convert (&c, gdk_cairo_get_color_state (cr), color);
components = gdk_color_get_components (&c);
cairo_set_source_rgba (cr,
components[0],
components[1],
components[2],
components[3]);
}
/**
@@ -303,3 +340,98 @@ gdk_cairo_region_create_from_surface (cairo_surface_t *surface)
return region;
}
static cairo_user_data_key_t color_state_key;
/**
* gdk_cairo_surface_set_color_state:
* @surface: a surface
* @color_state: the color state to attach to the surface
*
* Attaches a `GdkColorState` to the Cairo surface.
*
* This is just auxiliary data for use by GTK, no Cairo functions
* do interact with this information.
*
* Note that all Cairo compositing operations are assumed to happen
* in a linear RGB color state, so if you want to use the surface
* as a target for rendering in a color managed way, you should use
* such a color state.
*
* The default color state is assumed to be sRGB, which is not
* linear.
*
* Since: 4.16
*/
void
gdk_cairo_surface_set_color_state (cairo_surface_t *surface,
GdkColorState *color_state)
{
g_return_if_fail (surface != NULL);
g_return_if_fail (color_state != NULL);
cairo_surface_set_user_data (surface,
&color_state_key,
gdk_color_state_ref (color_state),
(cairo_destroy_func_t) gdk_color_state_unref);
}
/**
* gdk_cairo_surface_get_color_state:
* @surface: a surface
*
* Gets the color state GTK assumes for the surface.
*
* See [method@Gdk.CairoSurface.set_color_state] for details.
*
* Returns: (transfer none): the color state
*
* Since: 4.16
*/
GdkColorState *
gdk_cairo_surface_get_color_state (cairo_surface_t *surface)
{
GdkColorState *color_state;
g_return_val_if_fail (surface != NULL, gdk_color_state_get_srgb ());
color_state = cairo_surface_get_user_data (surface, &color_state_key);
if (color_state == NULL)
color_state = gdk_color_state_get_srgb ();
return color_state;
}
/**
* gdk_cairo_get_color_state:
* @cr: a cairo context
*
* Gets the color state GTK assumes for the cairo context.
*
* Returns: (transfer none): the color state
*
* Since: 4.16
*/
GdkColorState *
gdk_cairo_get_color_state (cairo_t *cr)
{
GdkColorState *color_state;
cairo_surface_t *surface;
g_return_val_if_fail (cr != NULL, gdk_color_state_get_srgb ());
surface = cairo_get_group_target (cr);
color_state = cairo_surface_get_user_data (surface, &color_state_key);
if (color_state != NULL)
return color_state;
/* theoretically, we should walk the whole group stack, but I don't
* think Cairo lets us do that
*/
surface = cairo_get_target (cr);
color_state = cairo_surface_get_user_data (surface, &color_state_key);
if (color_state != NULL)
return color_state;
return gdk_color_state_get_srgb ();
}

View File

@@ -30,6 +30,11 @@ G_BEGIN_DECLS
GDK_AVAILABLE_IN_ALL
void gdk_cairo_set_source_rgba (cairo_t *cr,
const GdkRGBA *rgba);
GDK_AVAILABLE_IN_4_16
void gdk_cairo_set_source_color (cairo_t *cr,
const GdkColor *color);
GDK_AVAILABLE_IN_ALL
void gdk_cairo_set_source_pixbuf (cairo_t *cr,
const GdkPixbuf *pixbuf,
@@ -44,9 +49,15 @@ void gdk_cairo_region (cairo_t *cr,
const cairo_region_t *region);
GDK_AVAILABLE_IN_ALL
cairo_region_t *
gdk_cairo_region_create_from_surface
(cairo_surface_t *surface);
cairo_region_t * gdk_cairo_region_create_from_surface (cairo_surface_t *surface);
GDK_AVAILABLE_IN_4_16
void gdk_cairo_surface_set_color_state (cairo_surface_t *surface,
GdkColorState *color_state);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_cairo_surface_get_color_state (cairo_surface_t *surface);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_cairo_get_color_state (cairo_t *cr);
GDK_DEPRECATED_IN_4_6_FOR(gdk_gl_texture_new)
void gdk_cairo_draw_from_gl (cairo_t *cr,

507
gdk/gdkcolor.c Normal file
View File

@@ -0,0 +1,507 @@
/* 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 "gdkcolorprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkrgbaprivate.h"
#include <lcms2.h>
/**
* GdkColor:
* @color_state: the color state to interpret the values in
* @values: the 3 coordinates that define the color, followed
* by the alpha value
*
* A `GdkColor` represents a color.
*
* The color state defines the meaning and range of the values.
* E.g., the srgb color state has r, g, b components representing
* red, green and blue with a range of [0,1], while the oklch color
* state has l, c, h components representing luminosity, chromaticity
* and hue, with l ranging from 0 to 1 and c from 0 to about 0.4, while
* h is interpreted as angle in degrees.
*
* value[3] is always the alpha value with a range of [0,1].
*
* Note that `GdkColor` is mainly intended for on-stack use, and does
* not take a reference to the @color_state, unless you use gdk_color_copy().
*/
/* {{{ Boxed type */
G_DEFINE_BOXED_TYPE (GdkColor, gdk_color,
gdk_color_copy, gdk_color_free)
/**
* gdk_color_copy:
* @self: a `GdkColor`
*
* Makes a copy of a `GdkColor`.
*
* The result must be freed through [method@Gdk.Color.free].
*
* Returns: A newly allocated `GdkColor`, with the same contents as @self
*
* Since: 4.16
*/
GdkColor *
gdk_color_copy (const GdkColor *self)
{
GdkColor *copy = g_new0 (GdkColor, 1);
g_set_object (&copy->color_state, self->color_state);
memcpy (copy->values, self->values, sizeof (float) * 4);
return copy;
}
/**
* gdk_color_free:
* @self: a `GdkColor`
*
* Frees a `Gdkcolor`.
*
* Since: 4.16
*/
void
gdk_color_free (GdkColor *self)
{
g_clear_pointer (&self->color_state, gdk_color_state_unref);
g_free (self);
}
/* }}} */
/* {{{ Public API */
void
(gdk_color_init) (GdkColor *self,
GdkColorState *color_state,
const float components[4])
{
_gdk_color_init (self, color_state, components);
}
void
(gdk_color_init_from_rgba) (GdkColor *self,
const GdkRGBA *rgba)
{
_gdk_color_init_from_rgba (self, rgba);
}
GdkColorState *
(gdk_color_get_color_state) (const GdkColor *self)
{
return _gdk_color_get_color_state (self);
}
const float *
(gdk_color_get_components) (const GdkColor *self)
{
return _gdk_color_get_components (self);
}
gboolean
(gdk_color_equal) (const GdkColor *self,
const GdkColor *other)
{
return _gdk_color_equal (self, other);
}
gboolean
(gdk_color_is_black) (const GdkColor *self)
{
return _gdk_color_is_black (self);
}
gboolean
(gdk_color_is_clear) (const GdkColor *self)
{
return _gdk_color_is_clear (self);
}
gboolean
(gdk_color_is_opaque) (const GdkColor *self)
{
return _gdk_color_is_opaque (self);
}
/* }}} */
/**
* gdk_color_convert:
* @self: the `GdkColor` to store the result in
* @color_state: the target color start
* @other: the `GdkColor` to convert
*
* Converts a given `GdkColor` to another color state.
*
* After the conversion, @self will represent the same
* color as @other in @color_state, to the degree possible.
*
* Different color states have different gamuts of colors
* they can represent, and converting a color to a color
* state with a smaller gamut may yield an 'out of gamut'
* result.
*
* Since: 4.16
*/
void
(gdk_color_convert) (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other)
{
GdkColorStateTransform tf;
self->color_state = color_state;
gdk_color_state_transform_init (&tf, other->color_state, color_state, TRUE);
gdk_color_state_transform (&tf, other->values, self->values, 1);
gdk_color_state_transform_finish (&tf);
}
/**
* gdk_color_convert_rgba:
* @self: the `GdkColor` to store the result in
* @color_state: the target color state
* @rgba: the `GdkRGBA` to convert
*
* Converts a given `GdkRGBA` to the target @color_state.
*
* Since: 4.16
*/
void
gdk_color_convert_rgba (GdkColor *self,
GdkColorState *color_state,
const GdkRGBA *rgba)
{
GdkColor tmp = { (GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_SRGB),
{ rgba->red, rgba->green, rgba->blue, rgba->alpha } };
gdk_color_convert (self, color_state, &tmp);
}
/**
* gdk_color_mix:
* @self: the `GdkColor` to store the result in
* @color_start: the target color state
* @src1: the first color
* @src2: the second color
* @progress: the relative amount of @src2, from 0 to 1
*
* Mix two colors.
*
* This operation first converts @src1 and @src2 to the
* target @color_state, and then interpolates between them
* with a position given by @progress.
*
* Since: 4.16
*/
void
gdk_color_mix (GdkColor *self,
GdkColorState *color_state,
const GdkColor *src1,
const GdkColor *src2,
double progress)
{
if (src1->color_state != color_state)
{
GdkColor tmp;
gdk_color_convert (&tmp, color_state, src1);
gdk_color_mix (self, color_state, &tmp, src2, progress);
}
else if (src2->color_state != color_state)
{
GdkColor tmp;
gdk_color_convert (&tmp, color_state, src2);
gdk_color_mix (self, color_state, src1, &tmp, progress);
}
else
{
gsize i;
const float *s1, *s2;
float *d;
self->color_state = color_state;
self->values[3] = src1->values[3] * (1.0 - progress) + src2->values[3] * progress;
d = (float *) gdk_color_get_components (self);
s1 = gdk_color_get_components (src1);
s2 = gdk_color_get_components (src2);
if (self->values[3] == 0)
{
for (i = 0; i < 3; i++)
d[i] = s1[i] * (1.0 - progress) + s2[i] * progress;
}
else
{
for (i = 0; i < 3; i++)
d[i] = (s1[i] * src1->values[3] * (1.0 - progress) + s2[i] * src2->values[3] * progress) / self->values[3];
}
}
}
/*< private >
* gdk_color_parser_parse:
* @parser: the parser
* @color: location to store the parsed color
*
* Parses a string representation of colors that
* is inspired by CSS.
*
* Returns: `TRUE` if parsing succeeded
*
* Since: 4.16
*/
gboolean
gdk_color_parser_parse (GtkCssParser *parser,
GdkColor *color)
{
const GtkCssToken *token;
GdkRGBA rgba;
if (gtk_css_parser_has_function (parser, "color"))
{
GdkColorState *color_state;
float values[4];
const char *coords;
gtk_css_parser_start_block (parser);
if (gtk_css_parser_try_ident (parser, "srgb"))
{
coords = "rgb";
color_state = gdk_color_state_get_srgb ();
}
else if (gtk_css_parser_try_ident (parser, "srgb-linear"))
{
coords = "rgb";
color_state = gdk_color_state_get_srgb_linear ();
}
else if (gtk_css_parser_try_ident (parser, "oklab"))
{
coords = "lab";
color_state = gdk_color_state_get_oklab ();
}
else if (gtk_css_parser_try_ident (parser, "oklch"))
{
coords = "lch";
color_state = gdk_color_state_get_oklch ();
}
else
{
gtk_css_parser_error_syntax (parser, "Expected a valid color state");
gtk_css_parser_end_block (parser);
return FALSE;
}
for (int i = 0; i < 3; i++)
{
token = gtk_css_parser_get_token (parser);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE))
{
float v = token->number.number;
switch (coords[i])
{
case 'l':
values[i] = CLAMP (v / 100.0, 0, 1);
break;
case 'a':
case 'b':
values[i] = v * 0.4 / 100.0;
break;
case 'c':
values[i] = MAX (0, v * 0.4 / 100.0);
break;
case 'h':
gtk_css_parser_error_syntax (parser, "Can't use percentage for hue");
gtk_css_parser_end_block (parser);
return FALSE;
default:
values[i] = CLAMP (v / 100.0, 0, 1);
break;
}
gtk_css_parser_consume_token (parser);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_NUMBER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_NUMBER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
float v = token->number.number;
switch (coords[i])
{
case 'l':
values[i] = CLAMP (v, 0, 1);
break;
case 'a':
case 'b':
case 'h':
values[i] = v;
break;
case 'c':
values[i] = MAX (0, v);
break;
default:
values[i] = CLAMP (v, 0, 1);
break;
}
gtk_css_parser_consume_token (parser);
}
else
{
gtk_css_parser_error_syntax (parser, "Expected a number or percentage");
gtk_css_parser_end_block (parser);
return FALSE;
}
}
token = gtk_css_parser_get_token (parser);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
values[3] = 1;
}
else if (gtk_css_token_is_delim (token, '/'))
{
gtk_css_parser_consume_token (parser);
token = gtk_css_parser_get_token (parser);
if (gtk_css_token_is (token, GTK_CSS_TOKEN_PERCENTAGE))
{
values[3] = CLAMP (token->number.number / 100.0, 0, 1);
gtk_css_parser_consume_token (parser);
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_NUMBER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_NUMBER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNED_INTEGER) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_SIGNLESS_INTEGER))
{
values[3] = CLAMP (token->number.number, 0, 1);
gtk_css_parser_consume_token (parser);
}
else
{
gtk_css_parser_error_syntax (parser, "Expected a number or percentage");
gtk_css_parser_end_block (parser);
return FALSE;
}
token = gtk_css_parser_get_token (parser);
if (!gtk_css_token_is (token, GTK_CSS_TOKEN_EOF))
{
gtk_css_parser_error_syntax (parser, "Garbage at the end of the value");
gtk_css_parser_end_block (parser);
return FALSE;
}
gtk_css_parser_consume_token (parser);
}
else
{
gtk_css_parser_error_syntax (parser, "Expected '/'");
gtk_css_parser_end_block (parser);
return FALSE;
}
gtk_css_parser_end_block (parser);
gdk_color_init (color, color_state, values);
return TRUE;
}
else if (gdk_rgba_parser_parse (parser, &rgba))
{
gdk_color_init_from_rgba (color, &rgba);
return TRUE;
}
return FALSE;
}
/**
* gdk_color_print:
* @self: a `GdkColor`
* @string: the string to print on
*
* Appends a representation of @self to @string.
*
* The representation is inspired by CSS3 colors,
* but not 100% identical, and looks like this:
*
* color(NAME V1 V2 V3 / ALPHA)
*
* where `NAME` is the name of the color state,
* `V1`, `V2`, `V3` and `ALPHA` are the components
* of the color. Alpha may be omitted if it is 1.
*
* Since: 4.16
*/
void
gdk_color_print (const GdkColor *self,
GString *string)
{
char buffer[48];
g_string_append (string, "color(");
g_string_append (string, gdk_color_state_get_name (self->color_state));
g_string_append_c (string, ' ');
g_ascii_dtostr (buffer, sizeof (buffer), self->values[0]);
g_string_append (string, buffer);
g_string_append_c (string, ' ');
g_ascii_dtostr (buffer, sizeof (buffer), self->values[1]);
g_string_append (string, buffer);
g_string_append_c (string, ' ');
g_ascii_dtostr (buffer, sizeof (buffer), self->values[2]);
g_string_append (string, buffer);
if (self->values[3] < 0.999)
{
g_string_append (string, " / ");
g_ascii_dtostr (buffer, sizeof (buffer), self->values[3]);
g_string_append (string, buffer);
}
g_string_append_c (string, ')');
}
/**
* gdk_color_to_string:
* @self: a `GdkColor`
*
* Returns a string representation @self.
*
* See [method@Gdk.Color.print] for details about
* the format.
*
* Returns: (transfer full): a newly allocated string
*
* Since: 4.16
*/
char *
gdk_color_to_string (const GdkColor *self)
{
GString *string = g_string_new ("");
gdk_color_print (self, string);
return g_string_free (string, FALSE);
}
/* vim:set foldmethod=marker expandtab: */

106
gdk/gdkcolor.h Normal file
View File

@@ -0,0 +1,106 @@
/* 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/>.
*/
#pragma once
#include <gdk/gdktypes.h>
#include <gdk/gdkcolorstate.h>
#include <gdk/gdkrgba.h>
/* The interpretation of the first 3 components depends on the color state.
* values[3] is always alpha.
*/
struct _GdkColor
{
GdkColorState *color_state;
float values[4];
};
G_STATIC_ASSERT (sizeof (GdkColor) % sizeof (gpointer) == 0);
#define GDK_TYPE_COLOR (gdk_color_get_type ())
G_BEGIN_DECLS
#define GDK_COLOR_INIT(cs, c1, c2, c3, c4) \
(GdkColor) { (cs), { (c1), (c2), (c3), (c4) } }
#define GDK_COLOR_INIT_SRGB(c1, c2, c3, c4) \
GDK_COLOR_INIT (GDK_COLOR_STATE_SRGB, (c1), (c2), (c3), (c4) )
#define GDK_COLOR_INIT_RGBA(r) \
GDK_COLOR_INIT_SRGB ((r)->red, (r)->green, (r)->blue, (r)->alpha)
GDK_AVAILABLE_IN_4_16
GType gdk_color_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_16
GdkColor * gdk_color_copy (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
void gdk_color_free (GdkColor *self);
GDK_AVAILABLE_IN_4_16
void gdk_color_init (GdkColor *self,
GdkColorState *color_state,
const float components[4]);
GDK_AVAILABLE_IN_4_16
void gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba);
GDK_AVAILABLE_IN_4_16
void gdk_color_convert (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other);
GDK_AVAILABLE_IN_4_16
void gdk_color_convert_rgba (GdkColor *self,
GdkColorState *color_state,
const GdkRGBA *rgba);
GDK_AVAILABLE_IN_4_16
void gdk_color_mix (GdkColor *self,
GdkColorState *color_state,
const GdkColor *src1,
const GdkColor *src2,
double progress);
GDK_AVAILABLE_IN_4_16
void gdk_color_print (const GdkColor *self,
GString *string);
GDK_AVAILABLE_IN_4_16
char * gdk_color_to_string (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_get_color_state (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
const float * gdk_color_get_components (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_equal (const GdkColor *color1,
const GdkColor *color2);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_is_black (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_is_clear (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_is_opaque (const GdkColor *self);
#include "gdkcolorimpl.h"
G_END_DECLS

122
gdk/gdkcolorimpl.h Normal file
View File

@@ -0,0 +1,122 @@
/* 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/>.
*/
#pragma once
#define gdk_color_init(self, cs, comp) _gdk_color_init ((self), (cs), (comp))
static inline void
_gdk_color_init (GdkColor *self,
GdkColorState *color_state,
const float components[4])
{
self->color_state = color_state;
self->values[0] = components[0];
self->values[1] = components[1];
self->values[2] = components[2];
self->values[3] = components[3];
}
#define gdk_color_init_from_rgb(self, rgba) _gdk_color_init_from_rgba (self, rgba)
static inline void
_gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba)
{
self->color_state = GDK_COLOR_STATE_SRGB;
self->values[0] = rgba->red;
self->values[1] = rgba->green;
self->values[2] = rgba->blue;
self->values[3] = rgba->alpha;
}
#define gdk_color_get_color_state(self) _gdk_color_get_color_state (self)
static inline GdkColorState *
_gdk_color_get_color_state (const GdkColor *self)
{
return self->color_state;
}
#define gdk_color_get_components(self) _gdk_color_get_components (self)
static inline const float *
_gdk_color_get_components (const GdkColor *self)
{
return self->values;
}
#define gdk_color_equal(self, other) _gdk_color_equal (self, other)
static inline gboolean
_gdk_color_equal (const GdkColor *self,
const GdkColor *other)
{
return self->values[0] == other->values[0] &&
self->values[1] == other->values[1] &&
self->values[2] == other->values[2] &&
self->values[3] == other->values[3] &&
gdk_color_state_equal (self->color_state, other->color_state);
}
static inline gboolean
all_zero (const GdkColor *c)
{
return c->values[0] == 0 && c->values[1] == 0 && c->values[2] == 0;
}
#define gdk_color_is_black(self) _gdk_color_is_black (self)
static inline gboolean
_gdk_color_is_black (const GdkColor *self)
{
if (gdk_color_state_equal (self->color_state, GDK_COLOR_STATE_SRGB))
return all_zero (self);
else
{
GdkColor c;
gboolean res;
gdk_color_convert (&c, GDK_COLOR_STATE_SRGB, self);
res = all_zero (&c);
return res;
}
}
#define gdk_color_is_clear(self) _gdk_color_is_clear (self)
static inline gboolean
_gdk_color_is_clear (const GdkColor *self)
{
return self->values[3] < ((float) 0x00ff / (float) 0xffff);
}
#define gdk_color_is_opaque(self) _gdk_color_is_opaque (self)
static inline gboolean
_gdk_color_is_opaque (const GdkColor *self)
{
return self->values[3] > ((float)0xff00 / (float)0xffff);
}
#define gdk_color_convert(self, cs, other) _gdk_color_convert (self, cs, other)
static inline void
_gdk_color_convert (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other)
{
if (gdk_color_state_equal (color_state, other->color_state))
{
gdk_color_init (self, color_state, other->values);
return;
}
(gdk_color_convert) (self, color_state, other);
}

27
gdk/gdkcolorprivate.h Normal file
View File

@@ -0,0 +1,27 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2024, Red Hat, Inc
*
* 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/>.
*/
#pragma once
#include "gdkcolor.h"
#include "gtk/css/gtkcssparserprivate.h"
gboolean gdk_color_parser_parse (GtkCssParser *parser,
GdkColor *color);

950
gdk/gdkcolorstate.c Normal file
View File

@@ -0,0 +1,950 @@
/* 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 <glib/gi18n-lib.h>
#include "gtk/gtkcolorutilsprivate.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
*/
static GdkColorStateClass * get_class (GdkColorState *self);
G_DEFINE_BOXED_TYPE (GdkColorState, gdk_color_state,
gdk_color_state_ref, gdk_color_state_unref);
/* {{{ Public API */
GdkColorState *
(gdk_color_state_ref) (GdkColorState *self)
{
return _gdk_color_state_ref (self);
}
void
(gdk_color_state_unref) (GdkColorState *self)
{
_gdk_color_state_unref (self);
}
GdkColorState *
(gdk_color_state_get_srgb) (void)
{
return _gdk_color_state_get_srgb ();
}
GdkColorState *
(gdk_color_state_get_srgb_linear) (void)
{
return _gdk_color_state_get_srgb_linear ();
}
GdkColorState *
(gdk_color_state_get_hsl) (void)
{
return _gdk_color_state_get_hsl ();
}
GdkColorState *
(gdk_color_state_get_hwb) (void)
{
return _gdk_color_state_get_hwb ();
}
GdkColorState *
(gdk_color_state_get_oklab) (void)
{
return _gdk_color_state_get_oklab ();
}
GdkColorState *
(gdk_color_state_get_oklch) (void)
{
return _gdk_color_state_get_oklch ();
}
GdkColorState *
(gdk_color_state_get_display_p3) (void)
{
return _gdk_color_state_get_display_p3 ();
}
GdkColorState *
(gdk_color_state_get_xyz) (void)
{
return _gdk_color_state_get_xyz ();
}
GdkColorState *
(gdk_color_state_get_rec2020) (void)
{
return _gdk_color_state_get_rec2020 ();
}
GdkColorState *
(gdk_color_state_get_rec2100_pq) (void)
{
return _gdk_color_state_get_rec2100_pq ();
}
GdkColorState *
(gdk_color_state_get_rec2100_linear) (void)
{
return _gdk_color_state_get_rec2100_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);
}
/**
* gdk_color_state_is_linear:
* @self: a `GdkColorState`
*
* Returns whether the color state is linear.
*
* Returns: `TRUE` if the color state is linear
* Since: 4.16
*/
gboolean
gdk_color_state_is_linear (GdkColorState *self)
{
return get_class (self)->is_linear (self);
}
/**
* gdk_color_state_save_to_icc_profile:
* @self: a `GdkColorState`
* @error: Return location for an error
*
* Saves the color state to an
* [ICC profile](https://en.wikipedia.org/wiki/ICC_profile).
*
* Some color states cannot be represented as ICC profiles.
* In that case, @error will be set and %NULL will be returned.
*
* Returns: (nullable): A new `GBytes` containing the ICC profile
*
* Since: 4.16
*/
GBytes *
gdk_color_state_save_to_icc_profile (GdkColorState *self,
GError **error)
{
return get_class (self)->save_to_icc_profile (self, error);
}
/**
* gdk_color_state_save_to_cicp_data:
* @self: a `GdkColorState`
* @color_primaries: return location for color primaries
* @transfer_characteristics: return location for transfer characteristics
* @matrix_coefficients: return location for matrix_coefficients
* @full_range: return location for the full range flag
* @error: Return location for an error
*
* Saves the color state as
* [CICP](https://en.wikipedia.org/wiki/Coding-independent_code_points)
* data.
*
* Some color states cannot be represented as CICP data.
* In that case, @error will be set and `FALSE` will be returned.
*
* Returns: (nullable): `TRUE` if the out arguments were set
*
* Since: 4.16
*/
gboolean
gdk_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error)
{
return get_class (self)->save_to_cicp_data (self,
color_primaries,
transfer_characteristics,
matrix_coefficients,
full_range,
error);
}
/* }}} */
/* {{{ ICC implementation */
#define GDK_LCMS_COLOR_STATE(c) ((GdkLcmsColorState *)(c))
typedef struct {
GdkColorState state;
cmsHPROFILE lcms_profile;
} GdkLcmsColorState;
/* {{{ Helpers */
static cmsHPROFILE
gdk_lcms_color_state_get_lcms_profile (GdkColorState *self)
{
g_return_val_if_fail (GDK_IS_LCMS_COLOR_STATE (self), NULL);
return GDK_LCMS_COLOR_STATE (self)->lcms_profile;
}
static cmsHPROFILE
gdk_lcms_get_srgb_profile (void)
{
return cmsCreate_sRGBProfile ();
}
static cmsHPROFILE
gdk_lcms_get_srgb_linear_profile (void)
{
cmsToneCurve *curve;
cmsHPROFILE profile;
curve = cmsBuildGamma (NULL, 1.0);
profile = cmsCreateRGBProfile (&(cmsCIExyY) {
0.3127, 0.3290, 1.0
},
&(cmsCIExyYTRIPLE) {
{ 0.6400, 0.3300, 1.0 },
{ 0.3000, 0.6000, 1.0 },
{ 0.1500, 0.0600, 1.0 }
},
(cmsToneCurve*[3]) { curve, curve, curve });
cmsFreeToneCurve (curve);
return profile;
}
static GBytes *
gdk_lcms_save_profile (cmsHPROFILE profile,
GError **error)
{
cmsUInt32Number size;
guchar *data;
size = 0;
if (!cmsSaveProfileToMem (profile, NULL, &size))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Could not prepare ICC profile"));
return NULL;
}
data = g_malloc (size);
if (!cmsSaveProfileToMem (profile, data, &size))
{
g_free (data);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to save ICC profile"));
return NULL;
}
return g_bytes_new_take (data, size);
}
/* }}} */
/* {{{ GdkColorState vfuncs */
static void
gdk_lcms_color_state_free (GdkColorState *state)
{
GdkLcmsColorState *self = (GdkLcmsColorState *) state;
cmsCloseProfile (self->lcms_profile);
g_free (self);
}
static gboolean
gdk_lcms_color_state_equal (GdkColorState *state1,
GdkColorState *state2)
{
GBytes *icc1, *icc2;
gboolean res;
icc1 = gdk_color_state_save_to_icc_profile (state1, NULL);
icc2 = gdk_color_state_save_to_icc_profile (state2, NULL);
res = g_bytes_equal (icc1, icc2);
g_bytes_unref (icc1);
g_bytes_unref (icc2);
return res;
}
static gboolean
gdk_lcms_color_state_is_linear (GdkColorState *state)
{
return FALSE; /* FIXME */
}
static GBytes *
gdk_lcms_color_state_save_to_icc_profile (GdkColorState *state,
GError **error)
{
GdkLcmsColorState *self = GDK_LCMS_COLOR_STATE (state);
return gdk_lcms_save_profile (self->lcms_profile, error);
}
static gboolean
gdk_lcms_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("This color state does not support CICP data"));
return FALSE;
}
static const char *
gdk_lcms_color_state_get_name (GdkColorState *self)
{
static char buffer[48];
g_snprintf (buffer, sizeof (buffer), "lcms color state %p", self);
return buffer;
}
static guint
gdk_lcms_color_state_get_min_depth (GdkColorState *self)
{
return GDK_MEMORY_U16; /* ? */
}
static int
gdk_lcms_color_state_get_hue_coord (GdkColorState *self)
{
return -1;
}
static GdkColorStateClass LCMS_COLOR_STATE_CLASS =
{
GDK_TYPE_LCMS_COLOR_STATE,
gdk_lcms_color_state_free,
gdk_lcms_color_state_equal,
gdk_lcms_color_state_is_linear,
gdk_lcms_color_state_save_to_icc_profile,
gdk_lcms_color_state_save_to_cicp_data,
gdk_lcms_color_state_get_name,
gdk_lcms_color_state_get_min_depth,
gdk_lcms_color_state_get_hue_coord,
};
/* }}} */
/* {{{ Private API */
GdkColorState *
gdk_color_state_new_from_lcms_profile (cmsHPROFILE lcms_profile)
{
GdkLcmsColorState *self;
self= g_new0 (GdkLcmsColorState, 1);
self->state.klass = &LCMS_COLOR_STATE_CLASS;
self->state.ref_count = 1;
self->lcms_profile = lcms_profile;
return (GdkColorState *) self;
}
/* }}} */
/* {{{ Public API */
/**
* gdk_color_state_new_from_icc_profile:
* @icc_profile: The ICC profiles given as a `GBytes`
* @error: Return location for an error
*
* Creates a new color state for the given ICC profile data.
*
* if the profile is not valid, %NULL is returned and an error
* is raised.
*
* Returns: a new `GdkColorState` or %NULL on error
*
* Since: 4.16
*/
GdkColorState *
gdk_color_state_new_from_icc_profile (GBytes *icc_profile,
GError **error)
{
cmsHPROFILE lcms_profile;
const guchar *data;
gsize size;
g_return_val_if_fail (icc_profile != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
data = g_bytes_get_data (icc_profile, &size);
lcms_profile = cmsOpenProfileFromMem (data, size);
if (lcms_profile == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to load ICC profile"));
return NULL;
}
return gdk_color_state_new_from_lcms_profile (lcms_profile);
}
/* }}} */
/* }}} */
/* {{{ Named implementation */
static gboolean
gdk_named_color_state_is_linear (GdkColorState *self)
{
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return TRUE;
case GDK_COLOR_STATE_ID_SRGB:
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
return FALSE;
default:
g_assert_not_reached ();
}
}
static GBytes *
gdk_named_color_state_save_to_icc_profile (GdkColorState *self,
GError **error)
{
cmsHPROFILE profile;
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_SRGB:
profile = gdk_lcms_get_srgb_profile ();
break;
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
profile = gdk_lcms_get_srgb_linear_profile ();
break;
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
profile = NULL;
break;
default:
g_assert_not_reached ();
}
if (profile)
{
GBytes *bytes;
bytes = gdk_lcms_save_profile (profile, error);
cmsCloseProfile (profile);
return bytes;
}
else
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
_("ICC profile not supported for this color state"));
return NULL;
}
}
static gboolean
gdk_named_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error)
{
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_SRGB:
*color_primaries = 0;
*transfer_characteristics = 13;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
*color_primaries = 0;
*transfer_characteristics = 8;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_REC2100_PQ:
*color_primaries = 9;
*transfer_characteristics = 16;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
*color_primaries = 9;
*transfer_characteristics = 8;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_DISPLAY_P3:
*color_primaries = 12;
*transfer_characteristics = 13;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
break;
default:
g_assert_not_reached ();
}
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("This color state does not support CICP data"));
return FALSE;
}
const char *
gdk_color_state_get_name_from_id (GdkColorStateId id)
{
const char *names[] = {
"srgb", "srgb-linear", "hsl", "hwb",
"oklab", "oklch", "display-p3", "xyz",
"rec2020", "rec2100-pq", "rec2100-linear",
};
return names[(id - 1) >> 1];
}
static const char *
gdk_named_color_state_get_name (GdkColorState *self)
{
return gdk_color_state_get_name_from_id (GDK_NAMED_COLOR_STATE_ID (self));
}
static guint
gdk_named_color_state_get_min_depth (GdkColorState *self)
{
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
return GDK_MEMORY_FLOAT16;
case GDK_COLOR_STATE_ID_SRGB:
return GDK_MEMORY_U8;
default:
g_assert_not_reached ();
}
}
static int
gdk_named_color_state_get_hue_coord (GdkColorState *in)
{
switch (GDK_NAMED_COLOR_STATE_ID (in))
{
case GDK_COLOR_STATE_ID_SRGB:
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return -1;
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
return 0;
case GDK_COLOR_STATE_ID_OKLCH:
return 2;
default:
g_assert_not_reached ();
}
}
static GdkColorStateClass NAMED_COLOR_STATE_CLASS =
{
GDK_TYPE_NAMED_COLOR_STATE,
NULL,
NULL,
gdk_named_color_state_is_linear,
gdk_named_color_state_save_to_icc_profile,
gdk_named_color_state_save_to_cicp_data,
gdk_named_color_state_get_name,
gdk_named_color_state_get_min_depth,
gdk_named_color_state_get_hue_coord,
};
/* }}} */
/* {{{ CICP support */
GdkColorState *
gdk_color_state_new_from_cicp_data (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range)
{
/* FIXME We don't support these */
if (!full_range || matrix_coefficients != 0)
return NULL;
/* Look for cases we can handle */
if (color_primaries == 0 && transfer_characteristics == 13)
return gdk_color_state_get_srgb ();
else if (color_primaries == 0 && transfer_characteristics == 8)
return gdk_color_state_get_srgb_linear ();
else if (color_primaries == 9 && transfer_characteristics == 16)
return gdk_color_state_get_rec2100_pq ();
else if (color_primaries == 9 && transfer_characteristics == 8)
return gdk_color_state_get_rec2100_linear ();
else if (color_primaries == 12 && transfer_characteristics == 13)
return gdk_color_state_get_display_p3 ();
return NULL;
}
/* }}} */
/* {{{ Private API */
static GdkColorStateClass *
get_class (GdkColorState *self)
{
if (GDK_IS_NAMED_COLOR_STATE (self))
return &NAMED_COLOR_STATE_CLASS;
return self->klass;
}
GdkMemoryDepth
gdk_color_state_get_min_depth (GdkColorState *self)
{
return (GdkMemoryDepth) get_class (self)->get_min_depth (self);
}
const char *
gdk_color_state_get_name (GdkColorState *self)
{
return get_class (self)->get_name (self);
}
int
gdk_color_state_get_hue_coord (GdkColorState *self)
{
return get_class (self)->get_hue_coord (self);
}
/* }}} */
/* {{{ Conversion */
#define two_step(name, func1, func2) \
static void \
name (float r, float g, float b, \
float *x, float *y, float *z) \
{ \
func1 (r, g, b, x, y, z); \
func2 (*x, *y, *z, x, y, z); \
}
/* A full complement of xyz <> anything step functions */
two_step (srgb_to_xyz, gtk_rgb_to_linear_srgb, gtk_linear_srgb_to_xyz)
two_step (xyz_to_srgb, gtk_xyz_to_linear_srgb, gtk_linear_srgb_to_rgb)
two_step (hsl_to_xyz, gtk_hsl_to_rgb, srgb_to_xyz)
two_step (xyz_to_hsl, xyz_to_srgb, gtk_rgb_to_hsl)
two_step (hwb_to_xyz, gtk_hwb_to_rgb, srgb_to_xyz)
two_step (xyz_to_hwb, xyz_to_srgb, gtk_rgb_to_hwb)
two_step (oklab_to_xyz, gtk_oklab_to_linear_srgb, gtk_linear_srgb_to_xyz)
two_step (xyz_to_oklab, gtk_xyz_to_linear_srgb, gtk_linear_srgb_to_oklab)
two_step (oklch_to_xyz, gtk_oklch_to_oklab, oklab_to_xyz)
two_step (xyz_to_oklch, xyz_to_oklab, gtk_oklab_to_oklch)
two_step (p3_to_xyz, gtk_p3_to_rgb, srgb_to_xyz)
two_step (xyz_to_p3, xyz_to_srgb, gtk_rgb_to_p3)
two_step (rec2100_linear_to_xyz, gtk_rec2100_linear_to_rec2020_linear, gtk_rec2020_linear_to_xyz)
two_step (xyz_to_rec2100_linear, gtk_xyz_to_rec2020_linear, gtk_rec2020_linear_to_rec2100_linear)
two_step (rec2100_pq_to_xyz, gtk_rec2100_pq_to_rec2100_linear, rec2100_linear_to_xyz)
two_step (xyz_to_rec2100_pq, xyz_to_rec2100_linear, gtk_rec2100_linear_to_rec2100_pq)
static struct {
GdkColorStateId n1;
GdkColorStateId n2;
StepFunc func;
} functions[] = {
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_SRGB_LINEAR, gtk_rgb_to_linear_srgb },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_HSL, gtk_rgb_to_hsl },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_HWB, gtk_rgb_to_hwb },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_OKLAB, gtk_rgb_to_oklab },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_DISPLAY_P3, gtk_rgb_to_p3 },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_XYZ, srgb_to_xyz },
{ GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_SRGB, gtk_linear_srgb_to_rgb },
{ GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_OKLAB, gtk_linear_srgb_to_oklab },
{ GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_XYZ, gtk_linear_srgb_to_xyz },
{ GDK_COLOR_STATE_ID_HSL, GDK_COLOR_STATE_ID_SRGB, gtk_hsl_to_rgb },
{ GDK_COLOR_STATE_ID_HSL, GDK_COLOR_STATE_ID_XYZ, hsl_to_xyz },
{ GDK_COLOR_STATE_ID_HWB, GDK_COLOR_STATE_ID_SRGB, gtk_hwb_to_rgb },
{ GDK_COLOR_STATE_ID_HWB, GDK_COLOR_STATE_ID_XYZ, hwb_to_xyz },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_SRGB, gtk_oklab_to_rgb },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_SRGB_LINEAR, gtk_oklab_to_linear_srgb },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_OKLCH, gtk_oklab_to_oklch },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_XYZ, oklab_to_xyz },
{ GDK_COLOR_STATE_ID_OKLCH, GDK_COLOR_STATE_ID_OKLAB, gtk_oklch_to_oklab },
{ GDK_COLOR_STATE_ID_OKLCH, GDK_COLOR_STATE_ID_XYZ, oklch_to_xyz },
{ GDK_COLOR_STATE_ID_DISPLAY_P3, GDK_COLOR_STATE_ID_SRGB, gtk_p3_to_rgb },
{ GDK_COLOR_STATE_ID_DISPLAY_P3, GDK_COLOR_STATE_ID_XYZ, p3_to_xyz },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_SRGB, xyz_to_srgb },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_SRGB_LINEAR, gtk_xyz_to_linear_srgb },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_HSL, xyz_to_hsl },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_HWB, xyz_to_hwb },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_OKLAB, xyz_to_oklab },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_OKLCH, xyz_to_oklch },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_DISPLAY_P3, xyz_to_p3 },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2020, gtk_xyz_to_rec2020 },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2100_PQ, xyz_to_rec2100_pq },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2100_LINEAR, xyz_to_rec2100_linear },
{ GDK_COLOR_STATE_ID_REC2020, GDK_COLOR_STATE_ID_XYZ, gtk_rec2020_to_xyz },
{ GDK_COLOR_STATE_ID_REC2100_PQ, GDK_COLOR_STATE_ID_XYZ, rec2100_pq_to_xyz },
{ GDK_COLOR_STATE_ID_REC2100_PQ, GDK_COLOR_STATE_ID_REC2100_LINEAR, gtk_rec2100_pq_to_rec2100_linear },
{ GDK_COLOR_STATE_ID_REC2100_LINEAR, GDK_COLOR_STATE_ID_REC2100_PQ, gtk_rec2100_linear_to_rec2100_pq },
{ GDK_COLOR_STATE_ID_REC2100_LINEAR, GDK_COLOR_STATE_ID_XYZ, rec2100_linear_to_xyz },
};
static StepFunc
find_function (GdkColorStateId n1, GdkColorStateId n2)
{
for (int k = 0; k < G_N_ELEMENTS (functions); k++)
{
if (functions[k].n1 == n1 && functions[k].n2 == n2)
return functions[k].func;
}
return NULL;
}
void
gdk_color_state_transform_init (GdkColorStateTransform *tf,
GdkColorState *from,
GdkColorState *to,
gboolean copy_alpha)
{
memset (tf, 0, sizeof (GdkColorStateTransform));
if (GDK_IS_NAMED_COLOR_STATE (from) &&
GDK_IS_NAMED_COLOR_STATE (to))
{
tf->step1 = find_function (GDK_NAMED_COLOR_STATE_ID (from),
GDK_NAMED_COLOR_STATE_ID (to));
if (tf->step1 == NULL && from != to)
{
tf->step1 = find_function (GDK_NAMED_COLOR_STATE_ID (from),
GDK_COLOR_STATE_ID_XYZ);
tf->step2 = find_function (GDK_COLOR_STATE_ID_XYZ,
GDK_NAMED_COLOR_STATE_ID (to));
}
}
else
{
cmsHPROFILE profile1, profile2;
if (GDK_IS_LCMS_COLOR_STATE (from))
profile1 = gdk_lcms_color_state_get_lcms_profile (from);
else
profile1 = NULL;
if (GDK_IS_LCMS_COLOR_STATE (to))
profile2 = gdk_lcms_color_state_get_lcms_profile (to);
else
profile2 = NULL;
if (profile1 && profile2)
{
tf->transform = cmsCreateTransform (profile1,
TYPE_RGBA_FLT,
profile2,
TYPE_RGBA_FLT,
INTENT_PERCEPTUAL,
copy_alpha ? cmsFLAGS_COPY_ALPHA : 0);
}
else if (GDK_IS_NAMED_COLOR_STATE (from) && profile2)
{
tf->step1 = find_function (GDK_NAMED_COLOR_STATE_ID (from),
GDK_COLOR_STATE_ID_XYZ);
profile1 = cmsCreateXYZProfile ();
tf->transform = cmsCreateTransform (profile1,
TYPE_RGBA_FLT,
profile2,
TYPE_RGBA_FLT,
INTENT_PERCEPTUAL,
copy_alpha ? cmsFLAGS_COPY_ALPHA : 0);
tf->cms_first = FALSE;
}
else if (profile1 && GDK_IS_NAMED_COLOR_STATE (to))
{
profile2 = cmsCreateXYZProfile ();
tf->transform = cmsCreateTransform (profile1,
TYPE_RGBA_FLT,
profile2,
TYPE_RGBA_FLT,
INTENT_PERCEPTUAL,
copy_alpha ? cmsFLAGS_COPY_ALPHA : 0);
tf->step1 = find_function (GDK_COLOR_STATE_ID_XYZ,
GDK_NAMED_COLOR_STATE_ID (to));
tf->cms_first = TRUE;
}
else
g_assert_not_reached ();
g_clear_pointer (&profile1, cmsCloseProfile);
g_clear_pointer (&profile2, cmsCloseProfile);
}
tf->copy_alpha = copy_alpha;
}
void
gdk_color_state_transform_finish (GdkColorStateTransform *tf)
{
if (tf->transform)
cmsDeleteTransform (tf->transform);
}
void
gdk_color_state_transform (GdkColorStateTransform *tf,
const float *src,
float *dst,
int width)
{
if (tf->copy_alpha)
memcpy (dst, src, sizeof (float) * 4 * width);
else
{
for (int i = 0; i < width * 4; i += 4)
{
dst[i] = src[i];
dst[i + 1] = src[i + 1];
dst[i + 2] = src[i + 2];
}
}
if (tf->cms_first && tf->transform)
cmsDoTransform (tf->transform, dst, dst, width);
if (tf->step1 && tf->step2)
{
for (int i = 0; i < width * 4; i += 4)
{
tf->step1 (dst[i], dst[i+1], dst[i+2], &dst[i], &dst[i+1], &dst[i+2]);
tf->step2 (dst[i], dst[i+1], dst[i+2], &dst[i], &dst[i+1], &dst[i+2]);
}
}
else if (tf->step1)
{
for (int i = 0; i < width * 4; i += 4)
tf->step1 (dst[i], dst[i+1], dst[i+2], &dst[i], &dst[i+1], &dst[i+2]);
}
if (!tf->cms_first && tf->transform)
cmsDoTransform (tf->transform, dst, dst, width);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

104
gdk/gdkcolorstate.h Normal file
View File

@@ -0,0 +1,104 @@
/* gdkcolorstate.h
*
* Copyright 2024 Red Hat, Inc.
*
* 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/>.
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_COLOR_STATE (gdk_color_state_get_type ())
GDK_AVAILABLE_IN_4_16
GType gdk_color_state_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_ref (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
void gdk_color_state_unref (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_srgb (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_srgb_linear (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_hsl (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_hwb (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
GdkColorState * gdk_color_state_get_display_p3 (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_xyz (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_rec2020 (void);
GDK_AVAILABLE_IN_4_16
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
gboolean gdk_color_state_equal (GdkColorState *self,
GdkColorState *other);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_state_is_linear (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_new_from_icc_profile (GBytes *icc_profile,
GError **error);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_new_from_cicp_data (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range);
GDK_AVAILABLE_IN_4_16
GBytes * gdk_color_state_save_to_icc_profile (GdkColorState *self,
GError **error);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristic,
int *matrix_coefficients,
gboolean *full_range,
GError **error);
#include "gdkcolorstateimpl.h"
G_END_DECLS

204
gdk/gdkcolorstateimpl.h Normal file
View File

@@ -0,0 +1,204 @@
/* gdkcolorstateimpl.h
*
* Copyright 2024 Red Hat, Inc.
*
* 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/>.
*/
#pragma once
typedef enum
{
GDK_COLOR_STATE_ID_SRGB = 1,
GDK_COLOR_STATE_ID_SRGB_LINEAR = 3,
GDK_COLOR_STATE_ID_HSL = 5,
GDK_COLOR_STATE_ID_HWB = 7,
GDK_COLOR_STATE_ID_OKLAB = 9,
GDK_COLOR_STATE_ID_OKLCH = 11,
GDK_COLOR_STATE_ID_DISPLAY_P3 = 13,
GDK_COLOR_STATE_ID_XYZ = 15,
GDK_COLOR_STATE_ID_REC2020 = 17,
GDK_COLOR_STATE_ID_REC2100_PQ = 19,
GDK_COLOR_STATE_ID_REC2100_LINEAR = 21,
} GdkColorStateId;
enum
{
GDK_TYPE_NAMED_COLOR_STATE,
GDK_TYPE_LCMS_COLOR_STATE,
};
typedef struct _GdkColorStateClass GdkColorStateClass;
struct _GdkColorState
{
GdkColorStateClass *klass;
int ref_count;
};
struct _GdkColorStateClass
{
int type;
void (* free) (GdkColorState *self);
gboolean (* equal) (GdkColorState *self,
GdkColorState *other);
gboolean (* is_linear) (GdkColorState *self);
GBytes * (* save_to_icc_profile) (GdkColorState *self,
GError **error);
gboolean (* save_to_cicp_data) (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error);
const char * (* get_name) (GdkColorState *self);
guint (* get_min_depth) (GdkColorState *self);
int (* get_hue_coord) (GdkColorState *self);
};
#define GDK_NAMED_COLOR_STATE_ID(c) ((GdkColorStateId) (GPOINTER_TO_INT (c)))
#define GDK_IS_NAMED_COLOR_STATE(c) ((GPOINTER_TO_INT(c)) & 1)
#define GDK_IS_LCMS_COLOR_STATE(c) ((c)->klass->type == GDK_TYPE_LCMS_COLOR_STATE)
#define gdk_color_state_ref(self) _gdk_color_state_ref (self)
static inline GdkColorState *
_gdk_color_state_ref (GdkColorState *self)
{
if (GDK_IS_NAMED_COLOR_STATE (self))
return self;
self->ref_count++;
return self;
}
#define gdk_color_state_unref(self) _gdk_color_state_unref (self)
static inline void
_gdk_color_state_unref (GdkColorState *self)
{
if (GDK_IS_NAMED_COLOR_STATE (self))
return;
self->ref_count--;
if (self->ref_count == 0)
self->klass->free (self);
}
#define GDK_COLOR_STATE_SRGB ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_SRGB))
#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_SRGB_LINEAR))
#define GDK_COLOR_STATE_HSL ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_HSL))
#define GDK_COLOR_STATE_HWB ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_HWB))
#define GDK_COLOR_STATE_OKLAB ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_OKLAB))
#define GDK_COLOR_STATE_OKLCH ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_OKLCH))
#define GDK_COLOR_STATE_DISPLAY_P3 ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_DISPLAY_P3))
#define GDK_COLOR_STATE_XYZ ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_XYZ))
#define GDK_COLOR_STATE_REC2020 ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_REC2020))
#define GDK_COLOR_STATE_REC2100_PQ ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_REC2100_PQ))
#define GDK_COLOR_STATE_REC2100_LINEAR ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_REC2100_LINEAR))
#define gdk_color_state_get_srgb() _gdk_color_state_get_srgb ()
static inline GdkColorState *
_gdk_color_state_get_srgb (void)
{
return GDK_COLOR_STATE_SRGB;
}
#define gdk_color_state_get_srgb_linear() _gdk_color_state_get_srgb_linear ()
static inline GdkColorState *
_gdk_color_state_get_srgb_linear (void)
{
return GDK_COLOR_STATE_SRGB_LINEAR;
}
#define gdk_color_state_get_hsl() _gdk_color_state_get_hsl ()
static inline GdkColorState *
_gdk_color_state_get_hsl (void)
{
return GDK_COLOR_STATE_HSL;
}
#define gdk_color_state_get_hwb() _gdk_color_state_get_hwb ()
static inline GdkColorState *
_gdk_color_state_get_hwb (void)
{
return GDK_COLOR_STATE_HWB;
}
#define gdk_color_state_get_oklab() _gdk_color_state_get_oklab ()
static inline GdkColorState *
_gdk_color_state_get_oklab (void)
{
return GDK_COLOR_STATE_OKLAB;
}
#define gdk_color_state_get_oklch() _gdk_color_state_get_oklch ()
static inline GdkColorState *
_gdk_color_state_get_oklch (void)
{
return GDK_COLOR_STATE_OKLCH;
}
#define gdk_color_state_get_display_p3() _gdk_color_state_get_display_p3 ()
static inline GdkColorState *
_gdk_color_state_get_display_p3 (void)
{
return GDK_COLOR_STATE_DISPLAY_P3;
}
#define gdk_color_state_get_xyz() _gdk_color_state_get_xyz ()
static inline GdkColorState *
_gdk_color_state_get_xyz (void)
{
return GDK_COLOR_STATE_XYZ;
}
#define gdk_color_state_get_rec2020() _gdk_color_state_get_rec2020 ()
static inline GdkColorState *
_gdk_color_state_get_rec2020 (void)
{
return GDK_COLOR_STATE_REC2020;
}
#define gdk_color_state_get_rec2100_pq() _gdk_color_state_get_rec2100_pq ()
static inline GdkColorState *
_gdk_color_state_get_rec2100_pq (void)
{
return GDK_COLOR_STATE_REC2100_PQ;
}
#define gdk_color_state_get_rec2100_linear() _gdk_color_state_get_rec2100_linear ()
static inline GdkColorState *
_gdk_color_state_get_rec2100_linear (void)
{
return GDK_COLOR_STATE_REC2100_LINEAR;
}
#define gdk_color_state_equal(a,b) _gdk_color_state_equal ((a), (b))
static inline gboolean
_gdk_color_state_equal (GdkColorState *self,
GdkColorState *other)
{
if (self == other)
return TRUE;
if (GDK_IS_NAMED_COLOR_STATE (self) || GDK_IS_NAMED_COLOR_STATE (other))
return FALSE;
if (self->klass != other->klass)
return FALSE;
return self->klass->equal (self, other);
}

View File

@@ -0,0 +1,39 @@
#pragma once
#include "gdkcolorstate.h"
#include "gdkmemoryformatprivate.h"
#include <lcms2.h>
const char * gdk_color_state_get_name (GdkColorState *color_state);
GdkMemoryDepth gdk_color_state_get_min_depth (GdkColorState *color_state);
int gdk_color_state_get_hue_coord (GdkColorState *color_state);
typedef void (* StepFunc) (float s0, float s1, float s2,
float *d0, float *d1, float *d2);
typedef struct _GdkColorStateTransform GdkColorStateTransform;
struct _GdkColorStateTransform
{
gpointer transform;
StepFunc step1;
StepFunc step2;
gboolean cms_first;
gboolean copy_alpha;
};
void gdk_color_state_transform_init (GdkColorStateTransform *tf,
GdkColorState *from,
GdkColorState *to,
gboolean copy_alpha);
void gdk_color_state_transform_finish (GdkColorStateTransform *tf);
void gdk_color_state_transform (GdkColorStateTransform *tf,
const float *src,
float *dst,
int width);
GdkColorState *gdk_color_state_new_from_lcms_profile (cmsHPROFILE profile);
const char *gdk_color_state_get_name_from_id (GdkColorStateId id);

View File

@@ -40,6 +40,7 @@ typedef enum {
GDK_DEBUG_OFFLOAD = 1 << 12,
/* flags below are influencing behavior */
GDK_DEBUG_SRGB = 1 << 13,
GDK_DEBUG_PORTALS = 1 << 14,
GDK_DEBUG_NO_PORTALS = 1 << 15,
GDK_DEBUG_GL_DISABLE = 1 << 16,

View File

@@ -24,6 +24,7 @@
#include "gdkdmabuffourccprivate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkcolorstate.h"
#ifdef HAVE_DMABUF
#include <sys/mman.h>
@@ -2062,12 +2063,15 @@ out:
void
gdk_dmabuf_download_mmap (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
GdkMemoryFormat src_format = gdk_texture_get_format (texture);
GdkColorState *src_color_state = gdk_texture_get_color_state (texture);
if (format == src_format)
if (format == src_format &&
gdk_color_state_equal (color_state, src_color_state))
gdk_dmabuf_do_download_mmap (texture, data, stride);
else
{
@@ -2083,8 +2087,10 @@ gdk_dmabuf_download_mmap (GdkTexture *texture,
gdk_dmabuf_do_download_mmap (texture, src_data, src_stride);
gdk_memory_convert (data, stride, format,
src_data, src_stride, src_format,
gdk_memory_convert (data, stride,
format, color_state,
src_data, src_stride,
src_format, src_color_state,
width, height);
g_free (src_data);

View File

@@ -35,6 +35,7 @@ void
gdk_dmabuf_downloader_download (GdkDmabufDownloader *self,
GdkDmabufTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
@@ -43,6 +44,6 @@ gdk_dmabuf_downloader_download (GdkDmabufDownloader *self,
g_return_if_fail (GDK_IS_DMABUF_DOWNLOADER (self));
iface = GDK_DMABUF_DOWNLOADER_GET_IFACE (self);
iface->download (self, texture, format, data, stride);
iface->download (self, texture, format, color_state, data, stride);
}

View File

@@ -20,6 +20,7 @@ struct _GdkDmabufDownloaderInterface
void (* download) (GdkDmabufDownloader *downloader,
GdkDmabufTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride);
};
@@ -31,6 +32,7 @@ gboolean gdk_dmabuf_downloader_supports (GdkDmabufDownlo
void gdk_dmabuf_downloader_download (GdkDmabufDownloader *downloader,
GdkDmabufTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride);

View File

@@ -27,6 +27,7 @@ struct _GdkDmabuf
GdkDmabufFormats * gdk_dmabuf_get_mmap_formats (void) G_GNUC_CONST;
void gdk_dmabuf_download_mmap (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride);

View File

@@ -96,6 +96,7 @@ struct _Download
{
GdkDmabufTexture *texture;
GdkMemoryFormat format;
GdkColorState *color_state;
guchar *data;
gsize stride;
volatile int spinlock;
@@ -109,6 +110,7 @@ gdk_dmabuf_texture_invoke_callback (gpointer data)
gdk_dmabuf_downloader_download (download->texture->downloader,
download->texture,
download->format,
download->color_state,
download->data,
download->stride);
@@ -120,16 +122,17 @@ gdk_dmabuf_texture_invoke_callback (gpointer data)
static void
gdk_dmabuf_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture);
Download download = { self, format, data, stride, 0 };
Download download = { self, format, color_state, data, stride, 0 };
if (self->downloader == NULL)
{
#ifdef HAVE_DMABUF
gdk_dmabuf_download_mmap (texture, format, data, stride);
gdk_dmabuf_download_mmap (texture, format, color_state, data, stride);
#endif
return;
}
@@ -200,6 +203,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder,
self = g_object_new (GDK_TYPE_DMABUF_TEXTURE,
"width", width,
"height", height,
"color-state", gdk_dmabuf_texture_builder_get_color_state (builder),
NULL);
g_set_object (&self->display, display);

View File

@@ -24,6 +24,7 @@
#include "gdkdebugprivate.h"
#include "gdkdisplay.h"
#include "gdkenumtypes.h"
#include "gdkcolorstate.h"
#include "gdkdmabuftextureprivate.h"
#include "gdkdmabuftexturebuilderprivate.h"
@@ -41,6 +42,8 @@ struct _GdkDmabufTextureBuilder
GdkDmabuf dmabuf;
GdkColorState *color_state;
GdkTexture *update_texture;
cairo_region_t *update_region;
};
@@ -124,6 +127,7 @@ enum
PROP_MODIFIER,
PROP_PREMULTIPLIED,
PROP_N_PLANES,
PROP_COLOR_STATE,
PROP_UPDATE_REGION,
PROP_UPDATE_TEXTURE,
@@ -141,6 +145,7 @@ gdk_dmabuf_texture_builder_dispose (GObject *object)
g_clear_object (&self->update_texture);
g_clear_pointer (&self->update_region, cairo_region_destroy);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
G_OBJECT_CLASS (gdk_dmabuf_texture_builder_parent_class)->dispose (object);
}
@@ -183,6 +188,10 @@ gdk_dmabuf_texture_builder_get_property (GObject *object,
g_value_set_uint (value, self->dmabuf.n_planes);
break;
case PROP_COLOR_STATE:
g_value_set_boxed (value, self->color_state);
break;
case PROP_UPDATE_REGION:
g_value_set_boxed (value, self->update_region);
break;
@@ -235,6 +244,10 @@ gdk_dmabuf_texture_builder_set_property (GObject *object,
gdk_dmabuf_texture_builder_set_n_planes (self, g_value_get_uint (value));
break;
case PROP_COLOR_STATE:
gdk_dmabuf_texture_builder_set_color_state (self, g_value_get_boxed (value));
break;
case PROP_UPDATE_REGION:
gdk_dmabuf_texture_builder_set_update_region (self, g_value_get_boxed (value));
break;
@@ -347,6 +360,18 @@ gdk_dmabuf_texture_builder_class_init (GdkDmabufTextureBuilderClass *klass)
1, GDK_DMABUF_MAX_PLANES, 1,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:color-state: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_color_state org.gtk.Property.set=gdk_dmabuf_texture_builder_set_color_state)
*
* The color state of the texture.
*
* Since: 4.16
*/
properties[PROP_COLOR_STATE] =
g_param_spec_boxed ("color-state", NULL, NULL,
GDK_TYPE_COLOR_STATE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkDmabufTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_update_region org.gtk.Property.set=gdk_dmabuf_texture_builder_set_update_region)
*
@@ -383,6 +408,8 @@ gdk_dmabuf_texture_builder_init (GdkDmabufTextureBuilder *self)
for (int i = 0; i < GDK_DMABUF_MAX_PLANES; i++)
self->dmabuf.planes[i].fd = -1;
self->color_state = gdk_color_state_get_srgb ();
}
/**
@@ -843,6 +870,48 @@ gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self,
self->dmabuf.planes[plane].offset = offset;
}
/**
* gdk_dmabuf_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state)
* @self: a `GdkDmabufTextureBuilder`
*
* Gets the color state previously set via gdk_dmabuf_texture_builder_set_color_state().
*
* Returns: the color state
*
* Since: 4.16
*/
GdkColorState *
gdk_dmabuf_texture_builder_get_color_state (GdkDmabufTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL);
return self->color_state;
}
/**
* gdk_dmabuf_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state)
* @self: a `GdkDmabufTextureBuilder`
* @color_state: a `GdkColorState`
*
* Sets the color state for the texture.
*
* Since: 4.16
*/
void
gdk_dmabuf_texture_builder_set_color_state (GdkDmabufTextureBuilder *self,
GdkColorState *color_state)
{
g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self));
g_return_if_fail (color_state != NULL);
if (self->color_state != color_state)
{
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gdk_color_state_ref (color_state);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]);
}
}
/**
* gdk_dmabuf_texture_builder_get_update_texture: (attributes org.gtk.Method.get_property=update-texture)
* @self: a `GdkDmabufTextureBuilder`

View File

@@ -100,6 +100,12 @@ void gdk_dmabuf_texture_builder_set_offset (GdkDmabufT
unsigned int plane,
unsigned int offset);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_dmabuf_texture_builder_get_color_state (GdkDmabufTextureBuilder *self);
GDK_AVAILABLE_IN_4_16
void gdk_dmabuf_texture_builder_set_color_state (GdkDmabufTextureBuilder *self,
GdkColorState *color_state);
GDK_AVAILABLE_IN_4_14
GdkTexture * gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_14

View File

@@ -24,6 +24,7 @@
#include "gdkglcontextprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkcolorstate.h"
#include <epoxy/gl.h>
@@ -136,6 +137,7 @@ typedef struct _Download Download;
struct _Download
{
GdkMemoryFormat format;
GdkColorState *color_state;
guchar *data;
gsize stride;
};
@@ -185,13 +187,15 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
{
GdkTexture *texture = GDK_TEXTURE (self);
GdkMemoryFormat format;
GdkColorState *color_state;
gsize expected_stride;
Download *download = download_;
GLint gl_internal_format;
GLenum gl_format, gl_type;
GLint gl_swizzle[4];
format = gdk_texture_get_format (texture),
format = gdk_texture_get_format (texture);
color_state = gdk_texture_get_color_state (texture);
expected_stride = texture->width * gdk_memory_format_bytes_per_pixel (download->format);
if (!gdk_gl_context_get_use_es (context) &&
@@ -225,9 +229,11 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
gdk_memory_convert (download->data,
download->stride,
download->format,
download->color_state,
pixels,
stride,
format,
color_state,
texture->width,
texture->height);
@@ -377,9 +383,11 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
gdk_memory_convert (download->data,
download->stride,
download->format,
download->color_state,
pixels,
stride,
actual_format,
color_state,
texture->width,
texture->height);
@@ -393,6 +401,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self,
static void
gdk_gl_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
@@ -401,11 +410,12 @@ gdk_gl_texture_download (GdkTexture *texture,
if (self->saved)
{
gdk_texture_do_download (self->saved, format, data, stride);
gdk_texture_do_download (self->saved, format, color_state, data, stride);
return;
}
download.format = format;
download.color_state = color_state;
download.data = data;
download.stride = stride;
@@ -471,8 +481,7 @@ gdk_gl_texture_release (GdkGLTexture *self)
g_return_if_fail (self->saved == NULL);
texture = GDK_TEXTURE (self);
self->saved = GDK_TEXTURE (gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture)));
self->saved = GDK_TEXTURE (gdk_memory_texture_from_texture (texture));
drop_gl_resources (self);
}
@@ -488,6 +497,7 @@ gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder,
self = g_object_new (GDK_TYPE_GL_TEXTURE,
"width", gdk_gl_texture_builder_get_width (builder),
"height", gdk_gl_texture_builder_get_height (builder),
"color-state", gdk_gl_texture_builder_get_color_state (builder),
NULL);
self->context = g_object_ref (gdk_gl_texture_builder_get_context (builder));

View File

@@ -23,6 +23,7 @@
#include "gdkenumtypes.h"
#include "gdkglcontext.h"
#include "gdkcolorstate.h"
#include "gdkgltextureprivate.h"
#include <cairo-gobject.h>
@@ -38,6 +39,7 @@ struct _GdkGLTextureBuilder
GdkMemoryFormat format;
gboolean has_mipmap;
gpointer sync;
GdkColorState *color_state;
GdkTexture *update_texture;
cairo_region_t *update_region;
@@ -75,6 +77,7 @@ enum
PROP_HEIGHT,
PROP_ID,
PROP_SYNC,
PROP_COLOR_STATE,
PROP_UPDATE_REGION,
PROP_UPDATE_TEXTURE,
PROP_WIDTH,
@@ -95,6 +98,7 @@ gdk_gl_texture_builder_dispose (GObject *object)
g_clear_object (&self->update_texture);
g_clear_pointer (&self->update_region, cairo_region_destroy);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
G_OBJECT_CLASS (gdk_gl_texture_builder_parent_class)->dispose (object);
}
@@ -133,6 +137,10 @@ gdk_gl_texture_builder_get_property (GObject *object,
g_value_set_pointer (value, self->sync);
break;
case PROP_COLOR_STATE:
g_value_set_object (value, self->color_state);
break;
case PROP_UPDATE_REGION:
g_value_set_boxed (value, self->update_region);
break;
@@ -185,6 +193,10 @@ gdk_gl_texture_builder_set_property (GObject *object,
gdk_gl_texture_builder_set_sync (self, g_value_get_pointer (value));
break;
case PROP_COLOR_STATE:
gdk_gl_texture_builder_set_color_state (self, g_value_get_object (value));
break;
case PROP_UPDATE_REGION:
gdk_gl_texture_builder_set_update_region (self, g_value_get_boxed (value));
break;
@@ -286,6 +298,18 @@ gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass)
g_param_spec_pointer ("sync", NULL, NULL,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:color-state: (attributes org.gtk.Property.get=gdk_gl_texture_builder_get_color_state org.gtk.Property.set=gdk_gl_texture_builder_set_color_state)
*
* The color state of the texture.
*
* Since: 4.16
*/
properties[PROP_COLOR_STATE] =
g_param_spec_boxed ("color-state", NULL, NULL,
GDK_TYPE_COLOR_STATE,
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
/**
* GdkGLTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_gl_texture_builder_get_update_region org.gtk.Property.set=gdk_gl_texture_builder_set_update_region)
*
@@ -329,6 +353,7 @@ static void
gdk_gl_texture_builder_init (GdkGLTextureBuilder *self)
{
self->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
self->color_state = gdk_color_state_get_srgb ();
}
/**
@@ -616,6 +641,48 @@ gdk_gl_texture_builder_set_sync (GdkGLTextureBuilder *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SYNC]);
}
/**
* gdk_gl_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state)
* @self: a `GdkGLTextureBuilder`
*
* Gets the color state previously set via gdk_gl_texture_builder_set_color_state().
*
* Returns: the color state
*
* Since: 4.16
*/
GdkColorState *
gdk_gl_texture_builder_get_color_state (GdkGLTextureBuilder *self)
{
g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL);
return self->color_state;
}
/**
* gdk_gl_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state)
* @self: a `GdkGLTextureBuilder`
* @color_state: a `GdkColorState`
*
* Sets the color state for the texture.
*
* Since: 4.16
*/
void
gdk_gl_texture_builder_set_color_state (GdkGLTextureBuilder *self,
GdkColorState *color_state)
{
g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self));
g_return_if_fail (color_state != NULL);
if (self->color_state != color_state)
{
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gdk_color_state_ref (color_state);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]);
}
}
/**
* gdk_gl_texture_builder_get_format: (attributes org.gtk.Method.get_property=format)
* @self: a `GdkGLTextureBuilder`

View File

@@ -76,6 +76,12 @@ GDK_AVAILABLE_IN_4_12
void gdk_gl_texture_builder_set_sync (GdkGLTextureBuilder *self,
gpointer sync);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_gl_texture_builder_get_color_state (GdkGLTextureBuilder *self);
GDK_AVAILABLE_IN_4_16
void gdk_gl_texture_builder_set_color_state (GdkGLTextureBuilder *self,
GdkColorState *color_state);
GDK_AVAILABLE_IN_4_12
GdkTexture * gdk_gl_texture_builder_get_update_texture (GdkGLTextureBuilder *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_12

View File

@@ -23,8 +23,9 @@
#include "gdkdmabuffourccprivate.h"
#include "gdkglcontextprivate.h"
#include "gdkcolorstateprivate.h"
#include "gsk/gl/fp16private.h"
#include "gtk/gtkcolorutilsprivate.h"
#include <epoxy/gl.h>
@@ -1734,14 +1735,18 @@ void
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorState *dest_color_state,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorState *src_color_state,
gsize width,
gsize height)
{
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
GdkColorStateTransform transform;
gboolean has_transform;
float *tmp;
gsize y;
void (*func) (guchar *, const guchar *, gsize) = NULL;
@@ -1749,7 +1754,8 @@ gdk_memory_convert (guchar *dest_data,
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
if (src_format == dest_format)
if (gdk_color_state_equal (src_color_state, dest_color_state) &&
src_format == dest_format)
{
gsize bytes_per_row = src_desc->bytes_per_pixel * width;
@@ -1769,7 +1775,9 @@ gdk_memory_convert (guchar *dest_data,
return;
}
if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
if (!gdk_color_state_equal (src_color_state, dest_color_state))
func = NULL;
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
func = r8g8b8a8_to_r8g8b8a8_premultiplied;
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
func = r8g8b8a8_to_b8g8r8a8_premultiplied;
@@ -1817,19 +1825,43 @@ gdk_memory_convert (guchar *dest_data,
return;
}
if (!gdk_color_state_equal (src_color_state, dest_color_state))
{
gdk_color_state_transform_init (&transform, src_color_state, dest_color_state, TRUE);
has_transform = TRUE;
}
else
{
has_transform = FALSE;
}
tmp = g_new (float, width * 4);
for (y = 0; y < height; y++)
{
src_desc->to_float (tmp, src_data, width);
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
unpremultiply (tmp, width);
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
if (has_transform)
{
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED)
unpremultiply (tmp, width);
gdk_color_state_transform (&transform, tmp, tmp, width);
if (dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
}
else
{
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
unpremultiply (tmp, width);
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
}
dest_desc->from_float (dest_data, tmp, width);
src_data += src_stride;
dest_data += dest_stride;
}
if (has_transform)
gdk_color_state_transform_finish (&transform);
g_free (tmp);
}

View File

@@ -80,9 +80,11 @@ const char * gdk_memory_format_get_name (GdkMemoryFormat
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorState *dest_color_state,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorState *src_color_state,
gsize width,
gsize height);

View File

@@ -22,6 +22,7 @@
#include "gdkmemorytextureprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkcolorstate.h"
#include "gsk/gl/fp16private.h"
/**
@@ -58,6 +59,7 @@ gdk_memory_texture_dispose (GObject *object)
static void
gdk_memory_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
@@ -65,9 +67,11 @@ gdk_memory_texture_download (GdkTexture *texture,
gdk_memory_convert (data, stride,
format,
color_state,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
texture->format,
texture->color_state,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
@@ -131,7 +135,7 @@ gdk_memory_sanitize (GBytes *bytes,
* @bytes: the `GBytes` containing the pixel data
* @stride: rowstride for the data
*
* Creates a new texture for a blob of image data.
* Creates a new texture for a blob of sRGB image data.
*
* The `GBytes` must contain @stride × @height pixels
* in the given format.
@@ -144,11 +148,43 @@ gdk_memory_texture_new (int width,
GdkMemoryFormat format,
GBytes *bytes,
gsize stride)
{
return gdk_memory_texture_new_with_color_state (width, height, format,
gdk_color_state_get_srgb (),
bytes, stride);
}
/**
* gdk_memory_texture_new_with_color_state:
* @width: the width of the texture
* @height: the height of the texture
* @format: the format of the data
* @color_state: a `GdkColorSpace`
* @bytes: the `GBytes` containing the pixel data
* @stride: rowstride for the data
*
* Creates a new texture for a blob of image data with a given color state.
*
* The `GBytes` must contain @stride x @height pixels
* in the given format.
*
* Returns: A newly-created `GdkTexture`
*
* Since: 4.16
*/
GdkTexture *
gdk_memory_texture_new_with_color_state (int width,
int height,
GdkMemoryFormat format,
GdkColorState *color_state,
GBytes *bytes,
gsize stride)
{
GdkMemoryTexture *self;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
g_return_val_if_fail (color_state != NULL, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
/* needs to be this complex to support subtexture of the bottom right part */
@@ -159,6 +195,7 @@ gdk_memory_texture_new (int width,
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
"width", width,
"height", height,
"color-state", color_state,
NULL);
GDK_TEXTURE (self)->format = format;
@@ -191,19 +228,19 @@ gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
size = source->stride * (height - 1) + width * bpp;
bytes = g_bytes_new_from_bytes (source->bytes, offset, size);
result = gdk_memory_texture_new (width,
height,
texture->format,
bytes,
source->stride);
result = gdk_memory_texture_new_with_color_state (width,
height,
texture->format,
texture->color_state,
bytes,
source->stride);
g_bytes_unref (bytes);
return result;
}
GdkMemoryTexture *
gdk_memory_texture_from_texture (GdkTexture *texture,
GdkMemoryFormat format)
gdk_memory_texture_from_texture (GdkTexture *texture)
{
GdkTexture *result;
GBytes *bytes;
@@ -213,23 +250,19 @@ gdk_memory_texture_from_texture (GdkTexture *texture,
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
if (GDK_IS_MEMORY_TEXTURE (texture))
{
GdkMemoryTexture *memtex = GDK_MEMORY_TEXTURE (texture);
return g_object_ref (GDK_MEMORY_TEXTURE (texture));
if (gdk_texture_get_format (texture) == format)
return g_object_ref (memtex);
}
stride = texture->width * gdk_memory_format_bytes_per_pixel (format);
stride = texture->width * gdk_memory_format_bytes_per_pixel (texture->format);
data = g_malloc_n (stride, texture->height);
gdk_texture_do_download (texture, format, data, stride);
gdk_texture_do_download (texture, texture->format, texture->color_state, data, stride);
bytes = g_bytes_new_take (data, stride * texture->height);
result = gdk_memory_texture_new (texture->width,
texture->height,
format,
bytes,
stride);
result = gdk_memory_texture_new_with_color_state (texture->width,
texture->height,
texture->format,
texture->color_state,
bytes,
stride);
g_bytes_unref (bytes);
return GDK_MEMORY_TEXTURE (result);

View File

@@ -68,6 +68,14 @@ GdkTexture * gdk_memory_texture_new (int
GBytes *bytes,
gsize stride);
GDK_AVAILABLE_IN_4_16
GdkTexture * gdk_memory_texture_new_with_color_state (int width,
int height,
GdkMemoryFormat format,
GdkColorState *color_state,
GBytes *bytes,
gsize stride);
G_END_DECLS

View File

@@ -28,8 +28,7 @@ G_BEGIN_DECLS
#define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8
#define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8
GdkMemoryTexture * gdk_memory_texture_from_texture (GdkTexture *texture,
GdkMemoryFormat format);
GdkMemoryTexture * gdk_memory_texture_from_texture (GdkTexture *texture);
GdkTexture * gdk_memory_texture_new_subtexture (GdkMemoryTexture *texture,
int x,
int y,

View File

@@ -30,6 +30,8 @@
#include "gdksurface.h"
#include "gdkprivate.h"
#include "gdkcolorstate.h"
#include "gdkcairo.h"
#include "gdkcontentprovider.h"
#include "gdkdeviceprivate.h"
#include "gdkdisplayprivate.h"
@@ -44,6 +46,7 @@
#include "gdktoplevelprivate.h"
#include "gdkvulkancontext.h"
#include "gdksubsurfaceprivate.h"
#include "gdkcolorstate.h"
#include <math.h>
@@ -89,6 +92,7 @@ enum {
enum {
PROP_0,
PROP_COLOR_STATE,
PROP_CURSOR,
PROP_DISPLAY,
PROP_FRAME_CLOCK,
@@ -484,6 +488,18 @@ gdk_surface_init (GdkSurface *surface)
surface->alpha = 255;
if (g_getenv ("GDK_DISPLAY_COLORSTATE"))
{
const char *env = g_getenv ("GDK_DISPLAY_COLORSTATE");
if (strcmp (env, "srgb") == 0)
surface->color_state = gdk_color_state_get_srgb ();
else if (strcmp (env, "srgb-linear") == 0)
surface->color_state = gdk_color_state_get_srgb_linear ();
}
if (surface->color_state == NULL)
surface->color_state = gdk_color_state_get_srgb ();
surface->device_cursor = g_hash_table_new_full (NULL, NULL,
NULL, g_object_unref);
@@ -528,6 +544,25 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
klass->get_scale = gdk_surface_real_get_scale;
klass->create_subsurface = gdk_surface_real_create_subsurface;
/**
* GdkSurface:color-state: (attributes org.gtk.Property.get=gdk_surface_get_color_state)
*
* The preferred color state for rendering to the surface
*
* This color state is negotiated between GTK and the compositor.
*
* The color state may change as the surface gets moved around - for example
* to different monitors or when the compositor gets reconfigured. As long as
* the surface isn't shown, the color space may not represent the actual color
* state that is going to be used.
*
* Since: 4.16
*/
properties[PROP_COLOR_STATE] =
g_param_spec_boxed ("color-state", NULL, NULL,
GDK_TYPE_COLOR_STATE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* GdkSurface:cursor: (attributes org.gtk.Property.get=gdk_surface_get_cursor org.gtk.Property.set=gdk_surface_set_cursor)
*
@@ -786,6 +821,10 @@ gdk_surface_set_property (GObject *object,
switch (prop_id)
{
case PROP_COLOR_STATE:
gdk_surface_set_color_state (surface, g_value_get_object (value));
break;
case PROP_CURSOR:
gdk_surface_set_cursor (surface, g_value_get_object (value));
break;
@@ -819,6 +858,10 @@ gdk_surface_get_property (GObject *object,
switch (prop_id)
{
case PROP_COLOR_STATE:
g_value_set_object (value, gdk_surface_get_color_state (surface));
break;
case PROP_CURSOR:
g_value_set_object (value, gdk_surface_get_cursor (surface));
break;
@@ -2330,6 +2373,7 @@ gdk_surface_create_similar_surface (GdkSurface *surface,
content == CAIRO_CONTENT_ALPHA ? CAIRO_FORMAT_A8 : CAIRO_FORMAT_ARGB32,
width * scale, height * scale);
cairo_surface_set_device_scale (similar_surface, scale, scale);
gdk_cairo_surface_set_color_state (similar_surface, gdk_surface_get_color_state (surface));
return similar_surface;
}
@@ -3076,3 +3120,37 @@ gdk_surface_get_subsurface (GdkSurface *surface,
{
return g_ptr_array_index (surface->subsurfaces, idx);
}
void
gdk_surface_set_color_state (GdkSurface *surface,
GdkColorState *color_state)
{
/* This way we support unsetting, too */
if (G_UNLIKELY (gdk_display_get_debug_flags (surface->display) & GDK_DEBUG_SRGB))
color_state = gdk_color_state_get_srgb ();
if (gdk_color_state_equal (surface->color_state, color_state))
return;
g_set_object (&surface->color_state, color_state);
g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_COLOR_STATE]);
}
/**
* gdk_surface_get_color_state:
* @self: a `GdkSurface`
*
* Returns the preferred color state for rendering to the given @surface.
*
* Returns: (transfer none): The color state of @surface
*
* Since: 4.16
*/
GdkColorState *
gdk_surface_get_color_state (GdkSurface *surface)
{
g_return_val_if_fail (GDK_IS_SURFACE (surface), gdk_color_state_get_srgb ());
return surface->color_state;
}

View File

@@ -139,6 +139,9 @@ GdkVulkanContext *
gdk_surface_create_vulkan_context(GdkSurface *surface,
GError **error);
GDK_AVAILABLE_IN_4_16
GdkColorState *gdk_surface_get_color_state (GdkSurface *surface);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GdkSurface, g_object_unref)
G_END_DECLS

View File

@@ -105,6 +105,8 @@ struct _GdkSurface
*/
GdkSubsurface *subsurfaces_above;
GdkSubsurface *subsurfaces_below;
GdkColorState *color_state;
};
struct _GdkSurfaceClass
@@ -355,4 +357,7 @@ gsize gdk_surface_get_n_subsurfaces (GdkSurface *surface);
GdkSubsurface * gdk_surface_get_subsurface (GdkSurface *surface,
gsize idx);
void gdk_surface_set_color_state (GdkSurface *surface,
GdkColorState *color_state);
G_END_DECLS

View File

@@ -44,6 +44,8 @@
#include "gdkmemorytextureprivate.h"
#include "gdkpaintable.h"
#include "gdksnapshot.h"
#include "gdkcolorstate.h"
#include "gdkcairo.h"
#include <graphene.h>
#include "loaders/gdkpngprivate.h"
@@ -69,6 +71,7 @@ enum {
PROP_0,
PROP_WIDTH,
PROP_HEIGHT,
PROP_COLOR_STATE,
N_PROPS
};
@@ -258,6 +261,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
static void
gdk_texture_default_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
@@ -282,6 +286,12 @@ gdk_texture_set_property (GObject *gobject,
self->height = g_value_get_int (value);
break;
case PROP_COLOR_STATE:
if (self->color_state)
gdk_color_state_unref (self->color_state);
self->color_state = gdk_color_state_ref (g_value_get_boxed (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -306,6 +316,10 @@ gdk_texture_get_property (GObject *gobject,
g_value_set_int (value, self->height);
break;
case PROP_COLOR_STATE:
g_value_set_boxed (value, self->color_state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -344,6 +358,8 @@ gdk_texture_dispose (GObject *object)
gdk_texture_clear_render_data (self);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
G_OBJECT_CLASS (gdk_texture_parent_class)->dispose (object);
}
@@ -388,12 +404,28 @@ gdk_texture_class_init (GdkTextureClass *klass)
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GdkTexture:color-state: (attributes org.gtk.Property.get=gdk_texture_get_color_state)
*
* The color state of the texture.
*
* Since: 4.16
*/
properties[PROP_COLOR_STATE] =
g_param_spec_boxed ("color-state", NULL, NULL,
GDK_TYPE_COLOR_STATE,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, N_PROPS, properties);
}
static void
gdk_texture_init (GdkTexture *self)
{
self->color_state = gdk_color_state_get_srgb ();
}
/**
@@ -424,17 +456,42 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
(GDestroyNotify) cairo_surface_destroy,
cairo_surface_reference (surface));
texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
GDK_MEMORY_DEFAULT,
bytes,
cairo_image_surface_get_stride (surface));
texture = gdk_memory_texture_new_with_color_state (cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
GDK_MEMORY_DEFAULT,
gdk_cairo_surface_get_color_state (surface),
bytes,
cairo_image_surface_get_stride (surface));
g_bytes_unref (bytes);
return texture;
}
static GdkColorState *
gdk_color_state_from_pixbuf (GdkPixbuf *pixbuf)
{
const char *icc_profile_base64;
GdkColorState *color_state = NULL;
icc_profile_base64 = gdk_pixbuf_get_option (pixbuf, "icc-profile");
if (icc_profile_base64)
{
guchar *icc_data;
gsize icc_len;
GBytes *bytes;
icc_data = g_base64_decode (icc_profile_base64, &icc_len);
bytes = g_bytes_new_take (icc_data, icc_len);
color_state = gdk_color_state_new_from_icc_profile (bytes, NULL);
g_bytes_unref (bytes);
}
if (!color_state)
color_state = gdk_color_state_get_srgb ();
return color_state;
}
/**
* gdk_texture_new_for_pixbuf:
* @pixbuf: a `GdkPixbuf`
@@ -452,24 +509,31 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
{
GdkTexture *texture;
GBytes *bytes;
GdkColorState *color_state;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
color_state = gdk_color_state_from_pixbuf (pixbuf);
bytes = g_bytes_new_with_free_func (gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_height (pixbuf)
* (gsize) gdk_pixbuf_get_rowstride (pixbuf),
g_object_unref,
g_object_ref (pixbuf));
texture = gdk_memory_texture_new (gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
bytes,
gdk_pixbuf_get_rowstride (pixbuf));
texture = gdk_memory_texture_new_with_color_state (gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
gdk_pixbuf_get_has_alpha (pixbuf)
? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
color_state,
bytes,
gdk_pixbuf_get_rowstride (pixbuf));
g_bytes_unref (bytes);
gdk_color_state_unref (color_state);
return texture;
}
@@ -727,13 +791,32 @@ gdk_texture_get_height (GdkTexture *texture)
return texture->height;
}
/**
* gdk_texture_get_color_state: (attributes org.gtk.Method.get_property=color-state)
* @texture: a `GdkTexture`
*
* Returns the color state associsated with @texture.
*
* Returns: (transfer none): the color state of the `GdkTexture`
*
* Since: 4.16
*/
GdkColorState *
gdk_texture_get_color_state (GdkTexture *texture)
{
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
return texture->color_state;
}
void
gdk_texture_do_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data, stride);
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, color_state, data, stride);
}
static gboolean
@@ -829,7 +912,8 @@ gdk_texture_set_diff (GdkTexture *self,
}
cairo_surface_t *
gdk_texture_download_surface (GdkTexture *texture)
gdk_texture_download_surface (GdkTexture *texture,
GdkColorState *color_state)
{
cairo_surface_t *surface;
cairo_status_t surface_status;
@@ -841,10 +925,13 @@ gdk_texture_download_surface (GdkTexture *texture)
if (surface_status != CAIRO_STATUS_SUCCESS)
g_warning ("%s: surface error: %s", __FUNCTION__,
cairo_status_to_string (surface_status));
else
gdk_texture_do_download (texture,
GDK_MEMORY_DEFAULT,
color_state,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface));
gdk_texture_download (texture,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface));
cairo_surface_mark_dirty (surface);
return surface;
@@ -891,6 +978,7 @@ gdk_texture_download (GdkTexture *texture,
gdk_texture_do_download (texture,
GDK_MEMORY_DEFAULT,
gdk_color_state_get_srgb (),
data,
stride);
}

View File

@@ -83,6 +83,9 @@ int gdk_texture_get_height (GdkTexture
GDK_AVAILABLE_IN_4_10
GdkMemoryFormat gdk_texture_get_format (GdkTexture *self) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_texture_get_color_state (GdkTexture *self);
GDK_AVAILABLE_IN_ALL
void gdk_texture_download (GdkTexture *texture,
guchar *data,

View File

@@ -39,6 +39,7 @@
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdktextureprivate.h"
#include "gdkcolorstate.h"
G_DEFINE_BOXED_TYPE (GdkTextureDownloader, gdk_texture_downloader,
gdk_texture_downloader_copy,
@@ -51,6 +52,7 @@ gdk_texture_downloader_init (GdkTextureDownloader *self,
{
self->texture = g_object_ref (texture);
self->format = GDK_MEMORY_DEFAULT;
self->color_state = gdk_color_state_get_srgb ();
}
void
@@ -103,6 +105,7 @@ gdk_texture_downloader_copy (const GdkTextureDownloader *self)
copy = gdk_texture_downloader_new (self->texture);
gdk_texture_downloader_set_format (copy, self->format);
gdk_texture_downloader_set_color_state (copy, self->color_state);
return copy;
}
@@ -121,6 +124,8 @@ gdk_texture_downloader_free (GdkTextureDownloader *self)
g_return_if_fail (self != NULL);
gdk_texture_downloader_finish (self);
g_clear_pointer (&self->color_state, gdk_color_state_unref);
g_free (self);
}
@@ -199,6 +204,39 @@ gdk_texture_downloader_get_format (const GdkTextureDownloader *self)
return self->format;
}
/**
* gdk_texture_downloader_set_color_state:
* @self: a texture downloader
* @color_state: the color state to use
*
* Sets the color state that the data will be converted to.
*
* Since: 4.16
*/
void
gdk_texture_downloader_set_color_state (GdkTextureDownloader *self,
GdkColorState *color_state)
{
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gdk_color_state_ref (color_state);
}
/**
* gdk_texture_downloader_get_color_state:
* @self: a texture downloader
*
* Gets the color state that the data will be converted to.
*
* Returns: the color state
*
* Since: 4.16
*/
GdkColorState *
gdk_texture_downloader_get_color_state (const GdkTextureDownloader *self)
{
return self->color_state;
}
/**
* gdk_texture_downloader_download_into:
* @self: a texture downloader
@@ -219,7 +257,7 @@ gdk_texture_downloader_download_into (const GdkTextureDownloader *self,
g_return_if_fail (data != NULL);
g_return_if_fail (stride >= gdk_texture_get_width (self->texture) * gdk_memory_format_bytes_per_pixel (self->format));
gdk_texture_do_download (self->texture, self->format, data, stride);
gdk_texture_do_download (self->texture, self->format, self->color_state, data, stride);
}
/**
@@ -250,7 +288,8 @@ gdk_texture_downloader_download_bytes (const GdkTextureDownloader *self,
g_return_val_if_fail (out_stride != NULL, NULL);
if (GDK_IS_MEMORY_TEXTURE (self->texture) &&
gdk_texture_get_format (self->texture) == self->format)
gdk_texture_get_format (self->texture) == self->format &&
gdk_color_state_equal (self->texture->color_state, self->color_state))
{
GdkMemoryTexture *memtex = GDK_MEMORY_TEXTURE (self->texture);
@@ -260,7 +299,7 @@ gdk_texture_downloader_download_bytes (const GdkTextureDownloader *self,
stride = self->texture->width * gdk_memory_format_bytes_per_pixel (self->format);
data = g_malloc_n (stride, self->texture->height);
gdk_texture_do_download (self->texture, self->format, data, stride);
gdk_texture_do_download (self->texture, self->format, self->color_state, data, stride);
*out_stride = stride;
return g_bytes_new_take (data, stride * self->texture->height);

View File

@@ -49,6 +49,12 @@ void gdk_texture_downloader_set_format (GdkTextureDownl
GDK_AVAILABLE_IN_4_10
GdkMemoryFormat gdk_texture_downloader_get_format (const GdkTextureDownloader *self);
GDK_AVAILABLE_IN_4_16
void gdk_texture_downloader_set_color_state (GdkTextureDownloader *self,
GdkColorState *color_state);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_texture_downloader_get_color_state (const GdkTextureDownloader *self);
GDK_AVAILABLE_IN_4_10
void gdk_texture_downloader_download_into (const GdkTextureDownloader *self,

View File

@@ -28,6 +28,7 @@ struct _GdkTextureDownloader
/*< private >*/
GdkTexture *texture;
GdkMemoryFormat format;
GdkColorState *color_state;
};
void gdk_texture_downloader_init (GdkTextureDownloader *self,

View File

@@ -26,6 +26,8 @@ struct _GdkTexture
int width;
int height;
GdkColorState *color_state;
gpointer render_key;
gpointer render_data;
GDestroyNotify render_notify;
@@ -46,6 +48,7 @@ struct _GdkTextureClass {
/* mandatory: Download in the given format into data */
void (* download) (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride);
};
@@ -53,10 +56,12 @@ struct _GdkTextureClass {
gboolean gdk_texture_can_load (GBytes *bytes);
GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface);
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture);
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture,
GdkColorState *color_state);
void gdk_texture_do_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride);
void gdk_texture_diff (GdkTexture *self,

View File

@@ -74,6 +74,8 @@ typedef cairo_rectangle_int_t GdkRectangle;
/* Forward declarations of commonly used types */
typedef struct _GdkRGBA GdkRGBA;
typedef struct _GdkColor GdkColor;
typedef struct _GdkColorState GdkColorState;
typedef struct _GdkContentFormats GdkContentFormats;
typedef struct _GdkContentProvider GdkContentProvider;
typedef struct _GdkCursor GdkCursor;

View File

@@ -24,6 +24,8 @@
#include <glib/gi18n-lib.h>
#include "gdktexture.h"
#include "gdktexturedownloaderprivate.h"
#include "gdkcolorstate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
@@ -143,9 +145,12 @@ gdk_load_jpeg (GBytes *input_bytes,
guint width, height, stride;
unsigned char *data = NULL;
unsigned char *row[1];
JOCTET *icc_data;
unsigned int icc_len;
GBytes *bytes;
GdkTexture *texture;
GdkMemoryFormat format;
GdkColorState *color_state;
G_GNUC_UNUSED guint64 before = GDK_PROFILER_CURRENT_TIME;
info.err = jpeg_std_error (&jerr.pub);
@@ -169,6 +174,9 @@ gdk_load_jpeg (GBytes *input_bytes,
g_bytes_get_data (input_bytes, NULL),
g_bytes_get_size (input_bytes));
/* save color space */
jpeg_save_markers (&info, JPEG_APP0 + 2, 0xFFFF);
jpeg_read_header (&info, TRUE);
jpeg_start_decompress (&info);
@@ -226,19 +234,35 @@ gdk_load_jpeg (GBytes *input_bytes,
g_assert_not_reached ();
}
if (jpeg_read_icc_profile (&info, &icc_data, &icc_len))
{
GBytes *icc_bytes = g_bytes_new_with_free_func (icc_data, icc_len, free, icc_data);
color_state = gdk_color_state_new_from_icc_profile (icc_bytes, error);
g_bytes_unref (icc_bytes);
}
else
color_state = gdk_color_state_get_srgb ();
jpeg_finish_decompress (&info);
jpeg_destroy_decompress (&info);
bytes = g_bytes_new_take (data, stride * height);
texture = gdk_memory_texture_new (width, height,
format,
bytes, stride);
if (color_state)
{
texture = gdk_memory_texture_new_with_color_state (width, height,
format,
color_state,
bytes, stride);
}
else
texture = NULL;
g_clear_pointer (&color_state, gdk_color_state_unref);
g_bytes_unref (bytes);
gdk_profiler_end_mark (before, "Load jpeg", NULL);
return texture;
}
@@ -257,9 +281,12 @@ gdk_save_jpeg (GdkTexture *texture)
gsize texstride;
guchar *row;
int width, height;
GdkColorState *color_state;
GBytes *bytes;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
color_state = gdk_texture_get_color_state (texture);
info.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = fatal_error_handler;
@@ -298,6 +325,15 @@ gdk_save_jpeg (GdkTexture *texture)
jpeg_start_compress (&info, TRUE);
bytes = gdk_color_state_save_to_icc_profile (color_state, NULL);
if (bytes)
{
jpeg_write_icc_profile (&info,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
g_bytes_unref (bytes);
}
while (info.next_scanline < info.image_height)
{
row = (guchar *) texdata + info.next_scanline * texstride;

View File

@@ -20,11 +20,14 @@
#include "gdkpngprivate.h"
#include <glib/gi18n-lib.h>
#include "gdkcolorstateprivate.h"
#include "gdkcolorstateprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytexture.h"
#include "gdkprofilerprivate.h"
#include "gdktexturedownloaderprivate.h"
#include "gsk/gl/fp16private.h"
#include <png.h>
#include <stdio.h>
@@ -126,6 +129,182 @@ png_simple_warning_callback (png_structp png,
{
}
/* }}} */
/* {{{ Color profile handling */
typedef struct
{
gboolean cicp_chunk_read;
int color_primaries;
int transfer_function;
int matrix_coefficients;
int full_range;
} CICPData;
static int
png_read_chunk_func (png_structp png,
png_unknown_chunkp chunk)
{
if (strcmp ((char *) chunk->name, "cICP") == 0 &&
chunk->size == 4)
{
CICPData *cicp = png_get_user_chunk_ptr (png);
cicp->cicp_chunk_read = TRUE;
cicp->color_primaries = chunk->data[0];
cicp->transfer_function = chunk->data[1];
cicp->matrix_coefficients = chunk->data[2];
cicp->full_range = chunk->data[3];
return 1;
}
return 0;
}
static GdkColorState *
gdk_png_get_color_state (png_struct *png,
png_info *info)
{
GdkColorState *color_state;
guchar *icc_data;
png_uint_32 icc_len;
char *name;
double gamma;
cmsCIExyY whitepoint;
cmsCIExyYTRIPLE primaries;
cmsToneCurve *curve;
cmsHPROFILE lcms_profile;
int intent;
CICPData *cicp;
cicp = png_get_user_chunk_ptr (png);
if (cicp->cicp_chunk_read)
{
color_state = gdk_color_state_new_from_cicp_data (cicp->color_primaries,
cicp->transfer_function,
cicp->matrix_coefficients,
cicp->full_range);
if (color_state)
{
g_debug ("Color state from cICP data: %s\n", gdk_color_state_get_name (color_state));
return color_state;
}
else
{
g_debug ("Failed to create color state from cICP data: %d/%d/%d %d\n",
cicp->color_primaries,
cicp->transfer_function,
cicp->matrix_coefficients,
cicp->full_range);
}
}
if (png_get_iCCP (png, info, &name, NULL, &icc_data, &icc_len))
{
GBytes *bytes = g_bytes_new (icc_data, icc_len);
color_state = gdk_color_state_new_from_icc_profile (bytes, NULL);
g_bytes_unref (bytes);
if (color_state)
return color_state;
}
if (png_get_sRGB (png, info, &intent))
return gdk_color_state_get_srgb ();
/* If neither of those is valid, the result is sRGB */
if (!png_get_valid (png, info, PNG_INFO_gAMA) &&
!png_get_valid (png, info, PNG_INFO_cHRM))
return gdk_color_state_get_srgb ();
if (!png_get_gAMA (png, info, &gamma))
gamma = 2.4;
if (!png_get_cHRM (png, info,
&whitepoint.x, &whitepoint.y,
&primaries.Red.x, &primaries.Red.y,
&primaries.Green.x, &primaries.Green.y,
&primaries.Blue.x, &primaries.Blue.y))
{
if (gamma == 2.4)
return gdk_color_state_get_srgb ();
whitepoint = (cmsCIExyY) { 0.3127, 0.3290, 1.0 };
primaries = (cmsCIExyYTRIPLE) {
{ 0.6400, 0.3300, 1.0 },
{ 0.3000, 0.6000, 1.0 },
{ 0.1500, 0.0600, 1.0 }
};
}
else
{
primaries.Red.Y = 1.0;
primaries.Green.Y = 1.0;
primaries.Blue.Y = 1.0;
}
curve = cmsBuildGamma (NULL, 1.0 / gamma);
lcms_profile = cmsCreateRGBProfile (&whitepoint,
&primaries,
(cmsToneCurve*[3]) { curve, curve, curve });
color_state = gdk_color_state_new_from_lcms_profile (lcms_profile);
/* FIXME: errors? */
if (color_state == NULL)
color_state = gdk_color_state_get_srgb ();
cmsFreeToneCurve (curve);
return color_state;
}
static void
gdk_png_set_color_state (png_struct *png,
png_info *info,
GdkColorState *color_state,
png_byte *chunk_data)
{
int cp, tc, mc;
gboolean fr;
if (gdk_color_state_save_to_cicp_data (color_state, &cp, &tc, &mc, &fr, NULL))
{
png_unknown_chunk chunk = {
.name = { 'c', 'I', 'C', 'P', '\0' },
.data = chunk_data,
.size = 4,
.location = PNG_HAVE_IHDR,
};
chunk_data[0] = (png_byte)cp;
chunk_data[1] = (png_byte)tc;
chunk_data[2] = (png_byte)mc;
chunk_data[3] = (png_byte)fr;
g_debug ("got cicp %d/%d/%d %d\n", cp, tc, mc, fr);
png_set_unknown_chunks (png, info, &chunk, 1);
}
else if (color_state == gdk_color_state_get_srgb ())
{
png_set_sRGB_gAMA_and_cHRM (png, info, /* FIXME */ PNG_sRGB_INTENT_PERCEPTUAL);
}
else
{
GBytes *bytes = gdk_color_state_save_to_icc_profile (color_state, NULL);
if (bytes)
{
png_set_iCCP (png, info,
"ICC profile",
0,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
g_bytes_unref (bytes);
}
}
}
/* }}} */
/* {{{ Public API */
@@ -147,8 +326,11 @@ gdk_load_png (GBytes *bytes,
guchar *buffer = NULL;
guchar **row_pointers = NULL;
GBytes *out_bytes;
GdkColorState *color_state;
GdkTexture *texture;
int bpp;
CICPData cicp = { FALSE, };
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
io.data = (guchar *)g_bytes_get_data (bytes, &io.size);
@@ -169,6 +351,7 @@ gdk_load_png (GBytes *bytes,
g_error ("Out of memory");
png_set_read_fn (png, &io, png_read_func);
png_set_read_user_chunk_fn (png, &cicp, png_read_chunk_func);
if (sigsetjmp (png_jmpbuf (png), 1))
{
@@ -266,6 +449,8 @@ gdk_load_png (GBytes *bytes,
return NULL;
}
color_state = gdk_png_get_color_state (png, info);
bpp = gdk_memory_format_bytes_per_pixel (format);
if (!g_size_checked_mul (&stride, width, bpp) ||
!g_size_checked_add (&stride, stride, (8 - stride % 8) % 8))
@@ -281,6 +466,7 @@ gdk_load_png (GBytes *bytes,
if (!buffer || !row_pointers)
{
gdk_color_state_unref (color_state);
g_free (buffer);
g_free (row_pointers);
png_destroy_read_struct (&png, &info, NULL);
@@ -297,8 +483,11 @@ gdk_load_png (GBytes *bytes,
png_read_end (png, info);
out_bytes = g_bytes_new_take (buffer, height * stride);
texture = gdk_memory_texture_new (width, height, format, out_bytes, stride);
texture = gdk_memory_texture_new_with_color_state (width, height,
format, color_state,
out_bytes, stride);
g_bytes_unref (out_bytes);
gdk_color_state_unref (color_state);
if (options && png_get_text (png, info, &text, &num_texts))
{
@@ -337,11 +526,14 @@ gdk_save_png (GdkTexture *texture)
GBytes *bytes;
gsize stride;
const guchar *data;
GdkColorState *color_state;
int png_format;
int depth;
png_byte chunk_data[4];
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
color_state = gdk_texture_get_color_state (texture);
format = gdk_texture_get_format (texture);
switch (format)
@@ -436,6 +628,8 @@ gdk_save_png (GdkTexture *texture)
/* 2^31-1 is the maximum size for PNG files */
png_set_user_limits (png, (1u << 31) - 1, (1u << 31) - 1);
png_set_keep_unknown_chunks (png, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0);
info = png_create_info_struct (png);
if (!info)
{
@@ -465,6 +659,8 @@ gdk_save_png (GdkTexture *texture)
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
gdk_png_set_color_state (png, info, color_state, chunk_data);
png_write_info (png, info);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN

View File

@@ -24,6 +24,7 @@
#include "gdkmemorytexture.h"
#include "gdkprofilerprivate.h"
#include "gdktexturedownloaderprivate.h"
#include "gdkcolorstate.h"
#include <tiffio.h>
@@ -219,6 +220,49 @@ tiff_open_write (GBytes **result)
NULL, NULL);
}
/* }}} */
/* {{{ Color profile handling */
static GdkColorState *
gdk_tiff_get_color_state (TIFF *tiff)
{
const char *icc_data;
guint icc_len;
if (TIFFGetField (tiff, TIFFTAG_ICCPROFILE, &icc_len, &icc_data))
{
GBytes *icc_bytes;
GdkColorState *color_state;
icc_bytes = g_bytes_new (icc_data, icc_len);
color_state = gdk_color_state_new_from_icc_profile (icc_bytes, NULL);
g_bytes_unref (icc_bytes);
if (color_state)
return color_state;
}
return gdk_color_state_get_srgb ();
}
static void
gdk_tiff_set_color_state (TIFF *tiff,
GdkColorState *color_state)
{
GBytes *bytes;
bytes = gdk_color_state_save_to_icc_profile (color_state, NULL);
if (bytes)
{
TIFFSetField (tiff, TIFFTAG_ICCPROFILE,
g_bytes_get_size (bytes),
g_bytes_get_data (bytes, NULL));
g_bytes_unref (bytes);
}
}
/* }}} */
/* {{{ Public API */
@@ -282,6 +326,7 @@ gdk_save_tiff (GdkTexture *texture)
GBytes *bytes, *result = NULL;
GdkTextureDownloader downloader;
GdkMemoryFormat format;
GdkColorState *color_state;
const FormatData *fdata = NULL;
tif = tiff_open_write (&result);
@@ -289,6 +334,7 @@ gdk_save_tiff (GdkTexture *texture)
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
format = gdk_texture_get_format (texture);
color_state = gdk_texture_get_color_state (texture);
fdata = &format_data[format];
if (fdata == NULL)
@@ -308,6 +354,8 @@ gdk_save_tiff (GdkTexture *texture)
TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, fdata->photometric);
TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
gdk_tiff_set_color_state (tif, color_state);
gdk_texture_downloader_init (&downloader, texture);
gdk_texture_downloader_set_format (&downloader, fdata->format);
bytes = gdk_texture_downloader_download_bytes (&downloader, &stride);
@@ -344,6 +392,7 @@ load_fallback (TIFF *tif,
int width, height;
guchar *data;
GBytes *bytes;
GdkColorState *color_state;
GdkTexture *texture;
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width);
@@ -360,12 +409,15 @@ load_fallback (TIFF *tif,
return NULL;
}
color_state = gdk_tiff_get_color_state (tif);
bytes = g_bytes_new_take (data, width * height * 4);
texture = gdk_memory_texture_new (width, height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
bytes,
width * 4);
texture = gdk_memory_texture_new_with_color_state (width, height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
color_state,
bytes,
width * 4);
g_bytes_unref (bytes);
@@ -390,6 +442,7 @@ gdk_load_tiff (GBytes *input_bytes,
gsize stride;
int bpp;
GBytes *bytes;
GdkColorState *color_state;
GdkTexture *texture;
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
@@ -490,13 +543,16 @@ gdk_load_tiff (GBytes *input_bytes,
line += stride;
}
color_state = gdk_tiff_get_color_state (tif);
bpp = gdk_memory_format_bytes_per_pixel (format);
bytes = g_bytes_new_take (data, width * height * bpp);
texture = gdk_memory_texture_new (width, height,
format,
bytes, width * bpp);
texture = gdk_memory_texture_new_with_color_state (width, height,
format, color_state,
bytes, width * bpp);
g_bytes_unref (bytes);
gdk_color_state_unref (color_state);
TIFFClose (tif);

View File

@@ -6,6 +6,8 @@ gdk_public_sources = files([
'gdkcairo.c',
'gdkcairocontext.c',
'gdkclipboard.c',
'gdkcolor.c',
'gdkcolorstate.c',
'gdkcontentdeserializer.c',
'gdkcontentformats.c',
'gdkcontentprovider.c',
@@ -75,6 +77,9 @@ gdk_public_headers = files([
'gdkcairo.h',
'gdkcairocontext.h',
'gdkclipboard.h',
'gdkcolor.h',
'gdkcolorimpl.h',
'gdkcolorstate.h',
'gdkcontentdeserializer.h',
'gdkcontentformats.h',
'gdkcontentprovider.h',
@@ -224,6 +229,7 @@ gdk_deps = [
fontconfig_dep,
platform_gio_dep,
pangocairo_dep,
lcms2_dep,
vulkan_dep,
libdrm_dep,
png_dep,

View File

@@ -158,6 +158,9 @@ gdk_wayland_cairo_context_begin_frame (GdkDrawContext *draw_context,
else
self->paint_surface = gdk_wayland_cairo_context_create_surface (self);
gdk_cairo_surface_set_color_state (self->paint_surface,
gdk_surface_get_color_state (gdk_draw_context_get_surface (draw_context)));
surface_region = gdk_wayland_cairo_context_surface_get_region (self->paint_surface);
if (surface_region)
cairo_region_union (region, surface_region);

View File

@@ -47,6 +47,7 @@ create_cairo_surface_for_surface (GdkSurface *surface,
cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32);
cairo_surface_set_device_scale (cairo_surface, scale, scale);
gdk_cairo_surface_set_color_state (cairo_surface, gdk_surface_get_color_state (surface));
return cairo_surface;
}

View File

@@ -49,6 +49,7 @@ create_cairo_surface_for_surface (GdkSurface *surface)
gdk_surface_get_width (surface) * scale,
gdk_surface_get_height (surface) * scale);
cairo_surface_set_device_scale (cairo_surface, scale, scale);
gdk_cairo_surface_set_color_state (cairo_surface, gdk_surface_get_color_state (surface));
return cairo_surface;
}

View File

@@ -1405,6 +1405,71 @@ gdk_x11_display_init_leader_surface (GdkX11Display *self)
self->leader_window_title_set = FALSE;
}
static void
voidXFree (gpointer data)
{
XFree (data);
}
static void
gdk_x11_display_check_color_state (GdkX11Display *self)
{
GdkDisplay *display = GDK_DISPLAY (self);
GdkX11Screen *screen;
char *atom_name;
Atom type;
int result;
int format;
gulong nitems;
gulong bytes_after;
guchar *data;
GBytes *bytes;
screen = self->screen;
if (screen->screen_num > 0)
atom_name = g_strdup_printf ("_ICC_PROFILE_%d", screen->screen_num);
else
atom_name = g_strdup ("_ICC_PROFILE");
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gdk_color_state_get_srgb ();
gdk_x11_display_error_trap_push (display);
result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
screen->xroot_window,
gdk_x11_get_xatom_by_name_for_display (display, atom_name),
0, G_MAXLONG, False, XA_CARDINAL, &type,
&format, &nitems,
&bytes_after, &data);
gdk_x11_display_error_trap_pop_ignored (display);
g_free (atom_name);
if (result != Success || type != XA_CARDINAL || nitems <= 0)
return;
switch (format)
{
case 8:
bytes = g_bytes_new_with_free_func (data, nitems, voidXFree, data);
break;
case 16:
bytes = g_bytes_new_with_free_func (data, sizeof (short) * nitems, voidXFree, data);
break;
case 32:
bytes = g_bytes_new_with_free_func (data, sizeof (long) * nitems, voidXFree, data);
break;
default:
XFree (data);
return;
}
g_clear_pointer (&self->color_state, gdk_color_state_unref);
self->color_state = gdk_color_state_new_from_icc_profile (bytes, NULL);
if (!self->color_state)
self->color_state = gdk_color_state_get_srgb ();
}
/**
* gdk_x11_display_open:
* @display_name: (nullable): name of the X display.
@@ -1475,6 +1540,9 @@ gdk_x11_display_open (const char *display_name)
/* initialize the display's screens */
display_x11->screen = _gdk_x11_screen_new (display, DefaultScreen (display_x11->xdisplay));
/* We want this for the leader surface already */
gdk_x11_display_check_color_state (display_x11);
/* If GL is available we want to pick better default/rgba visuals,
* as we care about GLX details such as alpha/depth/stencil depth,
* stereo and double buffering
@@ -1923,15 +1991,17 @@ gdk_x11_display_ungrab (GdkDisplay *display)
static void
gdk_x11_display_dispose (GObject *object)
{
GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
GdkX11Display *self = GDK_X11_DISPLAY (object);
if (display_x11->event_source)
if (self->event_source)
{
g_source_destroy (display_x11->event_source);
g_source_unref (display_x11->event_source);
display_x11->event_source = NULL;
g_source_destroy (self->event_source);
g_source_unref (self->event_source);
self->event_source = NULL;
}
g_clear_pointer (&self->color_state, gdk_color_state_unref);
G_OBJECT_CLASS (gdk_x11_display_parent_class)->dispose (object);
}

View File

@@ -127,6 +127,9 @@ struct _GdkX11Display
guint have_damage;
#endif
/* Stored in the ICC_PROFILE rootwindow prop */
GdkColorState *color_state;
/* If GL is not supported, store the error here */
GError *gl_error;

View File

@@ -926,6 +926,8 @@ setup_toplevel_window (GdkSurface *surface)
/* This will set WM_CLIENT_MACHINE and WM_LOCALE_NAME */
XSetWMProperties (xdisplay, xid, NULL, NULL, NULL, 0, NULL, NULL, NULL);
gdk_surface_set_color_state (surface, GDK_X11_DISPLAY (display)->color_state);
if (!gdk_running_in_sandbox ())
{
@@ -3136,7 +3138,7 @@ gdk_surface_update_icon (GdkSurface *surface,
toplevel->icon_pixmap = gdk_x11_surface_create_pixmap_surface (surface, width, height);
cairo_surface = gdk_texture_download_surface (best_icon);
cairo_surface = gdk_texture_download_surface (best_icon, gdk_color_state_get_srgb ());
cr = cairo_create (toplevel->icon_pixmap);
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);

View File

@@ -477,7 +477,7 @@ get_colorized_texture (GdkTexture *texture,
return g_object_ref (colorized->texture);
}
surface = gdk_texture_download_surface (texture);
surface = gdk_texture_download_surface (texture, gdk_color_state_get_srgb ());
image_surface = cairo_surface_map_to_image (surface, NULL);
data = cairo_image_surface_get_data (image_surface);
width = cairo_image_surface_get_width (image_surface);

View File

@@ -972,7 +972,7 @@ gsk_gl_driver_load_texture (GskGLDriver *self,
if (texture_id == 0)
{
downloaded_texture = gdk_memory_texture_from_texture (texture, gdk_texture_get_format (texture));
downloaded_texture = gdk_memory_texture_from_texture (texture);
/* The download_texture() call may have switched the GL context. Make sure
* the right context is at work again.
@@ -1471,8 +1471,7 @@ gsk_gl_driver_add_texture_slices (GskGLDriver *self,
}
slices = g_new0 (GskGLTextureSlice, n_slices);
memtex = gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture));
memtex = gdk_memory_texture_from_texture (texture);
if (ensure_mipmap)
{

View File

@@ -281,9 +281,11 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self,
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
gdk_color_state_get_srgb (),
cairo_image_surface_get_data (surface),
stride,
GDK_MEMORY_DEFAULT,
gdk_color_state_get_srgb (),
width, height);
stride = width * 4;
gl_format = GL_RGBA;

View File

@@ -106,7 +106,7 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
icon_data->source_texture = g_object_ref (key);
/* actually upload the texture */
surface = gdk_texture_download_surface (key);
surface = gdk_texture_download_surface (key, gdk_color_state_get_srgb ());
surface_data = cairo_image_surface_get_data (surface);
gdk_gl_context_push_debug_group_printf (gdk_gl_context_get_current (),
"Uploading texture");
@@ -116,8 +116,11 @@ gsk_gl_icon_library_add (GskGLIconLibrary *self,
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
gdk_color_state_get_srgb (),
surface_data, cairo_image_surface_get_stride (surface),
GDK_MEMORY_DEFAULT, width, height);
GDK_MEMORY_DEFAULT,
gdk_texture_get_color_state (key),
width, height);
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
}

View File

@@ -104,6 +104,7 @@ static void
gsk_gl_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader_,
GdkDmabufTexture *texture,
GdkMemoryFormat format,
GdkColorState *color_state,
guchar *data,
gsize stride)
{
@@ -125,6 +126,7 @@ gsk_gl_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader_,
downloader = gdk_texture_downloader_new (native);
gdk_texture_downloader_set_format (downloader, format);
gdk_texture_downloader_set_color_state (downloader, color_state);
gdk_texture_downloader_download_into (downloader, data, stride);
gdk_texture_downloader_free (downloader);

View File

@@ -57,6 +57,8 @@
#define MAX_GRADIENT_STOPS 6
#define SHADOW_EXTRA_SIZE 4
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* Make sure gradient stops fits in packed array_count */
G_STATIC_ASSERT ((MAX_GRADIENT_STOPS * 5) < (1 << GSK_GL_UNIFORM_ARRAY_BITS));
@@ -300,6 +302,7 @@ node_supports_2d_transform (const GskRenderNode *node)
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
case GSK_SUBSURFACE_NODE:
case GSK_COLOR_STATE_NODE:
return TRUE;
case GSK_SHADOW_NODE:
@@ -357,6 +360,7 @@ node_supports_transform (const GskRenderNode *node)
case GSK_FILL_NODE:
case GSK_STROKE_NODE:
case GSK_SUBSURFACE_NODE:
case GSK_COLOR_STATE_NODE:
return TRUE;
case GSK_SHADOW_NODE:
@@ -4228,6 +4232,10 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
gsk_gl_render_job_visit_subsurface_node (job, node);
break;
case GSK_COLOR_STATE_NODE:
gsk_gl_render_job_visit_node (job, gsk_color_state_node_get_child (node));
break;
case GSK_NOT_A_RENDER_NODE:
default:
g_assert_not_reached ();

View File

@@ -6,6 +6,7 @@
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gskgpucolorconvertopprivate.h"
#include "gpu/shaders/gskgpublendmodeinstance.h"
@@ -23,11 +24,13 @@ gsk_gpu_blend_mode_op_print_instance (GskGpuShaderOp *shader,
{
GskGpuBlendmodeInstance *instance = (GskGpuBlendmodeInstance *) instance_;
gsk_gpu_print_enum (string, GSK_TYPE_BLEND_MODE, shader->variation);
gsk_gpu_print_enum (string, GSK_TYPE_BLEND_MODE, shader->variation & 0xff);
gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->bottom_id);
gsk_gpu_print_enum (string, GSK_TYPE_BLEND_MODE, shader->variation);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->top_id);
if ((shader->variation >> 8) != 0)
gsk_gpu_print_color_conversion_triple (string, shader->variation >> 8);
}
static const GskGpuShaderOpClass GSK_GPU_BLEND_MODE_OP_CLASS = {
@@ -54,6 +57,7 @@ static const GskGpuShaderOpClass GSK_GPU_BLEND_MODE_OP_CLASS = {
void
gsk_gpu_blend_mode_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *target_color_state,
GskGpuDescriptors *desc,
const graphene_rect_t *rect,
const graphene_point_t *offset,
@@ -61,14 +65,19 @@ gsk_gpu_blend_mode_op (GskGpuFrame *frame,
GskBlendMode blend_mode,
guint32 bottom_descriptor,
const graphene_rect_t *bottom_rect,
GdkColorState *bottom_color_state,
guint32 top_descriptor,
const graphene_rect_t *top_rect)
const graphene_rect_t *top_rect,
GdkColorState *top_color_state)
{
GskGpuBlendmodeInstance *instance;
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_BLEND_MODE_OP_CLASS,
blend_mode,
blend_mode |
(gsk_gpu_color_conversion_triple (bottom_color_state,
top_color_state,
target_color_state) << 8),
clip,
desc,
&instance);

View File

@@ -8,15 +8,18 @@ G_BEGIN_DECLS
void gsk_gpu_blend_mode_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *target_color_state,
GskGpuDescriptors *desc,
const graphene_rect_t *rect,
const graphene_point_t *offset,
float opacity,
GskBlendMode blend_mode,
guint32 start_descriptor,
const graphene_rect_t *start_rect,
guint32 end_descriptor,
const graphene_rect_t *end_rect);
guint32 bottom_descriptor,
const graphene_rect_t *bottom_rect,
GdkColorState *bottom_color_state,
guint32 top_descriptor,
const graphene_rect_t *top_rect,
GdkColorState *top_color_state);
G_END_DECLS

View File

@@ -62,7 +62,7 @@ gsk_gpu_blur_op_full (GskGpuFrame *frame,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
const graphene_vec2_t *blur_direction,
const GdkRGBA *blur_color)
const GdkColor *blur_color)
{
GskGpuBlurInstance *instance;
@@ -76,7 +76,7 @@ gsk_gpu_blur_op_full (GskGpuFrame *frame,
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_rect_to_float (tex_rect, offset, instance->tex_rect);
graphene_vec2_to_float (blur_direction, instance->blur_direction);
gsk_gpu_rgba_to_float (blur_color, instance->blur_color);
gsk_gpu_color_to_float (blur_color, instance->blur_color);
instance->tex_id = descriptor;
}
@@ -90,6 +90,10 @@ gsk_gpu_blur_op (GskGpuFrame *frame,
const graphene_rect_t *tex_rect,
const graphene_vec2_t *blur_direction)
{
GdkColor color;
gdk_color_init_from_rgba (&color, &GDK_RGBA_TRANSPARENT);
gsk_gpu_blur_op_full (frame,
0,
clip,
@@ -99,7 +103,7 @@ gsk_gpu_blur_op (GskGpuFrame *frame,
offset,
tex_rect,
blur_direction,
&GDK_RGBA_TRANSPARENT);
&color);
}
void
@@ -111,7 +115,7 @@ gsk_gpu_blur_shadow_op (GskGpuFrame *frame,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
const graphene_vec2_t *blur_direction,
const GdkRGBA *shadow_color)
const GdkColor *shadow_color)
{
gsk_gpu_blur_op_full (frame,
VARIATION_COLORIZE,

View File

@@ -23,7 +23,7 @@ void gsk_gpu_blur_shadow_op (GskGpuF
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
const graphene_vec2_t *blur_direction,
const GdkRGBA *shadow_color);
const GdkColor *shadow_color);
G_END_DECLS

View File

@@ -20,8 +20,10 @@ static gboolean
color_equal (const float *color1,
const float *color2)
{
return gdk_rgba_equal (&(GdkRGBA) { color1[0], color1[1], color1[2], color1[3] },
&(GdkRGBA) { color2[0], color2[1], color2[2], color2[3] });
return color1[0] == color2[0] &&
color1[1] == color2[1] &&
color1[2] == color2[2] &&
color1[3] == color2[3];
}
static void
@@ -100,7 +102,7 @@ gsk_gpu_border_op (GskGpuFrame *frame,
const graphene_point_t *offset,
const graphene_point_t *inside_offset,
const float widths[4],
const GdkRGBA colors[4])
const GdkColor colors[4])
{
GskGpuBorderInstance *instance;
guint i;
@@ -117,7 +119,7 @@ gsk_gpu_border_op (GskGpuFrame *frame,
for (i = 0; i < 4; i++)
{
instance->border_widths[i] = widths[i];
gsk_gpu_rgba_to_float (&colors[i], &instance->border_colors[4 * i]);
gsk_gpu_color_to_float (&colors[i], &instance->border_colors[4 * i]);
}
instance->offset[0] = inside_offset->x;
instance->offset[1] = inside_offset->y;

View File

@@ -13,7 +13,7 @@ void gsk_gpu_border_op (GskGpuF
const graphene_point_t *offset,
const graphene_point_t *inside_offset,
const float widths[4],
const GdkRGBA colors[4]);
const GdkColor colors[4]);
G_END_DECLS

View File

@@ -82,7 +82,7 @@ gsk_gpu_box_shadow_op (GskGpuFrame *frame,
float spread,
float blur_radius,
const graphene_point_t *offset,
const GdkRGBA *color)
const GdkColor *color)
{
GskGpuBoxshadowInstance *instance;
@@ -98,7 +98,7 @@ gsk_gpu_box_shadow_op (GskGpuFrame *frame,
gsk_gpu_rect_to_float (bounds, offset, instance->bounds);
gsk_rounded_rect_to_float (outline, offset, instance->outline);
gsk_gpu_rgba_to_float (color, instance->color);
gsk_gpu_color_to_float (color, instance->color);
instance->shadow_offset[0] = shadow_offset->x;
instance->shadow_offset[1] = shadow_offset->y;
instance->shadow_spread = spread;

View File

@@ -16,7 +16,7 @@ void gsk_gpu_box_shadow_op (
float spread,
float blur_radius,
const graphene_point_t *offset,
const GdkRGBA *color);
const GdkColor *color);
G_END_DECLS

View File

@@ -4,8 +4,6 @@
#include "gskgpuopprivate.h"
#include "gskgpuprintprivate.h"
/* for gsk_gpu_rgba_to_float() */
#include "gskgpushaderopprivate.h"
typedef struct _GskGpuClearOp GskGpuClearOp;
@@ -14,7 +12,7 @@ struct _GskGpuClearOp
GskGpuOp op;
cairo_rectangle_int_t rect;
GdkRGBA color;
float color[4];
};
static void
@@ -29,21 +27,19 @@ gsk_gpu_clear_op_print (GskGpuOp *op,
guint indent)
{
GskGpuClearOp *self = (GskGpuClearOp *) op;
float rgba[4];
gsk_gpu_print_op (string, indent, "clear");
gsk_gpu_print_int_rect (string, &self->rect);
gsk_gpu_rgba_to_float (&self->color, rgba);
gsk_gpu_print_rgba (string, rgba);
gsk_gpu_print_rgba (string, self->color);
gsk_gpu_print_newline (string);
}
#ifdef GDK_RENDERING_VULKAN
static void
gsk_gpu_init_clear_value (VkClearValue *value,
const GdkRGBA *rgba)
gsk_gpu_init_clear_value (VkClearValue *value,
const float color[4])
{
gsk_gpu_rgba_to_float (rgba, value->color.float32);
memcpy (value->color.float32, color, sizeof (float) * 4);
}
static GskGpuOp *
@@ -54,7 +50,7 @@ gsk_gpu_clear_op_vk_command (GskGpuOp *op,
GskGpuClearOp *self = (GskGpuClearOp *) op;
VkClearValue clear_value;
gsk_gpu_init_clear_value (&clear_value, &self->color);
gsk_gpu_init_clear_value (&clear_value, self->color);
vkCmdClearAttachments (state->vk_command_buffer,
1,
@@ -92,7 +88,7 @@ gsk_gpu_clear_op_gl_command (GskGpuOp *op,
else
glScissor (self->rect.x, self->rect.y, self->rect.width, self->rect.height);
glClearColor (self->color.red, self->color.green, self->color.blue, self->color.alpha);
glClearColor (self->color[0], self->color[1], self->color[2], self->color[3]);
glClear (GL_COLOR_BUFFER_BIT);
glScissor (scissor[0], scissor[1], scissor[2], scissor[3]);
@@ -114,12 +110,12 @@ static const GskGpuOpClass GSK_GPU_CLEAR_OP_CLASS = {
void
gsk_gpu_clear_op (GskGpuFrame *frame,
const cairo_rectangle_int_t *rect,
const GdkRGBA *color)
const GdkColor *color)
{
GskGpuClearOp *self;
self = (GskGpuClearOp *) gsk_gpu_op_alloc (frame, &GSK_GPU_CLEAR_OP_CLASS);
self->rect = *rect;
self->color = *color;
memcpy (self->color, color->values, sizeof (float) * 4);
}

View File

@@ -6,7 +6,7 @@ G_BEGIN_DECLS
void gsk_gpu_clear_op (GskGpuFrame *frame,
const cairo_rectangle_int_t *rect,
const GdkRGBA *color);
const GdkColor *color);
G_END_DECLS

View File

@@ -0,0 +1,112 @@
#include "config.h"
#include "gskgpucolorconvertopprivate.h"
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gpu/shaders/gskgpucolorconvertinstance.h"
typedef struct _GskGpuColorConvertOp GskGpuColorConvertOp;
struct _GskGpuColorConvertOp
{
GskGpuShaderOp op;
};
static void
gsk_gpu_color_convert_op_print_instance (GskGpuShaderOp *shader,
gpointer instance_,
GString *string)
{
GskGpuColorconvertInstance *instance = (GskGpuColorconvertInstance *) instance_;
gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->tex_id);
gsk_gpu_print_color_conversion (string, shader->variation);
}
static const GskGpuShaderOpClass GSK_GPU_COLOR_CONVERT_OP_CLASS = {
{
GSK_GPU_OP_SIZE (GskGpuColorConvertOp),
GSK_GPU_STAGE_SHADER,
gsk_gpu_shader_op_finish,
gsk_gpu_shader_op_print,
#ifdef GDK_RENDERING_VULKAN
gsk_gpu_shader_op_vk_command,
#endif
gsk_gpu_shader_op_gl_command
},
"gskgpucolorconvert",
sizeof (GskGpuColorconvertInstance),
#ifdef GDK_RENDERING_VULKAN
&gsk_gpu_colorconvert_info,
#endif
gsk_gpu_color_convert_op_print_instance,
gsk_gpu_colorconvert_setup_attrib_locations,
gsk_gpu_colorconvert_setup_vao
};
void
gsk_gpu_color_convert_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *from,
GdkColorState *to,
GskGpuDescriptors *desc,
guint32 descriptor,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect)
{
GskGpuColorconvertInstance *instance;
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_COLOR_CONVERT_OP_CLASS,
gsk_gpu_color_conversion (from, to),
clip,
desc,
&instance);
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_rect_to_float (tex_rect, offset, instance->tex_rect);
instance->tex_id = descriptor;
}
guint
gsk_gpu_color_conversion (GdkColorState *from,
GdkColorState *to)
{
if (from == to)
return 0;
if (!GDK_IS_NAMED_COLOR_STATE (from) || !GDK_IS_NAMED_COLOR_STATE (to))
{
g_warning ("FIXME: Implement support for ICC color transforms");
return 0;
}
return GDK_NAMED_COLOR_STATE_ID (from) |
(GDK_NAMED_COLOR_STATE_ID (to) << 16);
}
guint
gsk_gpu_color_conversion_triple (GdkColorState *from1,
GdkColorState *from2,
GdkColorState *to)
{
if (from1 == to && from2 == to)
return 0;
if (!GDK_IS_NAMED_COLOR_STATE (from1) ||
!GDK_IS_NAMED_COLOR_STATE (from2) ||
!GDK_IS_NAMED_COLOR_STATE (to))
{
g_warning ("FIXME: Implement support for ICC color transforms");
return 0;
}
return GDK_NAMED_COLOR_STATE_ID (from1) |
(GDK_NAMED_COLOR_STATE_ID (from2) << 5) |
(GDK_NAMED_COLOR_STATE_ID (to) << 10);
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include "gskgpushaderopprivate.h"
#include <graphene.h>
G_BEGIN_DECLS
void gsk_gpu_color_convert_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *from,
GdkColorState *to,
GskGpuDescriptors *desc,
guint32 descriptor,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect);
/* For lack of a better place */
guint gsk_gpu_color_conversion (GdkColorState *from,
GdkColorState *to);
guint gsk_gpu_color_conversion_triple (GdkColorState *from1,
GdkColorState *from2,
GdkColorState *to);
G_END_DECLS

View File

@@ -56,7 +56,7 @@ gsk_gpu_colorize_op (GskGpuFrame *frame,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
const GdkRGBA *color)
const GdkColor *color)
{
GskGpuColorizeInstance *instance;
@@ -70,5 +70,5 @@ gsk_gpu_colorize_op (GskGpuFrame *frame,
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_rect_to_float (tex_rect, offset, instance->tex_rect);
instance->tex_id = descriptor;
gsk_gpu_rgba_to_float (color, instance->color);
gsk_gpu_color_to_float (color, instance->color);
}

View File

@@ -13,7 +13,7 @@ void gsk_gpu_colorize_op (GskGpuF
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
const GdkRGBA *color);
const GdkColor *color);
G_END_DECLS

View File

@@ -5,6 +5,7 @@
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gskgpucolorconvertopprivate.h"
#include "gpu/shaders/gskgpucolormatrixinstance.h"
@@ -24,6 +25,8 @@ gsk_gpu_color_matrix_op_print_instance (GskGpuShaderOp *shader,
gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->tex_id);
if (shader->variation != 0)
gsk_gpu_print_color_conversion (string, shader->variation);
}
static const GskGpuShaderOpClass GSK_GPU_COLOR_MATRIX_OP_CLASS = {
@@ -55,6 +58,8 @@ gsk_gpu_color_matrix_op (GskGpuFrame *frame,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
GdkColorState *from,
GdkColorState *to,
const graphene_matrix_t *color_matrix,
const graphene_vec4_t *color_offset)
{
@@ -62,7 +67,7 @@ gsk_gpu_color_matrix_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_COLOR_MATRIX_OP_CLASS,
0,
gsk_gpu_color_conversion (from, to),
clip,
desc,
&instance);
@@ -82,6 +87,8 @@ gsk_gpu_color_matrix_op_opacity (GskGpuFrame *frame,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
GdkColorState *from,
GdkColorState *to,
float opacity)
{
graphene_matrix_t matrix;
@@ -101,6 +108,8 @@ gsk_gpu_color_matrix_op_opacity (GskGpuFrame *frame,
rect,
offset,
tex_rect,
from,
to,
&matrix,
graphene_vec4_zero ());
}

View File

@@ -13,6 +13,8 @@ void gsk_gpu_color_matrix_op (GskGpuF
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
GdkColorState *from,
GdkColorState *to,
const graphene_matrix_t *color_matrix,
const graphene_vec4_t *color_offset);
@@ -23,6 +25,8 @@ void gsk_gpu_color_matrix_op_opacity (GskGpuF
const graphene_rect_t *rect,
const graphene_point_t *offset,
const graphene_rect_t *tex_rect,
GdkColorState *from,
GdkColorState *to,
float opacity);
G_END_DECLS

View File

@@ -53,7 +53,7 @@ gsk_gpu_color_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const GdkRGBA *color)
const GdkColor *color)
{
GskGpuColorInstance *instance;
@@ -65,5 +65,5 @@ gsk_gpu_color_op (GskGpuFrame *frame,
&instance);
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_rgba_to_float (color, instance->color);
gsk_gpu_color_to_float (color, instance->color);
}

View File

@@ -10,7 +10,7 @@ void gsk_gpu_color_op (GskGpuF
GskGpuShaderClip clip,
const graphene_rect_t *rect,
const graphene_point_t *offset,
const GdkRGBA *color);
const GdkColor *color);
G_END_DECLS

View File

@@ -5,6 +5,10 @@
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gskgpucolorconvertopprivate.h"
#include "gskgpulineargradientopprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#include "gpu/shaders/gskgpuconicgradientinstance.h"
@@ -25,6 +29,8 @@ gsk_gpu_conic_gradient_op_print_instance (GskGpuShaderOp *shader,
GskGpuConicgradientInstance *instance = (GskGpuConicgradientInstance *) instance_;
gsk_gpu_print_rect (string, instance->rect);
if ((shader->variation >> 1) != 0)
gsk_gpu_print_color_conversion (string, shader->variation >> 1);
}
static const GskGpuShaderOpClass GSK_GPU_CONIC_GRADIENT_OP_CLASS = {
@@ -55,7 +61,10 @@ gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
const graphene_point_t *center,
float angle,
const graphene_point_t *offset,
const GskColorStop *stops,
GdkColorState *in,
GdkColorState *target,
GskHueInterpolation hue_interp,
const GskColorStop2 *stops,
gsize n_stops)
{
GskGpuConicgradientInstance *instance;
@@ -65,7 +74,8 @@ gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_CONIC_GRADIENT_OP_CLASS,
(gsk_gpu_frame_should_optimize (frame, GSK_GPU_OPTIMIZE_GRADIENTS) ? VARIATION_SUPERSAMPLING : 0),
(gsk_gpu_frame_should_optimize (frame, GSK_GPU_OPTIMIZE_GRADIENTS) ? VARIATION_SUPERSAMPLING : 0) |
(gsk_gpu_color_conversion (in, target) << 1),
clip,
NULL,
&instance);
@@ -73,18 +83,30 @@ gsk_gpu_conic_gradient_op (GskGpuFrame *frame,
gsk_gpu_rect_to_float (rect, offset, instance->rect);
gsk_gpu_point_to_float (center, offset, instance->center);
instance->angle = angle;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 6)].color, instance->color6);
gsk_gpu_convert_color_to_float (&stops[MIN (n_stops - 1, 6)].color, in, instance->color6);
instance->offsets1[2] = stops[MIN (n_stops - 1, 6)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 5)].color, instance->color5);
gsk_gpu_convert_color_to_float (&stops[MIN (n_stops - 1, 5)].color, in, instance->color5);
instance->offsets1[1] = stops[MIN (n_stops - 1, 5)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 4)].color, instance->color4);
gsk_gpu_convert_color_to_float (&stops[MIN (n_stops - 1, 4)].color, in, instance->color4);
instance->offsets1[0] = stops[MIN (n_stops - 1, 4)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 3)].color, instance->color3);
gsk_gpu_convert_color_to_float (&stops[MIN (n_stops - 1, 3)].color, in, instance->color3);
instance->offsets0[3] = stops[MIN (n_stops - 1, 3)].offset;
gsk_gpu_rgba_to_float (&stops[MIN (n_stops - 1, 2)].color, instance->color2);
gsk_gpu_convert_color_to_float (&stops[MIN (n_stops - 1, 2)].color, in, instance->color2);
instance->offsets0[2] = stops[MIN (n_stops - 1, 2)].offset;
gsk_gpu_rgba_to_float (&stops[1].color, instance->color1);
gsk_gpu_convert_color_to_float (&stops[1].color, in, instance->color1);
instance->offsets0[1] = stops[1].offset;
gsk_gpu_rgba_to_float (&stops[0].color, instance->color0);
gsk_gpu_convert_color_to_float (&stops[0].color, in, instance->color0);
instance->offsets0[0] = stops[0].offset;
int hue_coord = gdk_color_state_get_hue_coord (in);
if (hue_coord != -1)
{
gsk_adjust_hue (hue_interp, &instance->color0[hue_coord], &instance->color1[hue_coord]);
gsk_adjust_hue (hue_interp, &instance->color1[hue_coord], &instance->color2[hue_coord]);
gsk_adjust_hue (hue_interp, &instance->color2[hue_coord], &instance->color3[hue_coord]);
gsk_adjust_hue (hue_interp, &instance->color3[hue_coord], &instance->color4[hue_coord]);
gsk_adjust_hue (hue_interp, &instance->color4[hue_coord], &instance->color5[hue_coord]);
gsk_adjust_hue (hue_interp, &instance->color5[hue_coord], &instance->color6[hue_coord]);
}
}

View File

@@ -14,7 +14,10 @@ void gsk_gpu_conic_gradient_op (GskGpuF
const graphene_point_t *center,
float angle,
const graphene_point_t *offset,
const GskColorStop *stops,
GdkColorState *in,
GdkColorState *target,
GskHueInterpolation hue_interp,
const GskColorStop2 *stops,
gsize n_stops);

View File

@@ -5,6 +5,7 @@
#include "gskgpuframeprivate.h"
#include "gskgpuprintprivate.h"
#include "gskrectprivate.h"
#include "gskgpucolorconvertopprivate.h"
#include "gpu/shaders/gskgpucrossfadeinstance.h"
@@ -25,7 +26,9 @@ gsk_gpu_cross_fade_op_print_instance (GskGpuShaderOp *shader,
gsk_gpu_print_rect (string, instance->rect);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->start_id);
gsk_gpu_print_image_descriptor (string, shader->desc, instance->end_id);
g_string_append_printf (string, "%g%%", 100 * instance->opacity_progress[1]);
g_string_append_printf (string, "%g%% ", 100 * instance->opacity_progress[1]);
if (shader->variation != 0)
gsk_gpu_print_color_conversion_triple (string, shader->variation);
}
static const GskGpuShaderOpClass GSK_GPU_CROSS_FADE_OP_CLASS = {
@@ -52,6 +55,7 @@ static const GskGpuShaderOpClass GSK_GPU_CROSS_FADE_OP_CLASS = {
void
gsk_gpu_cross_fade_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *target_color_state,
GskGpuDescriptors *desc,
const graphene_rect_t *rect,
const graphene_point_t *offset,
@@ -59,14 +63,18 @@ gsk_gpu_cross_fade_op (GskGpuFrame *frame,
float progress,
guint32 start_descriptor,
const graphene_rect_t *start_rect,
GdkColorState *start_color_state,
guint32 end_descriptor,
const graphene_rect_t *end_rect)
const graphene_rect_t *end_rect,
GdkColorState *end_color_state)
{
GskGpuCrossfadeInstance *instance;
gsk_gpu_shader_op_alloc (frame,
&GSK_GPU_CROSS_FADE_OP_CLASS,
0,
gsk_gpu_color_conversion_triple (start_color_state,
end_color_state,
target_color_state),
clip,
desc,
&instance);

View File

@@ -8,6 +8,7 @@ G_BEGIN_DECLS
void gsk_gpu_cross_fade_op (GskGpuFrame *frame,
GskGpuShaderClip clip,
GdkColorState *target_color_state,
GskGpuDescriptors *desc,
const graphene_rect_t *rect,
const graphene_point_t *offset,
@@ -15,8 +16,10 @@ void gsk_gpu_cross_fade_op (GskGpuF
float progress,
guint32 start_descriptor,
const graphene_rect_t *start_rect,
GdkColorState *start_color_state,
guint32 end_descriptor,
const graphene_rect_t *end_rect);
const graphene_rect_t *end_rect,
GdkColorState *end_color_state);
G_END_DECLS

View File

@@ -12,6 +12,7 @@
#include "gsk/gskdebugprivate.h"
#include "gsk/gskprivate.h"
#include "gdk/gdkcolorstateprivate.h"
#define MAX_SLICES_PER_ATLAS 64
@@ -325,9 +326,9 @@ gsk_gpu_cached_texture_destroy_cb (gpointer data)
}
static GskGpuCachedTexture *
gsk_gpu_cached_texture_new (GskGpuDevice *device,
GdkTexture *texture,
GskGpuImage *image)
gsk_gpu_cached_texture_new (GskGpuDevice *device,
GdkTexture *texture,
GskGpuImage *image)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (device);
GskGpuCachedTexture *self;
@@ -850,9 +851,9 @@ gsk_gpu_device_add_atlas_image (GskGpuDevice *self,
}
GskGpuImage *
gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp)
gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp)
{
GskGpuDevicePrivate *priv = gsk_gpu_device_get_instance_private (self);
GskGpuCachedTexture *cache;
@@ -861,7 +862,7 @@ gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
if (cache == NULL)
cache = g_hash_table_lookup (priv->texture_cache, texture);
if (!cache || !cache->image || gsk_gpu_cached_texture_is_invalid (cache))
if (!cache || cache->image == NULL || gsk_gpu_cached_texture_is_invalid (cache))
return NULL;
gsk_gpu_cached_use (self, (GskGpuCached *) cache, timestamp);
@@ -870,10 +871,10 @@ gsk_gpu_device_lookup_texture_image (GskGpuDevice *self,
}
void
gsk_gpu_device_cache_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp,
GskGpuImage *image)
gsk_gpu_device_cache_texture_image (GskGpuDevice *self,
GdkTexture *texture,
gint64 timestamp,
GskGpuImage *image)
{
GskGpuCachedTexture *cache;
@@ -969,6 +970,7 @@ gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,
gsk_gpu_upload_glyph_op (frame,
cache->image,
(flags & GSK_GPU_GLYPH_LINEAR) != 0,
scaled_font,
glyph,
&(cairo_rectangle_int_t) {

View File

@@ -86,7 +86,8 @@ typedef enum
GSK_GPU_GLYPH_X_OFFSET_3 = 0x3,
GSK_GPU_GLYPH_Y_OFFSET_1 = 0x4,
GSK_GPU_GLYPH_Y_OFFSET_2 = 0x8,
GSK_GPU_GLYPH_Y_OFFSET_3 = 0xC
GSK_GPU_GLYPH_Y_OFFSET_3 = 0xC,
GSK_GPU_GLYPH_LINEAR = 0x10,
} GskGpuGlyphLookupFlags;
GskGpuImage * gsk_gpu_device_lookup_glyph_image (GskGpuDevice *self,

Some files were not shown because too many files have changed in this diff Show More