Compare commits

..

51 Commits

Author SHA1 Message Date
Matthias Clasen
6cb3300009 Add a test for color conversion 2022-09-30 20:57:52 -04:00
Matthias Clasen
fde2fefbcd testsuite: Compare textures properly
When compoaring textures, we now need to look
at the colorspace as well.
2022-09-30 14:42:03 -04:00
Matthias Clasen
b6eb23afa7 widget-factory: Add an hdr image example
This uses the heif loader to show an image in
the 'color profile' notebook. The current image
isn't a very good HDR example, and should be
replaced by a more suitable image.
2022-09-30 14:42:03 -04:00
Matthias Clasen
17b7e9819b Add a quick-and-dirty heif loading test
This uses libheif to load an image and produce
a texture. If the image has more than 8 bits of
chroma or luma, the texture will be 16bit.
2022-09-30 14:42:03 -04:00
Matthias Clasen
966a150d19 Add libheif to the build 2022-09-30 14:42:03 -04:00
Matthias Clasen
1b83c44994 wip: Add a cicp color space implementation
This is a bit preliminary. It can't handle
HDR formats yet.
2022-09-30 14:42:03 -04:00
Matthias Clasen
6e75db713c wip: update testsuite for changed compositing 2022-09-30 14:42:03 -04:00
Matthias Clasen
82b45004c2 gsk: Add color space in gsk_renderer_render_texture
Make gsk_renderer_render_texture produce a texture
that has the correct color space attached. This
fixes the rendering of node files in the node editor.
2022-09-30 14:42:03 -04:00
Matthias Clasen
31b9e8dca6 gdk: Introduce GdkColor
GdkColor represents a color in the real world, by combining a color
profile, an alpha value and N component values.

gsk_render_node_draw() has been ported to use GdkColor when rendering,
which makes it so the rendering happens in a color-managed way when a
color profile has been attached to the target.
2022-09-30 14:42:03 -04:00
Matthias Clasen
623cdaf485 media: Use the new GL texture constructor
Use GdkGLTextureFlags in the gstreamer backend
to tell gsk that the buffers are unpremultiplied,
non-linear sRGB.
2022-09-30 14:42:03 -04:00
Matthias Clasen
77280d258a glarea: Use the new GL texture constructor
This lets us avoid doing the flipping in snapshot.
We can just tell gsk to do it for us.
2022-09-30 14:42:03 -04:00
Matthias Clasen
80bf2336c9 gsk: Use GL texture information
Use the flags and color space information from
GL textures to figure out what conversions we need
to do on them.
2022-09-30 14:42:03 -04:00
Matthias Clasen
55179c450b API: Add a new constructor for GL textures
Add a constructor that lets us provide more information
about the content of a GL texture, such as the color
profile, and whether it is premultiplied or flipped.
2022-09-30 14:42:03 -04:00
Matthias Clasen
f7268a5c52 gsk: Support flipping gl textures
Add upside-down flipping to the list of supported
conversions when handling GL textures.
2022-09-30 14:42:03 -04:00
Matthias Clasen
0e0bb92ff9 gsk: Do texture conversions in shaders
Do linearization and premultiplication of textures
in a shader after uploading the unconverted data.
This moves move work from the cpu to the gpu.

Conversions between other color spaces are still
done with lcms on the cpu.
2022-09-30 14:42:03 -04:00
Matthias Clasen
616a9e1804 gsk: Refactor a bit 2022-09-30 14:42:03 -04:00
Matthias Clasen
7371840772 gsk: Fix caching of textures 2022-09-30 14:42:03 -04:00
Matthias Clasen
ca062df561 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.
2022-09-30 14:42:03 -04:00
Matthias Clasen
b09c642c98 gsk: 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.
2022-09-30 14:42:03 -04:00
Matthias Clasen
830892e1b7 gsk: Linearize gl textures
GL textures are typically in non-linear sRGB,
and in that case, we need to linearize them.
2022-09-30 14:42:03 -04:00
Matthias Clasen
fda050e4fa gsk: Linearize colors too
Convert all the GdkRGBA colors that we have
in render nodes to linear sRGB before using
them. This brings the rendering back in line
with what cairo produces, except for the video.
2022-09-30 14:42:03 -04:00
Matthias Clasen
7e91c156fe gsk: Apply gamma to frames
Use a shader to go from linear sRGB to sRGB when
we are done with a frame.
2022-09-30 14:42:03 -04:00
Matthias Clasen
d9e6e92a64 gsk: Upload textures in linear sRGB
We want to do compositing in a linear color space,
so convert textures to linear sRGB before uploading.

Currently, this causes images to come out dark, since
we don't have a way to tell the compositor that our
framebuffer is linear, so it assumes a gamma that we
don't provide.
2022-09-30 14:42:03 -04:00
Benjamin Otte
ff78a913d7 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.
2022-09-30 14:42:03 -04:00
Benjamin Otte
91ffa97874 Add crude color management impl for cairo 2022-09-30 14:42:03 -04:00
Benjamin Otte
3ce7556235 x11: Implement support for color profiles
Stole the implementation from eog.

This doesn't yet update the profile when it changes though.
2022-09-30 14:42:03 -04:00
Matthias Clasen
2880a9c80f Support color space in pixbufs
When creating a GdkTexture from a GdkPixbuf,
see if it has an icc profile attached, and if
so, use it.
2022-09-30 14:42:03 -04:00
Benjamin Otte
f0e2e58939 widget-factory: Add tests for loading color profiles
I figured out how to generate them, yay:

  cmsHPROFILE lcms_profile;
  cmsToneCurve *curve[3];

  curve[0] = cmsBuildParametricToneCurve (NULL, 4, (double[5]) { 1.0, 0, 0, 0, 0 });
  curve[1] = cmsBuildParametricToneCurve (NULL, 4, (double[5]) { 2.4, 255.0 / 15 / 1.055, 0.055 / 1.055, 0, 15./255 });
  curve[2] = cmsBuildGamma (NULL, 2.4);
  lcms_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 }
                                      },
                                      curve);

  cmsSaveProfileToFile (lcms_profile, "foo.icc");

  cmsFreeToneCurveTriple (curve);
  cmsCloseProfile (lcms_profile);
2022-09-30 14:42:03 -04:00
Matthias Clasen
4137f26f41 lcmscolorspace: Implement a global transform cache
Speeds up things by a factor of 10x, so seems like a good idea.

The cache is never purges, we might want to fix that.
2022-09-30 14:42:03 -04:00
Benjamin Otte
b4116cbbb2 memoryformat: Optimize more
Make the formats allow converting to an lcms-compatible format and
then use a cmsTransform to convert between them.

Note that mixing RGBA and non-RGBA formats doesn't seem to work, so we
force all our RGB-only formats to convert to a RGBA format.
2022-09-30 14:42:03 -04:00
Benjamin Otte
c5909b16ad memoryformat: Do some gdk_memory_convert() massaging
* Add name support to the formats
* Add profiler mark to gdk_memory_convert()
* Split up the different branches of conversion
* Use memcpy for straight copies
2022-09-30 14:42:03 -04:00
Matthias Clasen
d2f9acf3b0 gsk: Avoid cairo in icon upload
Use the new memory texture magic
2022-09-30 14:42:03 -04:00
Matthias Clasen
3214e5a703 tiff: Add color space support
Apply an embedded icc profile when loading tiff
images, and save associated icc profile information
when saving tiff images.
2022-09-30 14:42:03 -04:00
Benjamin Otte
9ceaf3445d png: Handle color spaces 2022-09-30 14:42:02 -04:00
Matthias Clasen
8fd866ba2e gdk: Take a color space in gdk_memory_texture_from_texture
This will let us do profile conversions at the
same time.

Update all callers.
2022-09-30 14:42:02 -04:00
Benjamin Otte
f1e3ccf0d4 gdk: Take a color space in gdk_texture_download_surface
This way, the resulting surface can contain the pixels
in the desired color space.
2022-09-30 14:42:02 -04:00
Matthias Clasen
03c9e25377 memoryformat: Take a color space when converting 2022-09-30 14:42:02 -04:00
Benjamin Otte
d161830d4c API: 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.
2022-09-30 14:42:02 -04:00
Benjamin Otte
d546785f90 API: Add GdkSurface::color-space
Unused so far, but there's a private setter for backends and a public
readable property for code.
2022-09-30 14:42:02 -04:00
Matthias Clasen
e9315dbcf8 gtk-demo: Add a color space demo
This is using test images from http://displaycal.net/.
2022-09-30 14:42:02 -04:00
Benjamin Otte
69403eb66c 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.
2022-09-30 14:42:02 -04:00
Benjamin Otte
23fdeb9f20 jpeg: Add color space support 2022-09-30 14:42:02 -04:00
Benjamin Otte
157ad464d8 API: Add gdk_memory_texture_new_with_color_space()
A version of gdk_memory_texture_new() that allows passing
a color space. The old version assumes sRGB.
2022-09-30 14:42:02 -04:00
Benjamin Otte
e675b54df7 API: Add a GdkTexture::color-space property
Returns the associated color space. For now, this is always sRGB.
2022-09-30 14:42:02 -04:00
Matthias Clasen
9b824abddd Add some colorspace tests
This is very minimal, but it is enough to do
a very basic check of the gdk_color_space_equal
implementation.
2022-09-30 14:42:02 -04:00
Benjamin Otte
28f670d5fa gdk: Add GdkLcmsColorSpace
This is a colorspace implementation using LCMS to implement support
for random colorspaces from ICC profiles.
2022-09-30 14:41:31 -04:00
Benjamin Otte
28d70d17e0 Add mutter and lcms2-devel to the Fedora image
mutter will be needed to get a WM for the x11 testsuite.

lcms2 is needed for upcoming HDR work, so having it available in
varioius branches is neat.
2022-09-30 14:41:31 -04:00
Matthias Clasen
b286901f2b ci: Update dependencies for msys
Add libpng, libjpeg-turbo, libtiff and lcms2.
2022-09-30 14:41:31 -04:00
Matthias Clasen
588a7212c7 Add an lcms2 subproject
Since lcms2 is using autotools, this uses the
experimental 'external project' module of meson,
and adds a minimal meson.build file to lcms2.

It seems to work.
2022-09-30 14:41:31 -04:00
Benjamin Otte
6979811b0e cms: Add lcms to the build 2022-09-30 14:41:31 -04:00
Benjamin Otte
87fcac7508 gdk: Add GdkColorSpace
The code doesn't do anything yet, this is just the boilerplate.
2022-09-30 14:41:31 -04:00
533 changed files with 18376 additions and 21583 deletions

View File

@@ -192,7 +192,6 @@ macos:
only:
- branches@GNOME/gtk
stage: build
allow_failure: true
tags:
- macos
needs: []

View File

@@ -42,6 +42,7 @@ RUN dnf -y install \
iso-codes \
itstool \
json-glib-devel \
lcms2-devel \
lcov \
libasan \
libattr-devel \
@@ -71,6 +72,7 @@ RUN dnf -y install \
mesa-libEGL-devel \
mesa-libGLES-devel \
meson \
mutter \
ninja-build \
pango-devel \
pcre-devel \

View File

@@ -33,6 +33,10 @@ pacman --noconfirm -S --needed \
mingw-w64-$MSYS2_ARCH-gst-plugins-bad-libs \
mingw-w64-$MSYS2_ARCH-shared-mime-info \
mingw-w64-$MSYS2_ARCH-python-gobject
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)"

43
NEWS
View File

@@ -1,49 +1,6 @@
Overview of Changes in 4.9.1, dd-mm-yyyy
========================================
Note that deprecations are an early outlook
at changes that will appear in an eventual
GTK 5 release, which is still far away.
* GtkTreeView, GtkIconView, GtkComboBox and
auxiliary classes have been deprecated
* GtkEntryCompletion has been deprecated
* GtkStyleContext has been deprecated
* gtk_render_ and gtk_snapshot_render_ APIs
have been deprecated
* GtkAppChooser widgets hae been deprecated
* GtkMountOperation:
- Fix the dialog to look reasonable
- Make it work under non-X11
* GtkStringSorter:
- Support different collation methods
* Accessibility:
- Introduce GtkAccessibleRange and implement it
* Debugging:
- Unify formatting for debug output
- Make make debug options available in
non-debug builds
* Translation updates:
Abkhazian
Basque
Bulgarian
Croatian
Friulian
Georgian
German
Hungarian
Russian
Turkish
Overview of Changes in 4.8.1, 16-09-2022
========================================

View File

@@ -21,8 +21,6 @@
#include "constraint-editor.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
struct _ConstraintEditor
{
GtkWidget parent_instance;

View File

@@ -21,8 +21,6 @@
#include "guide-editor.h"
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
struct _GuideEditor
{
GtkWidget parent_instance;

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_widget_show (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

@@ -11,8 +11,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
enum
{
ICON_NAME_COL,

View File

@@ -1,16 +1,20 @@
/* Theming/CSS Accordion
*
* A simple accordion demo written using CSS transitions and multiple backgrounds
*
*/
#include <gtk/gtk.h>
static void
destroy_provider (GtkWidget *window,
GtkStyleProvider *provider)
apply_css (GtkWidget *widget, GtkStyleProvider *provider)
{
gtk_style_context_remove_provider_for_display (gtk_widget_get_display (window), provider);
GtkWidget *child;
gtk_style_context_add_provider (gtk_widget_get_style_context (widget), provider, G_MAXUINT);
for (child = gtk_widget_get_first_child (widget);
child != NULL;
child = gtk_widget_get_next_sibling (child))
apply_css (child, provider);
}
GtkWidget *
@@ -20,8 +24,8 @@ do_css_accordion (GtkWidget *do_widget)
if (!window)
{
GtkWidget *container, *styled_box, *child;
GtkCssProvider *provider;
GtkWidget *container, *child;
GtkStyleProvider *provider;
window = gtk_window_new ();
gtk_window_set_title (GTK_WINDOW (window), "CSS Accordion");
@@ -29,13 +33,10 @@ do_css_accordion (GtkWidget *do_widget)
gtk_window_set_default_size (GTK_WINDOW (window), 600, 300);
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
styled_box = gtk_frame_new (NULL);
gtk_window_set_child (GTK_WINDOW (window), styled_box);
gtk_widget_add_css_class (styled_box, "accordion");
container = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign (container, GTK_ALIGN_CENTER);
gtk_widget_set_valign (container, GTK_ALIGN_CENTER);
gtk_frame_set_child (GTK_FRAME (styled_box), container);
gtk_window_set_child (GTK_WINDOW (window), container);
child = gtk_button_new_with_label ("This");
gtk_box_append (GTK_BOX (container), child);
@@ -55,16 +56,10 @@ do_css_accordion (GtkWidget *do_widget)
child = gtk_button_new_with_label (":-)");
gtk_box_append (GTK_BOX (container), child);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_resource (provider, "/css_accordion/css_accordion.css");
provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider), "/css_accordion/css_accordion.css");
gtk_style_context_add_provider_for_display (gtk_widget_get_display (window),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_signal_connect (window, "destroy",
G_CALLBACK (destroy_provider), provider);
g_object_unref (provider);
apply_css (window, provider);
}
if (!gtk_widget_get_visible (window))

View File

@@ -1,13 +1,13 @@
.accordion, .accordion * {
all: unset;
@import url("resource://css_accordion/reset.css");
* {
transition-property: color, background-color, border-color, background-image, padding, border-width;
transition-duration: 1s;
font: 20px Cantarell;
}
.accordion {
window {
background: linear-gradient(153deg, #151515, #151515 5px, transparent 5px) 0 0,
linear-gradient(333deg, #151515, #151515 5px, transparent 5px) 10px 5px,
linear-gradient(153deg, #222, #222 5px, transparent 5px) 0 5px,
@@ -18,7 +18,7 @@
background-size: 20px 20px;
}
.accordion button {
button {
color: black;
background-color: #bbb;
border-style: solid;
@@ -28,25 +28,25 @@
padding: 12px 4px;
}
.accordion button:first-child {
button:first-child {
border-radius: 5px 0 0 5px;
}
.accordion button:last-child {
button:last-child {
border-radius: 0 5px 5px 0;
border-width: 2px;
}
.accordion button:hover {
button:hover {
padding: 12px 48px;
background-color: #4870bc;
}
.accordion button *:hover {
button *:hover {
color: white;
}
.accordion button:hover:active,
.accordion button:active {
button:hover:active,
button:active {
background-color: #993401;
}

View File

@@ -6,8 +6,6 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,

View File

@@ -6,8 +6,6 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,

View File

@@ -7,8 +7,6 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,

View File

@@ -5,8 +5,6 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
show_parsing_error (GtkCssProvider *provider,
GtkCssSection *section,

View File

@@ -19,11 +19,23 @@
<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>
<gresource prefix="/css_accordion">
<file>css_accordion.css</file>
<file>reset.css</file>
</gresource>
<gresource prefix="/css_basics">
<file>css_basics.css</file>
@@ -254,6 +266,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

@@ -11,7 +11,6 @@
#include <gtk/gtk.h>
G_DECLARE_FINAL_TYPE (CanvasItem, canvas_item, CANVAS, ITEM, GtkWidget)
struct _CanvasItem {
@@ -25,9 +24,6 @@ struct _CanvasItem {
double delta;
GtkWidget *editor;
GtkStyleProvider *provider;
char *css_class;
};
struct _CanvasItemClass {
@@ -38,41 +34,32 @@ G_DEFINE_TYPE (CanvasItem, canvas_item, GTK_TYPE_WIDGET)
static int n_items = 0;
static void
unstyle_item (CanvasItem *item)
{
if (item->provider)
{
gtk_style_context_remove_provider_for_display (gtk_widget_get_display (item->label), item->provider);
g_clear_object (&item->provider);
}
if (item->css_class)
{
gtk_widget_remove_css_class (item->label, item->css_class);
g_clear_pointer (&item->css_class, g_free);
}
}
static void
set_color (CanvasItem *item,
GdkRGBA *color)
{
char *css;
char *str;
GtkStyleContext *context;
GtkCssProvider *provider;
const char *name;
unstyle_item (item);
const char *old_class;
str = gdk_rgba_to_string (color);
name = gtk_widget_get_name (item->label);
css = g_strdup_printf ("#%s { background: %s; }", name, str);
css = g_strdup_printf ("* { background: %s; }", str);
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
old_class = (const char *)g_object_get_data (G_OBJECT (item->label), "css-class");
if (old_class)
gtk_widget_remove_css_class (item->label, old_class);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider_for_display (gtk_widget_get_display (item->label), GTK_STYLE_PROVIDER (provider), 700);
item->provider = GTK_STYLE_PROVIDER (provider);
gtk_style_context_add_provider (gtk_widget_get_style_context (item->label), GTK_STYLE_PROVIDER (provider), 800);
g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref);
g_free (str);
g_free (css);
@@ -82,10 +69,21 @@ static void
set_css (CanvasItem *item,
const char *class)
{
unstyle_item (item);
GtkStyleContext *context;
GtkCssProvider *provider;
const char *old_class;
context = gtk_widget_get_style_context (item->label);
provider = g_object_get_data (G_OBJECT (context), "style-provider");
if (provider)
gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider));
old_class = (const char *)g_object_get_data (G_OBJECT (item->label), "css-class");
if (old_class)
gtk_widget_remove_css_class (item->label, old_class);
g_object_set_data_full (G_OBJECT (item->label), "css-class", g_strdup (class), g_free);
gtk_widget_add_css_class (item->label, class);
item->css_class = g_strdup (class);
}
static gboolean
@@ -724,7 +722,6 @@ do_dnd (GtkWidget *do_widget)
int i;
int x, y;
GtkCssProvider *provider;
GString *css;
button = gtk_color_button_new ();
g_object_unref (g_object_ref_sink (button));
@@ -736,18 +733,6 @@ do_dnd (GtkWidget *do_widget)
800);
g_object_unref (provider);
css = g_string_new ("");
for (i = 0; colors[i]; i++)
g_string_append_printf (css, ".canvasitem.%s { background: %s; }\n", colors[i], colors[i]);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css->str, css->len);
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
g_object_unref (provider);
g_string_free (css, TRUE);
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
gtk_widget_get_display (do_widget));

View File

@@ -14,8 +14,6 @@
#include <string.h>
#include <stdlib.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef struct
{
int number;

View File

@@ -8,8 +8,6 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* Creates a tree model containing the completions */
static GtkTreeModel *
create_completion_model (void)

View File

@@ -9,8 +9,6 @@
#include <gtk/gtk.h>
#include <stdlib.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
enum {
WIDTH_COLUMN,
HEIGHT_COLUMN,

View File

@@ -21,75 +21,6 @@
#include "script-names.h"
#include "language-names.h"
/* {{{ ScriptLang object */
G_DECLARE_FINAL_TYPE (ScriptLang, script_lang, SCRIPT, LANG, GObject)
struct _ScriptLang
{
GObject parent;
char *langname;
unsigned int script_index;
unsigned int lang_index;
hb_tag_t lang_tag;
};
struct _ScriptLangClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE (ScriptLang, script_lang, G_TYPE_OBJECT)
static void
script_lang_init (ScriptLang *self)
{
}
static void
script_lang_finalize (GObject *object)
{
ScriptLang *self = SCRIPT_LANG (object);
g_free (self->langname);
G_OBJECT_CLASS (script_lang_parent_class)->finalize (object);
}
static void
script_lang_class_init (ScriptLangClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = script_lang_finalize;
}
static ScriptLang *
script_lang_new (const char *langname,
unsigned int script_index,
unsigned int lang_index,
hb_tag_t lang_tag)
{
ScriptLang *self;
self = g_object_new (script_lang_get_type (), NULL);
self->langname = g_strdup (langname);
self->script_index = script_index;
self->lang_index = lang_index;
self->lang_tag = lang_tag;
return self;
}
static char *
script_lang_get_langname (ScriptLang *self)
{
return g_strdup (self->langname);
}
/* }}} */
#define MAKE_TAG(a,b,c,d) (unsigned int)(((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
@@ -163,10 +94,6 @@ demo_free (gpointer data)
g_clear_pointer (&demo->axes, g_hash_table_unref);
g_clear_pointer (&demo->text, g_free);
gtk_style_context_remove_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (demo->provider));
g_object_unref (demo->provider);
g_free (demo);
}
@@ -544,6 +471,8 @@ update_display (void)
GString *s;
char *text;
gboolean has_feature;
GtkTreeIter iter;
GtkTreeModel *model;
PangoFontDescription *desc;
GList *l;
PangoAttrList *attrs;
@@ -646,13 +575,14 @@ update_display (void)
features = g_string_free (s, FALSE);
if (gtk_drop_down_get_selected (GTK_DROP_DOWN (demo->script_lang)) != 0)
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (demo->script_lang), &iter))
{
ScriptLang *selected;
hb_tag_t lang_tag;
selected = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (demo->script_lang));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (demo->script_lang));
gtk_tree_model_get (model, &iter, 3, &lang_tag, -1);
lang = pango_language_from_string (hb_language_to_string (hb_ot_tag_to_language (selected->lang_tag)));
lang = pango_language_from_string (hb_language_to_string (hb_ot_tag_to_language (lang_tag)));
}
else
lang = NULL;
@@ -809,30 +739,40 @@ tag_pair_equal (gconstpointer a, gconstpointer b)
return pair_a->script_tag == pair_b->script_tag && pair_a->lang_tag == pair_b->lang_tag;
}
static GtkOrdering
script_sort (const void *item1,
const void *item2,
void *data)
static int
script_sort_func (GtkTreeModel *model,
GtkTreeIter *a,
GtkTreeIter *b,
gpointer user_data)
{
ScriptLang *a = (ScriptLang *)item1;
ScriptLang *b = (ScriptLang *)item2;
char *sa, *sb;
int ret;
return strcmp (a->langname, b->langname);
gtk_tree_model_get (model, a, 0, &sa, -1);
gtk_tree_model_get (model, b, 0, &sb, -1);
ret = strcmp (sa, sb);
g_free (sa);
g_free (sb);
return ret;
}
static void
update_script_combo (void)
{
GListStore *store;
GtkSortListModel *sortmodel;
GtkListStore *store;
hb_font_t *hb_font;
int i, j, k;
PangoFont *pango_font;
GHashTable *tags;
GHashTableIter iter;
TagPair *pair;
char *lang;
hb_tag_t active;
GtkTreeIter active_iter;
gboolean have_active = FALSE;
lang = gtk_font_chooser_get_language (GTK_FONT_CHOOSER (demo->font));
@@ -842,7 +782,7 @@ update_script_combo (void)
g_free (lang);
store = g_list_store_new (script_lang_get_type ());
store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
pango_font = get_pango_font ();
hb_font = pango_font_get_hb_font (pango_font);
@@ -866,19 +806,19 @@ update_script_combo (void)
hb_face = hb_font_get_face (hb_font);
for (guint i = 0; i < 2; i++)
for (i= 0; i < 2; i++)
{
hb_tag_t scripts[80];
unsigned int script_count = G_N_ELEMENTS (scripts);
hb_ot_layout_table_get_script_tags (hb_face, tables[i], 0, &script_count, scripts);
for (guint j = 0; j < script_count; j++)
for (j = 0; j < script_count; j++)
{
hb_tag_t languages[80];
unsigned int language_count = G_N_ELEMENTS (languages);
hb_ot_layout_script_get_language_tags (hb_face, tables[i], j, 0, &language_count, languages);
for (guint k = 0; k < language_count; k++)
for (k = 0; k < language_count; k++)
{
pair = g_new (TagPair, 1);
pair->script_tag = scripts[j];
@@ -898,6 +838,7 @@ update_script_combo (void)
{
const char *langname;
char langbuf[5];
GtkTreeIter tree_iter;
if (pair->lang_tag == 0 && pair->script_tag == 0)
langname = NC_("Language", "None");
@@ -914,31 +855,31 @@ update_script_combo (void)
}
}
g_list_store_append (store, script_lang_new (langname,
pair->script_index,
pair->lang_index,
pair->lang_tag));
gtk_list_store_insert_with_values (store, &tree_iter, -1,
0, langname,
1, pair->script_index,
2, pair->lang_index,
3, pair->lang_tag,
-1);
if (pair->lang_tag == active)
{
have_active = TRUE;
active_iter = tree_iter;
}
}
g_hash_table_destroy (tags);
sortmodel = gtk_sort_list_model_new (G_LIST_MODEL (store),
GTK_SORTER (gtk_custom_sorter_new (script_sort, NULL, NULL)));
gtk_drop_down_set_model (GTK_DROP_DOWN (demo->script_lang), G_LIST_MODEL (sortmodel));
for (guint i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (sortmodel)); i++)
{
ScriptLang *item = g_list_model_get_item (G_LIST_MODEL (sortmodel), i);
g_object_unref (item);
if (item->lang_tag == active)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (demo->script_lang), i);
break;
}
}
g_object_unref (sortmodel);
gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store),
script_sort_func, NULL, NULL);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
GTK_SORT_ASCENDING);
gtk_combo_box_set_model (GTK_COMBO_BOX (demo->script_lang), GTK_TREE_MODEL (store));
if (have_active)
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (demo->script_lang), &active_iter);
else
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (demo->script_lang), 0);
}
static char *
@@ -963,19 +904,27 @@ static void
update_features (void)
{
int i, j;
GtkTreeModel *model;
GtkTreeIter iter;
guint script_index, lang_index;
hb_tag_t lang_tag;
PangoFont *pango_font;
hb_font_t *hb_font;
GList *l;
ScriptLang *selected;
/* set feature presence checks from the font features */
if (gtk_drop_down_get_selected (GTK_DROP_DOWN (demo->script_lang)) == 0)
if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (demo->script_lang), &iter))
return;
selected = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (demo->script_lang));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (demo->script_lang));
gtk_tree_model_get (model, &iter,
1, &script_index,
2, &lang_index,
3, &lang_tag,
-1);
if (selected->lang_tag == 0) /* None is selected */
if (lang_tag == 0) /* None is selected */
{
for (l = demo->feature_items; l; l = l->next)
{
@@ -1016,8 +965,8 @@ update_features (void)
hb_ot_layout_language_get_feature_tags (hb_face,
tables[i],
selected->script_index,
selected->lang_index,
script_index,
lang_index,
0,
&count,
features);
@@ -1039,8 +988,8 @@ update_features (void)
hb_ot_layout_language_find_feature (hb_face,
tables[i],
selected->script_index,
selected->lang_index,
script_index,
lang_index,
features[j],
&feature_index);
@@ -1372,9 +1321,10 @@ free_instance (gpointer data)
}
static void
add_instance (hb_face_t *face,
unsigned int index,
GtkStringList *strings)
add_instance (hb_face_t *face,
unsigned int index,
GtkWidget *combo,
int pos)
{
Instance *instance;
hb_ot_name_id_t name_id;
@@ -1390,20 +1340,20 @@ add_instance (hb_face_t *face,
instance->index = index;
g_hash_table_add (demo->instances, instance);
gtk_string_list_append (GTK_STRING_LIST (strings), instance->name);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), instance->name);
}
static void
unset_instance (GtkAdjustment *adjustment)
{
if (demo->instance_combo)
gtk_drop_down_set_selected (GTK_DROP_DOWN (demo->instance_combo), 0);
gtk_combo_box_set_active (GTK_COMBO_BOX (demo->instance_combo), 0);
}
static void
instance_changed (GtkDropDown *combo)
instance_changed (GtkComboBox *combo)
{
const char *text;
char *text;
Instance *instance;
Instance ikey;
int i;
@@ -1415,12 +1365,11 @@ instance_changed (GtkDropDown *combo)
hb_font_t *hb_font;
hb_face_t *hb_face;
text = gtk_string_list_get_string (GTK_STRING_LIST (gtk_drop_down_get_model (combo)),
gtk_drop_down_get_selected (combo));
text = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo));
if (text[0] == '\0')
goto out;
ikey.name = (char *) text;
ikey.name = text;
instance = g_hash_table_lookup (demo->instances, &ikey);
if (!instance)
{
@@ -1461,6 +1410,7 @@ instance_changed (GtkDropDown *combo)
}
out:
g_free (text);
g_clear_object (&pango_font);
g_free (ai);
g_free (coords);
@@ -1570,7 +1520,6 @@ update_font_variations (void)
{
GtkWidget *label;
GtkWidget *combo;
GtkStringList *strings;
label = gtk_label_new ("Instance");
gtk_label_set_xalign (GTK_LABEL (label), 0);
@@ -1578,28 +1527,26 @@ update_font_variations (void)
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (demo->variations_grid), label, 0, -1, 1, 1);
strings = gtk_string_list_new (NULL);
combo = gtk_drop_down_new (G_LIST_MODEL (strings), NULL);
combo = gtk_combo_box_text_new ();
gtk_widget_set_halign (combo, GTK_ALIGN_START);
gtk_widget_set_valign (combo, GTK_ALIGN_BASELINE);
gtk_string_list_append (strings, "");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo), "");
for (i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
add_instance (hb_face, i, strings);
add_instance (hb_face, i, combo, i);
for (i = 0; i < hb_ot_var_get_named_instance_count (hb_face); i++)
{
if (matches_instance (hb_face, i, n_axes, design_coords))
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (combo), i + 1);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i + 1);
break;
}
}
gtk_grid_attach (GTK_GRID (demo->variations_grid), combo, 1, -1, 3, 1);
g_signal_connect (combo, "notify::selecte", G_CALLBACK (instance_changed), NULL);
g_signal_connect (combo, "changed", G_CALLBACK (instance_changed), NULL);
demo->instance_combo = combo;
}
@@ -1746,7 +1693,6 @@ do_font_features (GtkWidget *do_widget)
GtkBuilder *builder;
GtkBuilderScope *scope;
GtkEventController *controller;
GtkExpression *expression;
builder = gtk_builder_new ();
@@ -1780,9 +1726,6 @@ do_font_features (GtkWidget *do_widget)
demo->description = GTK_WIDGET (gtk_builder_get_object (builder, "description"));
demo->font = GTK_WIDGET (gtk_builder_get_object (builder, "font"));
demo->script_lang = GTK_WIDGET (gtk_builder_get_object (builder, "script_lang"));
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL, 0, NULL, G_CALLBACK (script_lang_get_langname), NULL, NULL);
gtk_drop_down_set_expression (GTK_DROP_DOWN (demo->script_lang), expression);
gtk_expression_unref (expression);
demo->feature_list = GTK_WIDGET (gtk_builder_get_object (builder, "feature_list"));
demo->stack = GTK_WIDGET (gtk_builder_get_object (builder, "stack"));
demo->entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
@@ -1801,8 +1744,8 @@ do_font_features (GtkWidget *do_widget)
demo->swin = GTK_WIDGET (gtk_builder_get_object (builder, "swin"));
demo->provider = gtk_css_provider_new ();
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (demo->provider), 800);
gtk_style_context_add_provider (gtk_widget_get_style_context (demo->swin),
GTK_STYLE_PROVIDER (demo->provider), 800);
basic_value_changed (demo->size_adjustment, demo->size_entry);
basic_value_changed (demo->letterspacing_adjustment, demo->letterspacing_entry);
@@ -1880,5 +1823,3 @@ do_font_features (GtkWidget *do_widget)
return window;
}
/* vim:set foldmethod=marker expandtab: */

View File

@@ -259,10 +259,16 @@
<object class="GtkBox" id="feature_list">
<property name="orientation">vertical</property>
<child>
<object class="GtkDropDown" id="script_lang">
<object class="GtkComboBox" id="script_lang">
<property name="tooltip-text" translatable="yes">Language System</property>
<property name="margin-top">10</property>
<signal name="notify::selected" handler="font_features_script_changed" swapped="no"/>
<signal name="changed" handler="font_features_script_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>

View File

@@ -43,6 +43,7 @@ update_image (void)
cairo_t *cr;
GdkPixbuf *pixbuf;
GdkPixbuf *pixbuf2;
const char *hint;
cairo_font_options_t *fopt;
cairo_hint_style_t hintstyle;
cairo_hint_metrics_t hintmetrics;
@@ -57,23 +58,18 @@ update_image (void)
fopt = cairo_font_options_copy (pango_cairo_context_get_font_options (context));
switch (gtk_drop_down_get_selected (GTK_DROP_DOWN (hinting)))
hint = gtk_combo_box_get_active_id (GTK_COMBO_BOX (hinting));
hintstyle = CAIRO_HINT_STYLE_DEFAULT;
if (hint)
{
case 0:
hintstyle = CAIRO_HINT_STYLE_NONE;
break;
case 1:
hintstyle = CAIRO_HINT_STYLE_SLIGHT;
break;
case 2:
hintstyle = CAIRO_HINT_STYLE_MEDIUM;
break;
case 3:
hintstyle = CAIRO_HINT_STYLE_FULL;
break;
default:
hintstyle = CAIRO_HINT_STYLE_DEFAULT;
break;
if (strcmp (hint, "none") == 0)
hintstyle = CAIRO_HINT_STYLE_NONE;
else if (strcmp (hint, "slight") == 0)
hintstyle = CAIRO_HINT_STYLE_SLIGHT;
else if (strcmp (hint, "medium") == 0)
hintstyle = CAIRO_HINT_STYLE_MEDIUM;
else if (strcmp (hint, "full") == 0)
hintstyle = CAIRO_HINT_STYLE_FULL;
}
cairo_font_options_set_hint_style (fopt, hintstyle);
@@ -422,7 +418,7 @@ do_fontrendering (GtkWidget *do_widget)
g_signal_connect (down_button, "clicked", G_CALLBACK (scale_down), NULL);
g_signal_connect (entry, "notify::text", G_CALLBACK (update_image), NULL);
g_signal_connect (font_button, "notify::font-desc", G_CALLBACK (update_image), NULL);
g_signal_connect (hinting, "notify::selected", G_CALLBACK (update_image), NULL);
g_signal_connect (hinting, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (anti_alias, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (hint_metrics, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (text_radio, "notify::active", G_CALLBACK (update_image), NULL);

View File

@@ -116,18 +116,15 @@
</object>
</child>
<child>
<object class="GtkDropDown" id="hinting">
<object class="GtkComboBoxText" id="hinting">
<property name="active">0</property>
<property name="valign">center</property>
<property name="model">
<object class="GtkStringList">
<items>
<item translatable="yes">None</item>
<item translatable="yes">Slight</item>
<item translatable="yes">Medium</item>
<item translatable="yes">Full</item>
</items>
</object>
</property>
<items>
<item translatable="yes" id="none">None</item>
<item translatable="yes" id="slight">Slight</item>
<item translatable="yes" id="medium">Medium</item>
<item translatable="yes" id="full">Full</item>
</items>
</object>
</child>
<layout>

View File

@@ -144,6 +144,7 @@ make_shader_stack (const char *name,
GtkTextBuffer *buffer;
GBytes *bytes;
GtkEventController *controller;
GtkCssProvider *provider;
GdkPaintable *paintable;
stack = gtk_shader_stack_new ();
@@ -234,6 +235,12 @@ make_shader_stack (const char *name,
g_signal_connect (buffer, "changed", G_CALLBACK (text_changed), button);
g_object_set_data (G_OBJECT (button), "the-stack", stack);
g_signal_connect (button, "clicked", G_CALLBACK (apply_text), buffer);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, "button.small { padding: 0; }", -1);
gtk_style_context_add_provider (gtk_widget_get_style_context (button),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (provider);
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_widget_add_css_class (button, "small");
@@ -267,21 +274,11 @@ make_shader_stack (const char *name,
return vbox;
}
static void
remove_provider (gpointer data)
{
GtkStyleProvider *provider = GTK_STYLE_PROVIDER (data);
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
g_object_unref (provider);
}
static GtkWidget *
create_gltransition_window (GtkWidget *do_widget)
{
GtkWidget *window, *headerbar, *scale, *outer_grid, *grid, *background;
GdkPaintable *paintable;
GtkCssProvider *provider;
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
@@ -336,14 +333,6 @@ create_gltransition_window (GtkWidget *do_widget)
make_shader_stack ("Kaleidoscope", "/gltransition/kaleidoscope.glsl", 3, scale),
1, 1, 1, 1);
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, "button.small { padding: 0; }", -1);
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_set_data_full (G_OBJECT (window), "provider", provider, remove_provider);
return window;
}

View File

@@ -9,8 +9,6 @@
#include <gtk/gtk.h>
#include <string.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *window = NULL;
#define FOLDER_NAME "/iconview/gnome-fs-directory.png"

View File

@@ -8,8 +8,6 @@
#include <gtk/gtk.h>
#include <string.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
enum
{
COL_TEXT,

View File

@@ -7,8 +7,6 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static GtkWidget *window = NULL;
static GtkTreeModel *model = NULL;
static guint timeout = 0;

View File

@@ -422,10 +422,6 @@ do_listview_settings (GtkWidget *do_widget)
gtk_column_view_column_set_sorter (name_column, sorter);
g_object_unref (sorter);
sorter = GTK_SORTER (gtk_string_sorter_new (gtk_property_expression_new (SETTINGS_TYPE_KEY, NULL, "type")));
gtk_column_view_column_set_sorter (type_column, sorter);
g_object_unref (sorter);
g_object_unref (builder);
}

View File

@@ -10,6 +10,7 @@
#include "script-names.h"
#include "unicode-names.h"
#define UCD_TYPE_ITEM (ucd_item_get_type ())
G_DECLARE_FINAL_TYPE (UcdItem, ucd_item, UCD, ITEM, GObject)
@@ -337,15 +338,6 @@ create_ucd_view (GtkWidget *label)
static GtkWidget *window;
static void
remove_provider (gpointer data)
{
GtkStyleProvider *provider = GTK_STYLE_PROVIDER (data);
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
g_object_unref (provider);
}
GtkWidget *
do_listview_ucd (GtkWidget *do_widget)
{
@@ -368,7 +360,7 @@ do_listview_ucd (GtkWidget *do_widget)
gtk_widget_add_css_class (label, "enormous");
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, "label.enormous { font-size: 80px; }", -1);
gtk_style_context_add_provider_for_display (gdk_display_get_default (), GTK_STYLE_PROVIDER (provider), 800);
gtk_style_context_add_provider (gtk_widget_get_style_context (label), GTK_STYLE_PROVIDER (provider), 800);
gtk_widget_set_hexpand (label, TRUE);
gtk_box_append (GTK_BOX (box), label);
@@ -378,8 +370,6 @@ do_listview_ucd (GtkWidget *do_widget)
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
gtk_box_prepend (GTK_BOX (box), sw);
gtk_window_set_child (GTK_WINDOW (window), box);
g_object_set_data_full (G_OBJECT (window), "provider", provider, remove_provider);
}
if (!gtk_widget_get_visible (window))

View File

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

View File

@@ -8,7 +8,6 @@
#include "config.h"
#include <gtk/gtk.h>
/* Create an object for the pegs that get moved around in the game.
*
* We implement the GdkPaintable interface for them, so we can use GtkPicture
@@ -360,15 +359,6 @@ drop_drop (GtkDropTarget *target,
return TRUE;
}
static void
remove_provider (gpointer data)
{
GtkStyleProvider *provider = GTK_STYLE_PROVIDER (data);
gtk_style_context_remove_provider_for_display (gdk_display_get_default (), provider);
g_object_unref (provider);
}
static void
create_board (GtkWidget *window)
{
@@ -385,9 +375,6 @@ create_board (GtkWidget *window)
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider, css, -1);
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
GTK_STYLE_PROVIDER (provider),
800);
grid = gtk_grid_new ();
gtk_widget_set_halign (grid, GTK_ALIGN_CENTER);
@@ -406,6 +393,9 @@ create_board (GtkWidget *window)
continue;
image = gtk_image_new ();
gtk_style_context_add_provider (gtk_widget_get_style_context (image),
GTK_STYLE_PROVIDER (provider),
800);
gtk_widget_add_css_class (image, "solitaire-field");
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
if (x != 3 || y != 3)
@@ -449,7 +439,7 @@ create_board (GtkWidget *window)
}
}
g_object_set_data_full (G_OBJECT (window), "provider", provider, remove_provider);
g_object_unref (provider);
}
static void

View File

@@ -123,14 +123,8 @@ do_pickers (GtkWidget *do_widget)
gtk_widget_set_halign (label, GTK_ALIGN_START);
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
gtk_widget_set_hexpand (label, TRUE);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
picker = gtk_app_chooser_button_new ("x-scheme-handler/mailto");
gtk_app_chooser_button_set_show_dialog_item (GTK_APP_CHOOSER_BUTTON (picker), TRUE);
G_GNUC_END_IGNORE_DEPRECATIONS
gtk_grid_attach (GTK_GRID (table), label, 0, 3, 1, 1);
gtk_grid_attach (GTK_GRID (table), picker, 1, 3, 1, 1);
}

View File

@@ -16,6 +16,7 @@ enum {
NUM_PROPERTIES
};
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
static void
pixbuf_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
@@ -36,6 +37,7 @@ pixbuf_paintable_snapshot (GdkPaintable *paintable,
g_object_unref (texture);
}
G_GNUC_END_IGNORE_DEPRECATIONS;
static int
pixbuf_paintable_get_intrinsic_width (GdkPaintable *paintable)

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

@@ -16,6 +16,24 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
/* Convenience function to create a combo box holding a number of strings
*/
GtkWidget *
create_combo_box (const char **strings)
{
GtkWidget *combo_box;
const char **str;
combo_box = gtk_combo_box_text_new ();
for (str = strings; *str; str++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box), *str);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo_box), 0);
return combo_box;
}
static void
add_row (GtkGrid *table,
int row,
@@ -23,7 +41,7 @@ add_row (GtkGrid *table,
const char *label_text,
const char **options)
{
GtkWidget *dropdown;
GtkWidget *combo_box;
GtkWidget *label;
label = gtk_label_new_with_mnemonic (label_text);
@@ -32,12 +50,12 @@ add_row (GtkGrid *table,
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (table, label, 0, row, 1, 1);
dropdown = gtk_drop_down_new_from_strings (options);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), dropdown);
gtk_widget_set_halign (dropdown, GTK_ALIGN_END);
gtk_widget_set_valign (dropdown, GTK_ALIGN_BASELINE);
gtk_size_group_add_widget (size_group, dropdown);
gtk_grid_attach (table, dropdown, 1, row, 1, 1);
combo_box = create_combo_box (options);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), combo_box);
gtk_widget_set_halign (combo_box, GTK_ALIGN_END);
gtk_widget_set_valign (combo_box, GTK_ALIGN_BASELINE);
gtk_size_group_add_widget (size_group, combo_box);
gtk_grid_attach (table, combo_box, 1, row, 1, 1);
}
static void

View File

@@ -11,7 +11,6 @@
#include <stdlib.h> /* for exit() */
#include "paintable.h"
static void easter_egg_callback (GtkWidget *button, gpointer data);
static void
@@ -430,11 +429,11 @@ attach_widgets (GtkTextView *text_view)
}
else if (i == 1)
{
const char *options[] = {
"Option 1", "Option 2", "Option 3", NULL
};
widget = gtk_combo_box_text_new ();
widget = gtk_drop_down_new_from_strings (options);
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Option 1");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Option 2");
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (widget), "Option 3");
}
else if (i == 2)
{

View File

@@ -10,8 +10,6 @@
#include <gtk/gtk.h>
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* TreeItem structure */
typedef struct _TreeItem TreeItem;
struct _TreeItem

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,256 @@
#include "heif-loader.h"
#include <gtk/gtk.h>
#include <libheif/heif.h>
static void
describe_nclx_color_profile (const struct heif_color_profile_nclx *nclx,
GString *s)
{
if (nclx->color_primaries == heif_color_primaries_unspecified)
return;
if (nclx->color_primaries == heif_color_primaries_ITU_R_BT_709_5)
{
if (nclx->transfer_characteristics == heif_transfer_characteristic_IEC_61966_2_1 &&
(nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_470_6_System_B_G ||
nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_601_6))
{
g_string_append (s, "sRGB");
return;
}
if (nclx->transfer_characteristics == heif_transfer_characteristic_linear &&
(nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_470_6_System_B_G ||
nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_601_6))
{
g_string_append (s, "sRGB linear");
return;
}
}
if (nclx->color_primaries == heif_color_primaries_ITU_R_BT_2020_2_and_2100_0)
{
if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_PQ &&
nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_2020_2_non_constant_luminance)
{
g_string_append (s, "BT.2020 PQ");
return;
}
if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_HLG &&
nclx->matrix_coefficients == heif_matrix_coefficients_ITU_R_BT_2020_2_non_constant_luminance)
{
g_string_append (s, "BT.2020 HLG");
return;
}
}
if (nclx->color_primaries == heif_color_primaries_SMPTE_EG_432_1)
{
if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_PQ)
{
g_string_append (s, "P3 PQ");
return;
}
}
g_string_append_printf (s, "%d/%d/%d",
nclx->color_primaries,
nclx->matrix_coefficients,
nclx->transfer_characteristics);
}
GdkTexture *
load_heif_image (const char *resource_path,
GString *details,
GError **error)
{
struct heif_context *ctx;
struct heif_error err;
struct heif_image_handle *handle = NULL;
struct heif_image *image = NULL;
enum heif_chroma chroma;
GdkMemoryFormat format;
const char *format_name;
uint8_t *data = NULL;
gsize size;
int width, height, bpp, stride, bits;
GBytes *bytes;
GdkTexture *texture = NULL;
GdkColorSpace *color_space = NULL;
char *profile_type = NULL;
ctx = heif_context_alloc ();
bytes = g_resources_lookup_data (resource_path, 0, NULL);
data = (uint8_t *) g_bytes_get_data (bytes, &size);
err = heif_context_read_from_memory (ctx, data, size, NULL);
g_bytes_unref (bytes);
if (err.code != heif_error_Ok)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, err.message);
goto out;
}
err = heif_context_get_primary_image_handle (ctx, &handle);
if (err.code != heif_error_Ok)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, err.message);
goto out;
}
switch (heif_image_handle_get_color_profile_type (handle))
{
case heif_color_profile_type_not_present:
break;
case heif_color_profile_type_rICC:
case heif_color_profile_type_prof:
{
guchar *icc_data;
gsize icc_size;
profile_type = g_strdup ("icc");
icc_size = heif_image_handle_get_raw_color_profile_size (handle);
icc_data = g_new0 (guchar, icc_size);
err = heif_image_handle_get_raw_color_profile (handle, icc_data);
if (err.code == heif_error_Ok)
{
bytes = g_bytes_new (icc_data, icc_size);
color_space = gdk_color_space_new_from_icc_profile (bytes, NULL);
g_bytes_unref (bytes);
}
g_free (icc_data);
}
break;
case heif_color_profile_type_nclx:
{
struct heif_color_profile_nclx *nclx = NULL;
err = heif_image_handle_get_nclx_color_profile (handle, &nclx);
if (err.code == heif_error_Ok)
{
GString *s;
s = g_string_new ("");
describe_nclx_color_profile (nclx, s);
profile_type = g_string_free (s, FALSE);
color_space = gdk_color_space_new_from_cicp (nclx->color_primaries,
nclx->transfer_characteristics,
0,
TRUE);
heif_nclx_color_profile_free (nclx);
}
}
break;
default:
g_assert_not_reached ();
}
g_string_append_printf (details, "%d×%d pixels\n%d bits of luma, %d bits of chroma%s\n",
heif_image_handle_get_width (handle),
heif_image_handle_get_height (handle),
heif_image_handle_get_luma_bits_per_pixel (handle),
heif_image_handle_get_chroma_bits_per_pixel (handle),
heif_image_handle_has_alpha_channel (handle) ? ", with alpha" : "");
if (profile_type)
{
g_string_append_printf (details, "color profile: %s\n", profile_type);
g_free (profile_type);
}
if (color_space == NULL)
color_space = g_object_ref (gdk_color_space_get_srgb ());
if (heif_image_handle_has_alpha_channel (handle))
{
if (heif_image_handle_get_luma_bits_per_pixel (handle) > 8 ||
heif_image_handle_get_chroma_bits_per_pixel (handle) > 8)
{
chroma = heif_chroma_interleaved_RRGGBBAA_BE;
format = GDK_MEMORY_R16G16B16A16;
format_name = "R<sub>16</sub>G<sub>16</sub>B<sub>16</sub>A<sub>16</sub>";
}
else
{
chroma = heif_chroma_interleaved_RGBA;
format = GDK_MEMORY_R8G8B8A8;
format_name = "R<sub>8</sub>G<sub>8</sub>B<sub>8</sub>A<sub>8</sub>";
}
}
else
{
if (heif_image_handle_get_luma_bits_per_pixel (handle) > 8 ||
heif_image_handle_get_chroma_bits_per_pixel (handle) > 8)
{
chroma = heif_chroma_interleaved_RRGGBB_BE;
format = GDK_MEMORY_R16G16B16;
format_name = "R<sub>16</sub>G<sub>16</sub>B<sub>16</sub>";
}
else
{
chroma = heif_chroma_interleaved_RGB;
format = GDK_MEMORY_R8G8B8;
format_name = "R<sub>8</sub>G<sub>8</sub>B<sub>8</sub>";
}
}
err = heif_decode_image (handle, &image, heif_colorspace_RGB, chroma, NULL);
if (err.code != heif_error_Ok)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, err.message);
goto out;
}
width = heif_image_get_width (image, heif_channel_interleaved);
height = heif_image_get_height (image, heif_channel_interleaved);
bpp = heif_image_get_bits_per_pixel (image, heif_channel_interleaved);
data = (uint8_t*)heif_image_get_plane_readonly (image, heif_channel_interleaved, &stride);
bits = heif_image_get_bits_per_pixel_range (image, heif_channel_interleaved);
g_string_append_printf (details, "texture format %s", format_name);
if (format == GDK_MEMORY_R16G16B16A16 || format == GDK_MEMORY_R16G16B16)
{
/* Shift image data to full 16bit range */
int shift = 16 - bits;
if (shift > 0)
{
for (int y = 0; y < height; ++y)
{
uint8_t *row = data + y * stride;
for (int x = 0; x < stride; x += 2)
{
uint8_t* p = &row[x];
int v = (p[0] << 8) | p[1];
v = (v << shift) | (v >> (16 - shift));
p[1] = (uint8_t) (v >> 8);
p[0] = (uint8_t) (v & 0xFF);
}
}
}
}
bytes = g_bytes_new_with_free_func (data, height * stride * bpp, (GDestroyNotify)heif_image_release, image);
image = NULL;
texture = gdk_memory_texture_new_with_color_space (width, height,
format, color_space,
bytes, stride);
g_bytes_unref (bytes);
g_object_unref (color_space);
out:
heif_context_free (ctx);
if (handle)
heif_image_handle_release (handle);
if (image)
heif_image_release (image);
return texture;
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include <gtk/gtk.h>
GdkTexture *load_heif_image (const char *resource_path,
GString *details,
GError **error);

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

View File

@@ -73,10 +73,18 @@ else
)
endif
widgetfactory_cflags = []
widgetfactory_sources = [ 'widget-factory.c' ]
if libheif_dep.found()
widgetfactory_cflags += '-DHAVE_LIBHEIF'
widgetfactory_sources += 'heif-loader.c'
endif
executable('gtk4-widget-factory',
sources: ['widget-factory.c', widgetfactory_resources],
c_args: common_cflags,
dependencies: [ libgtk_dep, demo_conf_h ],
sources: [ widgetfactory_sources, widgetfactory_resources],
c_args: [ common_cflags, widgetfactory_cflags ],
dependencies: [ libgtk_dep, libheif_dep, demo_conf_h ],
include_directories: confinc,
win_subsystem: 'windows',
link_args: extra_demo_ldflags,

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

View File

@@ -27,6 +27,8 @@
#include "demo_conf.h"
#include "heif-loader.h"
static void
change_dark_state (GSimpleAction *action,
GVariant *state,
@@ -664,7 +666,6 @@ on_record_button_toggled (GtkToggleButton *button,
gtk_widget_add_css_class (GTK_WIDGET (button), "destructive-action");
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
on_page_combo_changed (GtkComboBox *combo,
gpointer user_data)
@@ -706,7 +707,6 @@ on_page_combo_changed (GtkComboBox *combo,
default:;
}
}
G_GNUC_END_IGNORE_DEPRECATIONS
static void
on_range_from_changed (GtkSpinButton *from)
@@ -845,7 +845,6 @@ page_changed_cb (GtkWidget *stack, GParamSpec *pspec, gpointer data)
}
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
populate_model (GtkTreeStore *store)
{
@@ -963,7 +962,6 @@ row_separator_func (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
return is_sep;
}
G_GNUC_END_IGNORE_DEPRECATIONS
static void
update_title_header (GtkListBoxRow *row,
@@ -1582,7 +1580,6 @@ osd_frame_pressed (GtkGestureClick *gesture,
return GDK_EVENT_STOP;
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static gboolean
page_combo_separator_func (GtkTreeModel *model,
GtkTreeIter *iter,
@@ -1597,7 +1594,6 @@ page_combo_separator_func (GtkTreeModel *model,
return res;
}
G_GNUC_END_IGNORE_DEPRECATIONS
static void
toggle_format (GSimpleAction *action,
@@ -1850,7 +1846,6 @@ update_buttons (GtkWidget *iv, GtkIconSize size)
gtk_widget_set_sensitive (button, size != GTK_ICON_SIZE_INHERIT);
}
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
increase_icon_size (GtkWidget *iv)
{
@@ -1901,7 +1896,6 @@ reset_icon_size (GtkWidget *iv)
gtk_widget_queue_resize (iv);
}
G_GNUC_END_IGNORE_DEPRECATIONS
static char *
scale_format_value_blank (GtkScale *scale, double value, gpointer user_data)
@@ -2278,12 +2272,10 @@ activate (GApplication *app)
g_object_set_data (G_OBJECT (window), "selection_flowbox", widget2);
g_signal_connect_swapped (widget, "clicked", G_CALLBACK (populate_flowbox), widget2);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
widget = (GtkWidget *)gtk_builder_get_object (builder, "charletree");
populate_model ((GtkTreeStore *)gtk_tree_view_get_model (GTK_TREE_VIEW (widget)));
gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (widget), row_separator_func, NULL, NULL);
gtk_tree_view_expand_all (GTK_TREE_VIEW (widget));
G_GNUC_END_IGNORE_DEPRECATIONS
widget = GTK_WIDGET (gtk_builder_get_object (builder, "munsell"));
widget2 = GTK_WIDGET (gtk_builder_get_object (builder, "cchooser"));
@@ -2291,7 +2283,6 @@ G_GNUC_END_IGNORE_DEPRECATIONS
populate_colors (widget, widget2);
g_signal_connect (widget2, "notify::rgba", G_CALLBACK (rgba_changed), widget);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
widget = (GtkWidget *)gtk_builder_get_object (builder, "page_combo");
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (widget), page_combo_separator_func, NULL, NULL);
widget2 = (GtkWidget *)gtk_builder_get_object (builder, "range_from_spin");
@@ -2302,7 +2293,6 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
g_object_set_data (G_OBJECT (widget), "range_to_spin", widget3);
g_object_set_data (G_OBJECT (widget2), "range_to_spin", widget3);
g_object_set_data (G_OBJECT (widget), "print_button", widget4);
G_GNUC_END_IGNORE_DEPRECATIONS
widget2 = (GtkWidget *)gtk_builder_get_object (builder, "tooltextview");
@@ -2395,6 +2385,20 @@ G_GNUC_END_IGNORE_DEPRECATIONS
model = (GMenuModel *)gtk_builder_get_object (builder, "new_style_context_menu_model");
set_up_context_popover (widget, model);
widget = (GtkWidget *)gtk_builder_get_object (builder, "hdr_picture");
#ifdef HAVE_LIBHEIF
widget2 = (GtkWidget *)gtk_builder_get_object (builder, "hdr_label");
GString *details = g_string_new ("");
GdkTexture *texture = load_heif_image ("/org/gtk/WidgetFactory4/hdr-example.heif", details, NULL);
gtk_picture_set_paintable (GTK_PICTURE (widget), GDK_PAINTABLE (texture));
gtk_label_set_label (GTK_LABEL (widget2), details->str);
g_string_free (details, TRUE);
g_object_unref (texture);
#else
widget2 = gtk_widget_get_ancestor (widget, GTK_TYPE_NOTEBOOK);
gtk_notebook_remove_page (GTK_NOTEBOOK (widget2), 2);
#endif
gtk_window_present (window);
g_object_unref (builder);

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

@@ -110,6 +110,7 @@
<file>icons/scalable/status/weather-severe-alert-symbolic.svg</file>
<file>icons/scalable/status/weather-showers-symbolic.svg</file>
<file>icons/scalable/status/weather-snow-symbolic.svg</file>
<file>hdr-example.heif</file>
<file alias='icons/scalable/apps/org.gtk.WidgetFactory4.svg'>data/scalable/apps/org.gtk.WidgetFactory4.svg</file>
@@ -120,5 +121,12 @@
<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>
<file>color-profile-check.png</file>
<file>color-profile-check.jpeg</file>
<file>color-profile-check.tiff</file>
</gresource>
</gresources>

View File

@@ -1347,13 +1347,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>
@@ -1362,13 +1522,92 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<object class="GtkNotebookPage">
<property name="position">1</property>
<property name="child">
<object class="GtkBox" id="box10">
<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">image loading</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="GtkImage">
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.png</property>
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">PNG</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkImage">
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.jpeg</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">JPEG</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkImage">
<property name="paintable">resource:///org/gtk/WidgetFactory4/color-profile-check.tiff</property>
<layout>
<property name="column">0</property>
<property name="row">3</property>
</layout>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">TIFF</property>
<property name="hexpand">1</property>
<layout>
<property name="column">1</property>
<property name="row">3</property>
</layout>
</object>
</child>
</object>
</property>
<property name="tab">
<object class="GtkLabel" id="label9">
<property name="label" translatable="1">page 2</property>
<property name="label" translatable="1">Images</property>
</object>
</property>
</object>
@@ -1378,12 +1617,26 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
<property name="position">2</property>
<property name="child">
<object class="GtkBox" id="box11">
<property name="orientation">1</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkPicture" id="hdr_picture">
<property name="can-shrink">1</property>
</object>
</child>
<child>
<object class="GtkLabel" id="hdr_label">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="use-markup">1</property>
</object>
</child>
</object>
</property>
<property name="tab">
<object class="GtkLabel" id="label10">
<property name="label" translatable="1">page 3</property>
<property name="label" translatable="1">HDR</property>
</object>
</property>
</object>
@@ -3345,12 +3598,10 @@ bad things might happen.</property>
<attribute name="display-hint">circular-buttons</attribute>
<item>
<attribute name="verb-icon">printer-symbolic</attribute>
<attribute name="label" translatable="yes">Print all the things!</attribute>
<attribute name="action">win.print</attribute>
</item>
<item>
<attribute name="verb-icon">emblem-shared-symbolic</attribute>
<attribute name="label" translatable="yes">Share all the things!</attribute>
<attribute name="action">app.share</attribute>
</item>
</section>
@@ -3365,17 +3616,14 @@ bad things might happen.</property>
<attribute name="label" translatable="yes">Edit</attribute>
<item>
<attribute name="verb-icon">edit-cut-symbolic</attribute>
<attribute name="label" translatable="yes">Cut</attribute>
<attribute name="action">app.cut</attribute>
</item>
<item>
<attribute name="verb-icon">edit-copy-symbolic</attribute>
<attribute name="label" translatable="yes">Copy</attribute>
<attribute name="action">app.copy</attribute>
</item>
<item>
<attribute name="verb-icon">edit-paste-symbolic</attribute>
<attribute name="label" translatable="yes">Paste</attribute>
<attribute name="action">app.paste</attribute>
</item>
</section>

View File

@@ -12,8 +12,8 @@ SYNOPSIS
--------
| **gtk4-builder-tool** <COMMAND> [OPTIONS...] <FILE>
|
| **gtk4-builder-tool** validate [OPTIONS...] <FILE>
| **gtk4-builder-tool** enumerate [OPTIONS...] <FILE>
| **gtk4-builder-tool** validate <FILE>
| **gtk4-builder-tool** enumerate <FILE>
| **gtk4-builder-tool** simplify [OPTIONS...] <FILE>
| **gtk4-builder-tool** preview [OPTIONS...] <FILE>
| **gtk4-builder-tool** screenshot [OPTIONS...] <FILE>
@@ -33,20 +33,12 @@ Validation
The ``validate`` command validates the given UI definition file and reports
errors to ``stderr``.
``--deprecations``
Warn about uses of deprecated types in the UI definition file.
Enumeration
^^^^^^^^^^^
The ``enumerate`` command prints all the named objects that are present in the UI
The ``enumerate`` command lists all the named objects that are present in the UI
definition file.
``--callbacks``
Print the names of callbacks as well.
Preview
^^^^^^^

View File

@@ -1,74 +0,0 @@
Title: Preparing for GTK 5
Slug: gtk-migrating-4-to-5
GTK 5 will be a major new version of GTK that breaks both API and
ABI compared to GTK 4.x. GTK 5 does not exist yet, so we cannot
be entirely sure what will be involved in a migration from GTK 4
to GTK 5. But we can already give some preliminary hints about
the likely changes, and how to prepare for them in code that is
using GTK 4.
### Do not use deprecated symbols
As always, functions and types that are known to go away in the
next major version of GTK are being marked as deprecated in GTK 4.
Removing the use of deprecated APIs is the most important step
to prepare your code for the next major version of GTK. Often,
deprecation notes will include hints about replacement APIs to
help you with this.
Sometimes, it is helpful to have some background information about
the motivation and goals of larger API changes.
## Cell renderers are going away
Cell renderers were introduced in GTK 2 to support rendering of
"big data" UIs, in particular treeviews. Over the years, more
"data-like" widgets have started to use them, and cell renderers
have grown into a shadowy, alternative rendering infrastructure
that duplicates much of what widgets do, while duplicating the
code and adding their own dose of bugs.
In GTK 4, replacement widgets for GtkTreeView, GtkIconView and
GtkComboBox have appeared: GtkListView, GtkColumnView, GtkGridView
and GtkDropDown. For GTK 5, we will take the next step and remove
all cell renderer-based widgets.
## Themed rendering APIs are going away
The old GTK 2 era rendering APIs for theme components like
gtk_render_frame() or gtk_render_check() have not been used by
GTK itself even in later GTK 3, but they have been kepy around
for the benefit of "external drawing" users - applications that
want their controls to look like GTK without using widgets.
Supporting this is increasingly getting in the way of making
the GTK CSS machinery fast and correct. One notable problem is
that temporary style changes (using gtk_style_context_save())
is breaking animations. Therefore, these APIs will be going away
in GTK 5, together with their more modern GtkSnapshot variants
like gtk_snapshot_render_background() or gtk_snapshot_render_focus().
The best way to render parts of your widget using CSS styling
is to use subwidgets. For example, to show a piece of text with
fonts, effects and shadows according to the current CSS style,
use a GtkLabel.
If you have a need for custom drawing that fits into the current
(dark or light) theme, e.g. for rendering a graph, you can still
get the current style foreground color, using
[method@Gtk.Widget.get_style_color].
## Local stylesheets are going away
The cascading part of GTK's CSS implementation is complicated by
the existence of local stylesheets (i.e. those added with
gtk_style_context_add_provider()). And local stylesheets are
unintuitive in that they do not apply to the whole subtree of
widgets, but just to the one widget where the stylesheet was
added.
GTK 5 will no longer provide this functionality. The recommendations
is to use a global stylesheet (i.e. gtk_style_context_add_provider_for_display())
and rely on style classes to make your CSS apply only where desired.

View File

@@ -92,7 +92,8 @@ Specifies a list of directories to search when GTK is looking for
dynamically loaded objects such as input method modules and print
backends. If the path to the dynamically loaded object is given as
an absolute path name, then GTK loads it directly. Otherwise, GTK
goes in turn through the directories in `GTK_PATH`, followed
goes in turn through the directories in `GTK_PATH`, followed by
the directory `.gtk-4.0` in the user's home directory, followed
by the system default directory, which is `libdir/gtk-4.0/modules`.
(If `GTK_EXE_PREFIX` is defined, `libdir` is `$GTK_EXE_PREFIX/lib`.
Otherwise it is the libdir specified when GTK was configured, usually

View File

@@ -1,13 +1,6 @@
Title: Tree and List Widget Overview
Slug: gtk-treeview
This document describes the `GtkTreeView` widget and auxiliary
classes, like tree models and cell renderers. All of these have
been deprecated and will be removed in GTK 5. Their replacements
are described in the [List Widget Overview](section-list-widget.html).
## Introduction
To create a tree or list in GTK, use the `GtkTreeModel` interface in
conjunction with the `GtkTreeView` widget. This widget is designed around
a _Model/View/Controller_ design and consists of four major parts:

View File

@@ -350,8 +350,7 @@ quit_activated (GSimpleAction *action,
}
static void
combo_changed (GtkDropDown *combo,
GParamSpec *pspec,
combo_changed (GtkComboBox *combo,
gpointer user_data)
{
GtkDialog *dialog = user_data;
@@ -360,7 +359,7 @@ combo_changed (GtkDropDown *combo,
char **accels;
char *str;
action = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (combo)));
action = gtk_combo_box_get_active_id (combo);
if (!action)
return;
@@ -389,7 +388,7 @@ response (GtkDialog *dialog,
gpointer user_data)
{
GtkEntry *entry = g_object_get_data (user_data, "entry");
GtkDropDown *combo = g_object_get_data (user_data, "combo");
GtkComboBox *combo = g_object_get_data (user_data, "combo");
const char *action;
const char *str;
char **accels;
@@ -400,7 +399,7 @@ response (GtkDialog *dialog,
return;
}
action = gtk_string_object_get_string (GTK_STRING_OBJECT (gtk_drop_down_get_selected_item (combo)));
action = gtk_combo_box_get_active_id (combo);
if (!action)
return;
@@ -425,7 +424,6 @@ edit_accels (GSimpleAction *action,
char **actions;
GtkWidget *dialog;
int i;
GtkStringList *strings;
dialog = gtk_dialog_new_with_buttons ("Accelerators",
NULL,
@@ -437,8 +435,7 @@ edit_accels (GSimpleAction *action,
gtk_window_set_application (GTK_WINDOW (dialog), app);
actions = gtk_application_list_action_descriptions (app);
strings = gtk_string_list_new (NULL);
combo = gtk_drop_down_new (G_LIST_MODEL (strings), NULL);
combo = gtk_combo_box_text_new ();
g_object_set (gtk_dialog_get_content_area (GTK_DIALOG (dialog)),
"margin-top", 10,
"margin-bottom", 10,
@@ -449,8 +446,8 @@ edit_accels (GSimpleAction *action,
gtk_box_append (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), combo);
for (i = 0; actions[i]; i++)
gtk_string_list_append (strings, actions[i]);
g_signal_connect (combo, "notify::selected", G_CALLBACK (combo_changed), dialog);
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), actions[i], actions[i]);
g_signal_connect (combo, "changed", G_CALLBACK (combo_changed), dialog);
entry = gtk_entry_new ();
gtk_widget_set_hexpand (entry, TRUE);
@@ -461,7 +458,7 @@ edit_accels (GSimpleAction *action,
g_object_set_data (G_OBJECT (dialog), "combo", combo);
g_object_set_data (G_OBJECT (dialog), "entry", entry);
gtk_drop_down_set_selected (GTK_DROP_DOWN (combo), 0);
gtk_combo_box_set_active (GTK_COMBO_BOX (combo), 0);
gtk_widget_show (dialog);
}

View File

@@ -39,26 +39,19 @@ gdk_broadway_cairo_context_begin_frame (GdkDrawContext *draw_context,
{
GdkBroadwayCairoContext *self = GDK_BROADWAY_CAIRO_CONTEXT (draw_context);
GdkSurface *surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self));
cairo_t *cr;
cairo_region_t *repaint_region;
int width, height, scale;
int width, height;
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,
height);
repaint_region = cairo_region_create_rectangle (&(cairo_rectangle_int_t) { 0, 0, width, height });
cairo_region_union (region, repaint_region);
cairo_region_destroy (repaint_region);
/* clear the repaint area */
cr = cairo_create (self->paint_surface);
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
cairo_fill (cr);
cairo_destroy (cr);
}
static void

View File

@@ -262,8 +262,7 @@ _gdk_broadway_events_got_input (GdkDisplay *display,
message->key.state,
FALSE,
&translated,
&translated,
NULL);
&translated);
node = _gdk_event_queue_append (display, event);
_gdk_windowing_got_event (display, node, event, message->base.serial);

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"
@@ -130,6 +130,7 @@ static const GdkDebugKey gdk_debug_keys[] = {
{ "vulkan-validate", GDK_DEBUG_VULKAN_VALIDATE, "Load the Vulkan validation layer", TRUE },
{ "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings", TRUE },
{ "high-depth", GDK_DEBUG_HIGH_DEPTH, "Use high bit depth rendering if possible", TRUE },
{ "srgb", GDK_DEBUG_SRGB, "Force sRRGB rendering and turn off color profiles", TRUE },
};

View File

@@ -31,6 +31,7 @@
#include <gdk/gdkcairo.h>
#include <gdk/gdkcairocontext.h>
#include <gdk/gdkclipboard.h>
#include <gdk/gdkcolorspace.h>
#include <gdk/gdkconfig.h>
#include <gdk/gdkcontentdeserializer.h>
#include <gdk/gdkcontentformats.h>

View File

@@ -1,5 +1,5 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2005 Red Hat, Inc.
* Copyright (C) 2005 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
@@ -19,6 +19,10 @@
#include "gdkcairoprivate.h"
#include "gdkcolorspace.h"
#include "gdkcolorprivate.h"
#include "gdkmemoryformatprivate.h"
#include <math.h>
/**
@@ -32,14 +36,20 @@ 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_space (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],
gdk_color_get_alpha (&color));
gdk_color_finish (&color);
}
/**
@@ -335,3 +345,97 @@ gdk_cairo_region_from_clip (cairo_t *cr)
return region;
}
static cairo_user_data_key_t color_space_key;
/**
* gdk_cairo_surface_set_color_space:
* @surface: a surface
* @color_space: the color space to attach to the surface
*
* Attaches a `GdkColorSpace` 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 space, so if you want to use the surface
* as a target for rendering in a color managed way, you should use
* such a color space.
*
* The default color space is assumed to be sRGB, which is not
* linear.
*
* Since: 4.10
*/
void
gdk_cairo_surface_set_color_space (cairo_surface_t *surface,
GdkColorSpace *color_space)
{
g_return_if_fail (surface != NULL);
g_return_if_fail (GDK_IS_COLOR_SPACE (color_space));
cairo_surface_set_user_data (surface,
&color_space_key,
g_object_ref (color_space),
g_object_unref);
}
/**
* gdk_cairo_surface_get_color_space:
* @surface: a surface
*
* Gets the color space GTK assumes for the surface. See
* [method@Gdk.CairoSurface.set_color_space] for details.
*
* Returns: (transfer none): the color space
*
* Since: 4.10
*/
GdkColorSpace *
gdk_cairo_surface_get_color_space (cairo_surface_t *surface)
{
GdkColorSpace *color_space;
g_return_val_if_fail (surface != NULL, gdk_color_space_get_srgb ());
color_space = cairo_surface_get_user_data (surface, &color_space_key);
if (color_space == NULL)
color_space = gdk_color_space_get_srgb ();
return color_space;
}
/**
* gdk_cairo_get_color_space:
* @cr: a cairo context
*
* Gets the color space GTK assumes for the cairo context.
*
* Returns: (transfer none): the color space
*
* Since: 4.10
*/
GdkColorSpace *
gdk_cairo_get_color_space (cairo_t *cr)
{
GdkColorSpace *color_space;
cairo_surface_t *surface;
g_return_val_if_fail (cr != NULL, gdk_color_space_get_srgb ());
surface = cairo_get_group_target (cr);
color_space = cairo_surface_get_user_data (surface, &color_space_key);
if (color_space != NULL)
return color_space;
/* theoretically, we should walk the whole group stack, but I don't
* think Cairo lets us do that
*/
surface = cairo_get_target (cr);
color_space = cairo_surface_get_user_data (surface, &color_space_key);
if (color_space != NULL)
return color_space;
return gdk_color_space_get_srgb ();
}

View File

@@ -1,5 +1,5 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2005 Red Hat, Inc.
* Copyright (C) 2005 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
@@ -46,9 +46,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_10
void gdk_cairo_surface_set_color_space (cairo_surface_t *surface,
GdkColorSpace *color_space);
GDK_AVAILABLE_IN_4_10
GdkColorSpace * gdk_cairo_surface_get_color_space (cairo_surface_t *surface);
GDK_AVAILABLE_IN_4_10
GdkColorSpace * gdk_cairo_get_color_space (cairo_t *cr);
GDK_DEPRECATED_IN_4_6_FOR(gdk_gl_texture_new)
void gdk_cairo_draw_from_gl (cairo_t *cr,

273
gdk/gdkcicpcolorspace.c Normal file
View File

@@ -0,0 +1,273 @@
/* gdkcicpcolorspace.c
*
* Copyright 2022 (c) 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/>.
*/
#include "config.h"
#include "gdkcicpcolorspaceprivate.h"
#include "gdklcmscolorspaceprivate.h"
#include <glib/gi18n-lib.h>
struct _GdkCicpColorSpace
{
GdkColorSpace parent_instance;
int color_primaries;
int transfer_characteristics;
int matrix_coefficients;
gboolean full_range;
GdkColorSpace *lcms;
};
struct _GdkCicpColorSpaceClass
{
GdkColorSpaceClass parent_class;
};
G_DEFINE_TYPE (GdkCicpColorSpace, gdk_cicp_color_space, GDK_TYPE_COLOR_SPACE)
static gboolean
gdk_cicp_color_space_supports_format (GdkColorSpace *space,
GdkMemoryFormat format)
{
GdkCicpColorSpace *self = GDK_CICP_COLOR_SPACE (space);
if (self->lcms)
return gdk_color_space_supports_format (self->lcms, format);
return FALSE;
}
static GBytes *
gdk_cicp_color_space_save_to_icc_profile (GdkColorSpace *space,
GError **error)
{
GdkCicpColorSpace *self = GDK_CICP_COLOR_SPACE (space);
if (self->lcms)
return gdk_color_space_save_to_icc_profile (self->lcms, error);
return NULL;
}
static int
gdk_cicp_color_space_get_n_components (GdkColorSpace *space)
{
GdkCicpColorSpace *self = GDK_CICP_COLOR_SPACE (space);
if (self->lcms)
return gdk_color_space_get_n_components (self->lcms);
return 0;
}
static void
gdk_cicp_color_space_dispose (GObject *object)
{
GdkCicpColorSpace *self = GDK_CICP_COLOR_SPACE (object);
g_clear_object (&self->lcms);
G_OBJECT_CLASS (gdk_cicp_color_space_parent_class)->dispose (object);
}
static void
gdk_cicp_color_space_class_init (GdkCicpColorSpaceClass *klass)
{
GdkColorSpaceClass *color_space_class = GDK_COLOR_SPACE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
color_space_class->supports_format = gdk_cicp_color_space_supports_format;
color_space_class->save_to_icc_profile = gdk_cicp_color_space_save_to_icc_profile;
color_space_class->get_n_components = gdk_cicp_color_space_get_n_components;
gobject_class->dispose = gdk_cicp_color_space_dispose;
}
static void
gdk_cicp_color_space_init (GdkCicpColorSpace *self)
{
}
static GdkColorSpace *
lcms_from_cicp (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range)
{
cmsHPROFILE profile = NULL;
cmsCIExyY whitepoint;
cmsCIExyYTRIPLE primaries;
cmsToneCurve *curve[3];
cmsCIExyY whiteD65 = (cmsCIExyY) { 0.3127, 0.3290, 1.0 };
cmsCIExyY whiteC = (cmsCIExyY) { 0.310, 0.316, 1.0 };
cmsFloat64Number srgb_parameters[5] =
{ 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
cmsFloat64Number rec709_parameters[5] =
{ 2.2, 1.0 / 1.099, 0.099 / 1.099, 1.0 / 4.5, 0.081 };
/* We only support full-range RGB profiles */
g_assert (matrix_coefficients == 0);
g_assert (full_range);
if (color_primaries == 0 /* ITU_R_BT_709_5 */)
{
if (transfer_characteristics == 13 /* IEC_61966_2_1 */)
return g_object_ref (gdk_color_space_get_srgb ());
else if (transfer_characteristics == 8 /* linear */)
return g_object_ref (gdk_color_space_get_srgb_linear ());
}
switch (color_primaries)
{
case 1:
primaries.Green = (cmsCIExyY) { 0.300, 0.600, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.150, 0.060, 1.0 };
primaries.Red = (cmsCIExyY) { 0.640, 0.330, 1.0 };
whitepoint = whiteD65;
break;
case 4:
primaries.Green = (cmsCIExyY) { 0.21, 0.71, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.14, 0.08, 1.0 };
primaries.Red = (cmsCIExyY) { 0.67, 0.33, 1.0 };
whitepoint = whiteC;
break;
case 5:
primaries.Green = (cmsCIExyY) { 0.29, 0.60, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.15, 0.06, 1.0 };
primaries.Red = (cmsCIExyY) { 0.64, 0.33, 1.0 };
whitepoint = whiteD65;
break;
case 6:
case 7:
primaries.Green = (cmsCIExyY) { 0.310, 0.595, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.155, 0.070, 1.0 };
primaries.Red = (cmsCIExyY) { 0.630, 0.340, 1.0 };
whitepoint = whiteD65;
break;
case 8:
primaries.Green = (cmsCIExyY) { 0.243, 0.692, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.145, 0.049, 1.0 };
primaries.Red = (cmsCIExyY) { 0.681, 0.319, 1.0 };
whitepoint = whiteC;
break;
case 9:
primaries.Green = (cmsCIExyY) { 0.170, 0.797, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.131, 0.046, 1.0 };
primaries.Red = (cmsCIExyY) { 0.708, 0.292, 1.0 };
whitepoint = whiteD65;
break;
case 10:
primaries.Green = (cmsCIExyY) { 0.0, 1.0, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.0, 0.0, 1.0 };
primaries.Red = (cmsCIExyY) { 1.0, 0.0, 1.0 };
whitepoint = (cmsCIExyY) { 0.333333, 0.333333, 1.0 };
break;
case 11:
primaries.Green = (cmsCIExyY) { 0.265, 0.690, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.150, 0.060, 1.0 };
primaries.Red = (cmsCIExyY) { 0.680, 0.320, 1.0 };
whitepoint = (cmsCIExyY) { 0.314, 0.351, 1.0 };
break;
case 12:
primaries.Green = (cmsCIExyY) { 0.265, 0.690, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.150, 0.060, 1.0 };
primaries.Red = (cmsCIExyY) { 0.680, 0.320, 1.0 };
whitepoint = whiteD65;
break;
case 22:
primaries.Green = (cmsCIExyY) { 0.295, 0.605, 1.0 };
primaries.Blue = (cmsCIExyY) { 0.155, 0.077, 1.0 };
primaries.Red = (cmsCIExyY) { 0.630, 0.340, 1.0 };
whitepoint = whiteD65;
break;
default:
return NULL;
}
switch (transfer_characteristics)
{
case 1: /* ITU_R_BT_709_5 */
curve[0] = curve[1] = curve[2] = cmsBuildParametricToneCurve (NULL, 4,
rec709_parameters);
profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
cmsFreeToneCurve (curve[0]);
break;
case 4: /* ITU_R_BT_470_6_System_M */
curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 2.2f);
profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
cmsFreeToneCurve (curve[0]);
break;
case 5: /* ITU_R_BT_470_6_System_B_G */
curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 2.8f);
profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
cmsFreeToneCurve (curve[0]);
break;
case 8: /* linear */
curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 1.0f);
profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
cmsFreeToneCurve (curve[0]);
break;
/* FIXME
* We need to handle at least 16 (PQ) here.
* Problem is: lcms can't do it
*/
case 13: /* IEC_61966_2_1 */
default:
curve[0] = curve[1] = curve[2] = cmsBuildParametricToneCurve (NULL, 4,
srgb_parameters);
profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
cmsFreeToneCurve (curve[0]);
break;
}
if (profile)
return gdk_lcms_color_space_new_from_lcms_profile (profile);
return NULL;
}
GdkColorSpace *
gdk_color_space_new_from_cicp (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range)
{
GdkCicpColorSpace *result;
result = g_object_new (GDK_TYPE_CICP_COLOR_SPACE, NULL);
result->color_primaries = color_primaries;
result->transfer_characteristics = transfer_characteristics;
result->matrix_coefficients = matrix_coefficients;
result->full_range = full_range;
result->lcms = lcms_from_cicp (color_primaries,
transfer_characteristics,
matrix_coefficients,
full_range);
return GDK_COLOR_SPACE (result);
}
GdkColorSpace *
gdk_cicp_color_space_get_lcms_color_space (GdkColorSpace *space)
{
GdkCicpColorSpace *self = GDK_CICP_COLOR_SPACE (space);
return self->lcms;
}

View File

@@ -0,0 +1,45 @@
/* gdkcicpcolorspaceprivate.h
*
* Copyright 2022 (c) 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/>.
*/
#ifndef __GDK_CICP_COLOR_SPACE_PRIVATE_H__
#define __GDK_CICP_COLOR_SPACE_PRIVATE_H__
#include "gdkcolorspaceprivate.h"
G_BEGIN_DECLS
#define GDK_TYPE_CICP_COLOR_SPACE (gdk_cicp_color_space_get_type ())
#define GDK_CICP_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CICP_COLOR_SPACE, GdkCicpColorSpace))
#define GDK_IS_CICP_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CICP_COLOR_SPACE))
#define GDK_CICP_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CICP_COLOR_SPACE, GdkCicpColorSpaceClass))
#define GDK_IS_CICP_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CICP_COLOR_SPACE))
#define GDK_CICP_COLOR_SPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CICP_COLOR_SPACE, GdkCicpColorSpaceClass))
typedef struct _GdkCicpColorSpace GdkCicpColorSpace;
typedef struct _GdkCicpColorSpaceClass GdkCicpColorSpaceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkCicpColorSpace, g_object_unref)
GType gdk_cicp_color_space_get_type (void) G_GNUC_CONST;
GdkColorSpace * gdk_cicp_color_space_get_lcms_color_space (GdkColorSpace *self);
G_END_DECLS
#endif /* __GDK_CICP_COLOR_SPACE_PRIVATE_H__ */

115
gdk/gdkcolor.c Normal file
View File

@@ -0,0 +1,115 @@
/* 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 "gdkcolorspaceprivate.h"
#include "gdklcmscolorspaceprivate.h"
#include <lcms2.h>
static inline cmsHTRANSFORM *
gdk_color_get_transform (GdkColorSpace *src,
GdkColorSpace *dest)
{
return gdk_color_space_lookup_transform (src, TYPE_RGBA_FLT, dest, TYPE_RGBA_FLT);
}
void
gdk_color_convert (GdkColor *self,
GdkColorSpace *color_space,
const GdkColor *other)
{
gdk_color_init (self,
color_space,
other->alpha,
NULL,
gdk_color_space_get_n_components (color_space));
cmsDoTransform (gdk_color_get_transform (other->color_space, color_space),
gdk_color_get_components (other),
(float *) gdk_color_get_components (self),
1);
}
void
gdk_color_convert_rgba (GdkColor *self,
GdkColorSpace *color_space,
const GdkRGBA *rgba)
{
gdk_color_init (self,
color_space,
rgba->alpha,
NULL,
gdk_color_space_get_n_components (color_space));
cmsDoTransform (gdk_color_get_transform (gdk_color_space_get_srgb (), color_space),
(float[3]) { rgba->red, rgba->green, rgba->blue },
(float *) gdk_color_get_components (self),
1);
}
void
gdk_color_mix (GdkColor *self,
GdkColorSpace *color_space,
const GdkColor *src1,
const GdkColor *src2,
double progress)
{
if (src1->color_space != color_space)
{
GdkColor tmp;
gdk_color_convert (&tmp, color_space, src1);
gdk_color_mix (self, color_space, &tmp, src2, progress);
}
else if (src2->color_space != color_space)
{
GdkColor tmp;
gdk_color_convert (&tmp, color_space, src2);
gdk_color_mix (self, color_space, src1, &tmp, progress);
}
else
{
gsize i, n;
const float *s1, *s2;
float *d;
n = gdk_color_space_get_n_components (color_space);
gdk_color_init (self,
color_space,
src1->alpha * (1.0 - progress) + src2->alpha * progress,
NULL, n);
d = (float *) gdk_color_get_components (self);
s1 = gdk_color_get_components (src1);
s2 = gdk_color_get_components (src2);
if (self->alpha == 0)
{
for (i = 0; i < n; i++)
d[i] = s1[i] * (1.0 - progress) + s2[i] * progress;
}
else
{
for (i = 0; i < n; i++)
d[i] = (s1[i] * src1->alpha * (1.0 - progress) + s2[i] * src2->alpha * progress) / self->alpha;
}
}
}

73
gdk/gdkcolorprivate.h Normal file
View File

@@ -0,0 +1,73 @@
/* 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/>.
*/
#ifndef __GDK_COLOR_PRIVATE_H__
#define __GDK_COLOR_PRIVATE_H__
#include <gdk/gdkcolorspace.h>
#include <gdk/gdkrgba.h>
/* RGB - and it makes the struct size a multiple of 8 bytes, ie pointer-aligned */
#define GDK_COLOR_MAX_NATIVE_COMPONENTS 3
typedef struct _GdkColor GdkColor;
struct _GdkColor
{
GdkColorSpace *color_space;
float alpha;
union {
float values[GDK_COLOR_MAX_NATIVE_COMPONENTS];
float *components;
};
};
G_STATIC_ASSERT (sizeof (GdkColor) % sizeof (gpointer) == 0);
static inline void gdk_color_init (GdkColor *self,
GdkColorSpace *color_space,
float alpha,
float *components,
gsize n_components);
static inline void gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba);
static inline void gdk_color_finish (GdkColor *self);
void gdk_color_convert (GdkColor *self,
GdkColorSpace *color_space,
const GdkColor *other);
void gdk_color_convert_rgba (GdkColor *self,
GdkColorSpace *color_space,
const GdkRGBA *rgba);
void gdk_color_mix (GdkColor *self,
GdkColorSpace *color_space,
const GdkColor *src1,
const GdkColor *src2,
double progress);
static inline GdkColorSpace * gdk_color_get_color_space (const GdkColor *self);
static inline float gdk_color_get_alpha (const GdkColor *self);
static inline const float * gdk_color_get_components (const GdkColor *self);
static inline gsize gdk_color_get_n_components (const GdkColor *self);
#include "gdkcolorprivateimpl.h"
G_END_DECLS
#endif

97
gdk/gdkcolorprivateimpl.h Normal file
View File

@@ -0,0 +1,97 @@
/* 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/>.
*/
static inline gboolean
gdk_color_is_allocated (const GdkColor *self)
{
return GPOINTER_TO_SIZE (self->color_space) & 1;
}
static inline void
gdk_color_init (GdkColor *self,
GdkColorSpace *color_space,
float alpha,
float *components,
gsize n_components)
{
gboolean allocated = n_components > GDK_COLOR_MAX_NATIVE_COMPONENTS;
g_assert (n_components == gdk_color_space_get_n_components (color_space));
self->color_space = GSIZE_TO_POINTER (GPOINTER_TO_SIZE (g_object_ref (color_space)) | allocated);
self->alpha = alpha;
if (allocated)
{
if (components)
self->components = g_memdup (components, sizeof (float) * n_components);
else
self->components = g_new (float, n_components);
}
else
{
if (components)
memcpy (self->values, components, sizeof (float) * n_components);
}
}
static inline void
gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba)
{
gdk_color_init (self,
gdk_color_space_get_srgb (),
rgba->alpha,
(float[3]) { rgba->red, rgba->green, rgba->blue },
3);
}
static inline void
gdk_color_finish (GdkColor *self)
{
if (gdk_color_is_allocated (self))
g_free (self->components);
g_object_unref (gdk_color_get_color_space (self));
}
static inline GdkColorSpace *
gdk_color_get_color_space (const GdkColor *self)
{
return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (self->color_space) & ~1);
}
static inline float
gdk_color_get_alpha (const GdkColor *self)
{
return self->alpha;
}
static inline const float *
gdk_color_get_components (const GdkColor *self)
{
if (gdk_color_is_allocated (self))
return self->components;
else
return self->values;
}
static inline gsize
gdk_color_get_n_components (const GdkColor *self)
{
return gdk_color_space_get_n_components (gdk_color_get_color_space (self));
}

227
gdk/gdkcolorspace.c Normal file
View File

@@ -0,0 +1,227 @@
/* gdkcolor_space.c
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* GdkColorSpace:
*
* `GdkColorSpace` is used to describe color spaces.
*
* Tell developers what a color space is instead of just linking to
* https://en.wikipedia.org/wiki/Color_space
*
* `GdkColorSpace` objects are immutable and therefore threadsafe.
*
* Since: 4.10
*/
#include "config.h"
#include "gdkcolorspaceprivate.h"
#include <glib/gi18n-lib.h>
enum {
PROP_0,
N_PROPS
};
//static GParamSpec *properties[N_PROPS];
G_DEFINE_TYPE (GdkColorSpace, gdk_color_space, G_TYPE_OBJECT)
static gboolean
gdk_color_space_default_supports_format (GdkColorSpace *self,
GdkMemoryFormat format)
{
return FALSE;
}
static GBytes *
gdk_color_space_default_save_to_icc_profile (GdkColorSpace *self,
GError **error)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("This color space does not support ICC profiles"));
return NULL;
}
static int
gdk_color_space_default_get_n_components (GdkColorSpace *self)
{
return 0;
}
static gboolean
gdk_color_space_default_equal (GdkColorSpace *profile1,
GdkColorSpace *profile2)
{
return profile1 == profile2;
}
static void
gdk_color_space_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
//GdkColorSpace *self = GDK_COLOR_SPACE (gobject);
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gdk_color_space_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
//GdkColorSpace *self = GDK_COLOR_SPACE (gobject);
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
gdk_color_space_dispose (GObject *object)
{
//GdkColorSpace *self = GDK_COLOR_SPACE (object);
G_OBJECT_CLASS (gdk_color_space_parent_class)->dispose (object);
}
static void
gdk_color_space_class_init (GdkColorSpaceClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->supports_format = gdk_color_space_default_supports_format;
klass->save_to_icc_profile = gdk_color_space_default_save_to_icc_profile;
klass->get_n_components = gdk_color_space_default_get_n_components;
klass->equal = gdk_color_space_default_equal;
gobject_class->set_property = gdk_color_space_set_property;
gobject_class->get_property = gdk_color_space_get_property;
gobject_class->dispose = gdk_color_space_dispose;
}
static void
gdk_color_space_init (GdkColorSpace *self)
{
}
/**
* gdk_color_space_supports_format:
* @self: a `GdkColorSpace`
* @format: the format to check
*
* Checks if this color space can be used with textures in the given format.
*
* Returns: %TRUE if this colorspace supports the format
*
* Since: 4.10
**/
gboolean
gdk_color_space_supports_format (GdkColorSpace *self,
GdkMemoryFormat format)
{
g_return_val_if_fail (GDK_IS_COLOR_SPACE (self), FALSE);
g_return_val_if_fail (format < GDK_MEMORY_N_FORMATS, FALSE);
return GDK_COLOR_SPACE_GET_CLASS (self)->supports_format (self, format);
}
/**
* gdk_color_space_save_to_icc_profile:
* @self: a `GdkColorSpace`
* @error: Return location for an error
*
* Saves the color space to an
* [ICC profile](https://en.wikipedia.org/wiki/ICC_profile).
*
* Some color spaces cannot be represented as ICC profiles. In
* that case, an error will be set and %NULL will be returned.
*
* Returns: (nullable): A new `GBytes` containing the ICC profile
*
* Since: 4.10
**/
GBytes *
gdk_color_space_save_to_icc_profile (GdkColorSpace *self,
GError **error)
{
g_return_val_if_fail (GDK_IS_COLOR_SPACE (self), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return GDK_COLOR_SPACE_GET_CLASS (self)->save_to_icc_profile (self, error);
}
gboolean
gdk_color_space_is_linear (GdkColorSpace *self)
{
g_return_val_if_fail (GDK_IS_COLOR_SPACE (self), FALSE);
return self == gdk_color_space_get_srgb_linear ();
}
int
gdk_color_space_get_n_components (GdkColorSpace *self)
{
g_return_val_if_fail (GDK_IS_COLOR_SPACE (self), 0);
return GDK_COLOR_SPACE_GET_CLASS (self)->get_n_components (self);
}
/**
* gdk_color_space_equal:
* @profile1: (type GdkColorSpace): a `GdkColorSpace`
* @profile2: (type GdkColorSpace): another `GdkColorSpace`
*
* Compares two `GdkColorSpace`s for equality.
*
* Note that this function is not guaranteed to be perfect and two objects
* describing the same color space may compare not equal. However, different
* color spaces will never compare equal.
*
* Returns: %TRUE if the two color profiles compare equal
*
* Since: 4.10
*/
gboolean
gdk_color_space_equal (gconstpointer profile1,
gconstpointer profile2)
{
if (profile1 == profile2)
return TRUE;
if (GDK_COLOR_SPACE_GET_CLASS (profile1) == GDK_COLOR_SPACE_GET_CLASS (profile2))
return GDK_COLOR_SPACE_GET_CLASS (profile1)->equal (GDK_COLOR_SPACE (profile1),
GDK_COLOR_SPACE (profile2));
return FALSE;
}

81
gdk/gdkcolorspace.h Normal file
View File

@@ -0,0 +1,81 @@
/* gdkcolor_space.h
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_COLOR_SPACE_H__
#define __GDK_COLOR_SPACE_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdkversionmacros.h>
#include <gdk/gdktypes.h>
#include <gdk/gdkenums.h>
G_BEGIN_DECLS
#define GDK_TYPE_COLOR_SPACE (gdk_color_space_get_type ())
#define GDK_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_COLOR_SPACE, GdkColorSpace))
#define GDK_IS_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_COLOR_SPACE))
#define GDK_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_COLOR_SPACE, GdkColorSpaceClass))
#define GDK_IS_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_COLOR_SPACE))
#define GDK_COLOR_SPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_COLOR_SPACE, GdkColorSpaceClass))
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkColorSpace, g_object_unref)
typedef struct _GdkColorSpaceClass GdkColorSpaceClass;
GDK_AVAILABLE_IN_4_10
GType gdk_color_space_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_10
GdkColorSpace * gdk_color_space_get_srgb (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_10
GdkColorSpace * gdk_color_space_new_from_icc_profile (GBytes *icc_profile,
GError **error);
GDK_AVAILABLE_IN_4_10
GdkColorSpace * gdk_color_space_new_from_cicp (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range);
GDK_AVAILABLE_IN_4_10
gboolean gdk_color_space_supports_format (GdkColorSpace *self,
GdkMemoryFormat format);
GDK_AVAILABLE_IN_4_10
GBytes * gdk_color_space_save_to_icc_profile (GdkColorSpace *self,
GError **error);
GDK_AVAILABLE_IN_4_10
gboolean gdk_color_space_is_linear (GdkColorSpace *self);
GDK_AVAILABLE_IN_4_10
int gdk_color_space_get_n_components (GdkColorSpace *self);
GDK_AVAILABLE_IN_4_10
gboolean gdk_color_space_equal (gconstpointer profile1,
gconstpointer profile2);
G_END_DECLS
#endif /* __GDK_COLOR_SPACE_H__ */

View File

@@ -0,0 +1,39 @@
#ifndef __GDK_COLOR_SPACE_PRIVATE_H__
#define __GDK_COLOR_SPACE_PRIVATE_H__
#include "gdkcolorspace.h"
#include <lcms2.h>
G_BEGIN_DECLS
struct _GdkColorSpace
{
GObject parent_instance;
};
struct _GdkColorSpaceClass
{
GObjectClass parent_class;
gboolean (* supports_format) (GdkColorSpace *self,
GdkMemoryFormat format);
GBytes * (* save_to_icc_profile) (GdkColorSpace *self,
GError **error);
int (* get_n_components) (GdkColorSpace *self);
gboolean (* equal) (GdkColorSpace *profile1,
GdkColorSpace *profile2);
};
GdkColorSpace * gdk_color_space_get_srgb_linear (void) G_GNUC_CONST;
cmsHTRANSFORM * gdk_color_space_lookup_transform (GdkColorSpace *source,
guint source_type,
GdkColorSpace *dest,
guint dest_type);
G_END_DECLS
#endif /* __GDK_COLOR_SPACE_PRIVATE_H__ */

View File

@@ -16,8 +16,6 @@ G_BEGIN_DECLS
#mesondefine GDK_WINDOWING_WAYLAND
#mesondefine GDK_WINDOWING_WIN32
#mesondefine GDK_RENDERING_CAIRO
#mesondefine GDK_RENDERING_GL
#mesondefine GDK_RENDERING_VULKAN
G_END_DECLS

View File

@@ -879,7 +879,7 @@ file_text_serializer (GdkContentSerializer *serializer)
g_string_append (str, path);
g_free (path);
if (l->next)
g_string_append (str, "\n");
g_string_append (str, " ");
}
path = g_string_free (str, FALSE);
}

View File

@@ -51,6 +51,7 @@ typedef enum {
GDK_DEBUG_VULKAN_VALIDATE = 1 << 23,
GDK_DEBUG_DEFAULT_SETTINGS= 1 << 24,
GDK_DEBUG_HIGH_DEPTH = 1 << 25,
GDK_DEBUG_SRGB = 1 << 26,
} GdkDebugFlags;
extern guint _gdk_debug_flags;

View File

@@ -1517,16 +1517,6 @@ gdk_button_event_get_button (GdkEvent *event)
* An event related to a key-based device.
*/
static void
gdk_key_event_finalize (GdkEvent *event)
{
GdkKeyEvent *self = (GdkKeyEvent *) event;
g_free (self->compose_sequence);
GDK_EVENT_SUPER (event)->finalize (event);
}
static GdkModifierType
gdk_key_event_get_state (GdkEvent *event)
{
@@ -1538,7 +1528,7 @@ gdk_key_event_get_state (GdkEvent *event)
static const GdkEventTypeInfo gdk_key_event_info = {
sizeof (GdkKeyEvent),
NULL,
gdk_key_event_finalize,
NULL,
gdk_key_event_get_state,
NULL,
NULL,
@@ -1562,10 +1552,6 @@ GDK_DEFINE_EVENT_TYPE (GdkKeyEvent, gdk_key_event,
* @is_modifier: whether the event is a modifiers only event
* @translated: the translated key data for the given @state
* @no_lock: the translated key data without the given @state
* @compose_sequence: (transfer none) (nullable):
* The compose sequence string, either partial or only the
* final composed string, if that can be determined at event
* creation time. Used by selected IM modules.
*
* Creates a new `GdkKeyEvent`.
*
@@ -1580,8 +1566,7 @@ gdk_key_event_new (GdkEventType type,
GdkModifierType state,
gboolean is_modifier,
GdkTranslatedKey *translated,
GdkTranslatedKey *no_lock,
char *compose_sequence)
GdkTranslatedKey *no_lock)
{
g_return_val_if_fail (type == GDK_KEY_PRESS ||
type == GDK_KEY_RELEASE, NULL);
@@ -1594,7 +1579,6 @@ gdk_key_event_new (GdkEventType type,
self->key_is_modifier = is_modifier;
self->translated[0] = *translated;
self->translated[1] = *no_lock;
self->compose_sequence = g_strdup (compose_sequence);
return event;
}
@@ -1625,26 +1609,6 @@ gdk_key_event_get_translated_key (GdkEvent *event,
return &(self->translated[0]);
}
/*< private >
* gdk_key_event_get_compose_sequence:
* @event: (type GdkKeyEvent): a key event
*
* Extracts the compose sequence string from a key event.
*
* Returns: (transfer none): the compose sequence string
*/
char *
gdk_key_event_get_compose_sequence (GdkEvent *event)
{
GdkKeyEvent *self = (GdkKeyEvent *) event;
g_return_val_if_fail (GDK_IS_EVENT (event), 0);
g_return_val_if_fail (GDK_IS_EVENT_TYPE (event, GDK_KEY_PRESS) ||
GDK_IS_EVENT_TYPE (event, GDK_KEY_RELEASE), FALSE);
return self->compose_sequence;
}
/**
* gdk_key_event_get_keyval:
* @event: (type GdkKeyEvent): a key event

View File

@@ -259,9 +259,6 @@ typedef struct {
* @keycode: the raw code of the key that was pressed or released.
* @translated: the result of translating @keycode. First with the full
* @state, then while ignoring Caps Lock.
* @compose_sequence: optional string for use by selected IM modules.
* Contains either partial compose sequences or the final composed
* string of the keystroke sequence.
*
* Describes a key press or key release event.
*/
@@ -273,7 +270,6 @@ struct _GdkKeyEvent
guint32 keycode;
gboolean key_is_modifier;
GdkTranslatedKey translated[2];
char *compose_sequence;
};
/*
@@ -474,8 +470,7 @@ GdkEvent * gdk_key_event_new (GdkEventType type,
GdkModifierType modifiers,
gboolean is_modifier,
GdkTranslatedKey *translated,
GdkTranslatedKey *no_lock,
char *compose_sequence);
GdkTranslatedKey *no_lock);
GdkEvent * gdk_focus_event_new (GdkSurface *surface,
GdkDevice *device,
@@ -602,8 +597,6 @@ GdkEvent * gdk_grab_broken_event_new (GdkSurface *surface,
GdkTranslatedKey * gdk_key_event_get_translated_key (GdkEvent *event,
gboolean no_lock);
char * gdk_key_event_get_compose_sequence (GdkEvent *event);
typedef enum
{
/* Following flag is set for events on the event queue during
@@ -633,6 +626,7 @@ void _gdk_event_queue_flush (GdkDisplay *display);
double * gdk_event_dup_axes (GdkEvent *event);
G_END_DECLS
#endif /* __GDK_EVENTS_PRIVATE_H__ */

View File

@@ -23,6 +23,7 @@
#include "gdkdisplayprivate.h"
#include "gdkglcontextprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkcolorspace.h"
#include "gdkmemorytextureprivate.h"
#include "gdktextureprivate.h"
@@ -38,6 +39,7 @@ struct _GdkGLTexture {
GdkTexture parent_instance;
GdkGLContext *context;
GdkGLTextureFlags flags;
guint id;
GdkTexture *saved;
@@ -115,6 +117,7 @@ typedef struct _Download Download;
struct _Download
{
GdkMemoryFormat format;
GdkColorSpace *color_space;
guchar *data;
gsize stride;
};
@@ -157,7 +160,7 @@ gdk_gl_texture_do_download (gpointer texture_,
expected_stride = texture->width * gdk_memory_format_bytes_per_pixel (download->format);
if (download->stride == expected_stride &&
!gdk_gl_context_get_use_es (self->context) &&
!gdk_gl_context_get_use_es (self->context) &&
gdk_memory_format_gl_format (download->format, TRUE, &gl_internal_format, &gl_format, &gl_type))
{
glGetTexImage (GL_TEXTURE_2D,
@@ -193,7 +196,7 @@ gdk_gl_texture_do_download (gpointer texture_,
(download->stride == expected_stride))
{
glReadPixels (0, 0,
texture->width, texture->height,
texture->width, texture->height,
gl_read_format,
gl_read_type,
download->data);
@@ -204,7 +207,7 @@ gdk_gl_texture_do_download (gpointer texture_,
guchar *pixels = g_malloc_n (texture->width * actual_bpp, texture->height);
glReadPixels (0, 0,
texture->width, texture->height,
texture->width, texture->height,
gl_read_format,
gl_read_type,
pixels);
@@ -212,9 +215,11 @@ gdk_gl_texture_do_download (gpointer texture_,
gdk_memory_convert (download->data,
download->stride,
download->format,
download->color_space,
pixels,
texture->width * actual_bpp,
actual_format,
gdk_color_space_get_srgb (),
texture->width,
texture->height);
@@ -228,6 +233,7 @@ gdk_gl_texture_do_download (gpointer texture_,
static void
gdk_gl_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
@@ -236,11 +242,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_space, data, stride);
return;
}
download.format = format;
download.color_space = color_space;
download.data = data;
download.stride = stride;
@@ -275,6 +282,12 @@ gdk_gl_texture_get_id (GdkGLTexture *self)
return self->id;
}
GdkGLTextureFlags
gdk_gl_texture_get_flags (GdkGLTexture *self)
{
return self->flags;
}
/**
* gdk_gl_texture_release:
* @self: a `GdkTexture` wrapping a GL texture
@@ -295,7 +308,8 @@ gdk_gl_texture_release (GdkGLTexture *self)
texture = GDK_TEXTURE (self);
self->saved = GDK_TEXTURE (gdk_memory_texture_from_texture (texture,
gdk_texture_get_format (texture)));
gdk_texture_get_format (texture),
gdk_texture_get_color_space (texture)));
if (self->destroy)
{
@@ -428,6 +442,10 @@ gdk_gl_texture_determine_format (GdkGLTexture *self)
* which will happen when the GdkTexture object is finalized, or due to
* an explicit call of [method@Gdk.GLTexture.release].
*
* The texture data is assumed to be premultiplied, not flipped, and in the
* sRGB colorspace, see [ctor@Gdk.GLTexture.new_with_color_profile] to override
* this.
*
* Return value: (transfer full) (type GdkGLTexture): A newly-created
* `GdkTexture`
*/
@@ -438,6 +456,46 @@ gdk_gl_texture_new (GdkGLContext *context,
int height,
GDestroyNotify destroy,
gpointer data)
{
return gdk_gl_texture_new_with_color_space (context, id,
width, height,
GDK_GL_TEXTURE_PREMULTIPLIED,
gdk_color_space_get_srgb (),
destroy, data);
}
/**
* gdk_gl_texture_new_with_color_space:
* @context: a `GdkGLContext`
* @id: the ID of a texture that was created with @context
* @width: the nominal width of the texture
* @height: the nominal height of the texture
* @flags: flags that describe the content of the texture
* @color_space: the `GdkColorSpace` for the content of the texture
* @destroy: a destroy notify that will be called when the GL resources
* are released
* @data: data that gets passed to @destroy
*
* Creates a new texture for an existing GL texture with a given color space
* and flags.
*
* Note that the GL texture must not be modified until @destroy is called,
* which will happen when the `GdkTexture` object is finalized, or due to
* an explicit call of [method@Gdk.GLTexture.release].
*
* Return value: (transfer full): A newly-created `GdkTexture`
*
* Since: 4.10
*/
GdkTexture *
gdk_gl_texture_new_with_color_space (GdkGLContext *context,
guint id,
int width,
int height,
GdkGLTextureFlags flags,
GdkColorSpace *color_space,
GDestroyNotify destroy,
gpointer data)
{
GdkGLTexture *self;
@@ -449,10 +507,12 @@ gdk_gl_texture_new (GdkGLContext *context,
self = g_object_new (GDK_TYPE_GL_TEXTURE,
"width", width,
"height", height,
"color-space", color_space,
NULL);
self->context = g_object_ref (context);
self->id = id;
self->flags = flags;
self->destroy = destroy;
self->data = data;
@@ -460,4 +520,3 @@ gdk_gl_texture_new (GdkGLContext *context,
return GDK_TEXTURE (self);
}

View File

@@ -47,6 +47,29 @@ GdkTexture * gdk_gl_texture_new (GdkGLContext
GDestroyNotify destroy,
gpointer data);
/**
* GdkGLTextureFlags:
* @GDK_GL_TEXTURE_FLAGS_PREMULTIPLIED: The alpha in the data is premultiplied
* @GDK_GL_TEXTURE_FLAGS_FLIPPED: The data has the origin at the bottom (this is usually
* th case for textures that are produced by GL rendering)
*
* Flags that describe the content of a GL texture.
*/
typedef enum {
GDK_GL_TEXTURE_PREMULTIPLIED = 1 << 0,
GDK_GL_TEXTURE_FLIPPED = 1 << 1,
} GdkGLTextureFlags;
GDK_AVAILABLE_IN_4_10
GdkTexture * gdk_gl_texture_new_with_color_space (GdkGLContext *context,
guint id,
int width,
int height,
GdkGLTextureFlags flags,
GdkColorSpace *color_space,
GDestroyNotify destroy,
gpointer data);
GDK_AVAILABLE_IN_ALL
void gdk_gl_texture_release (GdkGLTexture *self);

View File

@@ -9,6 +9,7 @@ G_BEGIN_DECLS
GdkGLContext * gdk_gl_texture_get_context (GdkGLTexture *self);
guint gdk_gl_texture_get_id (GdkGLTexture *self);
GdkGLTextureFlags gdk_gl_texture_get_flags (GdkGLTexture *self);
G_END_DECLS

342
gdk/gdklcmscolorspace.c Normal file
View File

@@ -0,0 +1,342 @@
/* gdklcmscolorspace.c
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdklcmscolorspaceprivate.h"
#include "gdkcicpcolorspaceprivate.h"
#include <glib/gi18n-lib.h>
struct _GdkLcmsColorSpace
{
GdkColorSpace parent_instance;
cmsHPROFILE lcms_profile;
};
struct _GdkLcmsColorSpaceClass
{
GdkColorSpaceClass parent_class;
};
G_DEFINE_TYPE (GdkLcmsColorSpace, gdk_lcms_color_space, GDK_TYPE_COLOR_SPACE)
static gboolean
gdk_lcms_color_space_supports_format (GdkColorSpace *space,
GdkMemoryFormat format)
{
GdkLcmsColorSpace *self = GDK_LCMS_COLOR_SPACE (space);
return cmsGetColorSpace (self->lcms_profile) == cmsSigRgbData;
}
static GBytes *
gdk_lcms_color_space_save_to_icc_profile (GdkColorSpace *space,
GError **error)
{
GdkLcmsColorSpace *self = GDK_LCMS_COLOR_SPACE (space);
cmsUInt32Number size;
guchar *data;
size = 0;
if (!cmsSaveProfileToMem (self->lcms_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 (self->lcms_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);
}
static int
gdk_lcms_color_space_get_n_components (GdkColorSpace *space)
{
return 3;
}
static gboolean
gdk_lcms_color_space_equal (GdkColorSpace *profile1,
GdkColorSpace *profile2)
{
GBytes *icc1, *icc2;
gboolean res;
icc1 = gdk_color_space_save_to_icc_profile (profile1, NULL);
icc2 = gdk_color_space_save_to_icc_profile (profile2, NULL);
res = g_bytes_equal (icc1, icc2);
g_bytes_unref (icc1);
g_bytes_unref (icc2);
return res;
}
static void
gdk_lcms_color_space_dispose (GObject *object)
{
GdkLcmsColorSpace *self = GDK_LCMS_COLOR_SPACE (object);
g_clear_pointer (&self->lcms_profile, cmsCloseProfile);
G_OBJECT_CLASS (gdk_lcms_color_space_parent_class)->dispose (object);
}
static void
gdk_lcms_color_space_class_init (GdkLcmsColorSpaceClass *klass)
{
GdkColorSpaceClass *color_space_class = GDK_COLOR_SPACE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
color_space_class->supports_format = gdk_lcms_color_space_supports_format;
color_space_class->save_to_icc_profile = gdk_lcms_color_space_save_to_icc_profile;
color_space_class->get_n_components = gdk_lcms_color_space_get_n_components;
color_space_class->equal = gdk_lcms_color_space_equal;
gobject_class->dispose = gdk_lcms_color_space_dispose;
}
static void
gdk_lcms_color_space_init (GdkLcmsColorSpace *self)
{
}
GdkColorSpace *
gdk_lcms_color_space_new_from_lcms_profile (cmsHPROFILE lcms_profile)
{
GdkLcmsColorSpace *result;
result = g_object_new (GDK_TYPE_LCMS_COLOR_SPACE, NULL);
result->lcms_profile = lcms_profile;
return GDK_COLOR_SPACE (result);
}
/**
* gdk_color_space_new_from_icc_profile:
* @icc_profile: The ICC profiles given as a `GBytes`
* @error: Return location for an error
*
* Creates a new color profile for the given ICC profile data.
*
* if the profile is not valid, %NULL is returned and an error
* is raised.
*
* Returns: a new `GdkLcmsColorSpace` or %NULL on error
*
* Since: 4.10
*/
GdkColorSpace *
gdk_color_space_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_lcms_color_space_new_from_lcms_profile (lcms_profile);
}
cmsHPROFILE
gdk_lcms_color_space_get_lcms_profile (GdkColorSpace *self)
{
g_return_val_if_fail (GDK_IS_LCMS_COLOR_SPACE (self), NULL);
return GDK_LCMS_COLOR_SPACE (self)->lcms_profile;
}
/**
* gdk_color_space_get_srgb:
*
* Returns the object representing the sRGB color space.
*
* If you don't know anything about color spaces but need one for
* use with some function, this one is most likely the right one.
*
* Returns: (transfer none): the object for the sRGB color space.
*
* Since: 4.8
*/
GdkColorSpace *
gdk_color_space_get_srgb (void)
{
static GdkColorSpace *srgb_color_space;
if (g_once_init_enter (&srgb_color_space))
{
GdkColorSpace *color_space;
color_space = gdk_lcms_color_space_new_from_lcms_profile (cmsCreate_sRGBProfile ());
g_assert (color_space);
g_once_init_leave (&srgb_color_space, color_space);
}
return srgb_color_space;
}
/*<private>
* gdk_color_space_get_srgb_linear:
*
* Returns the object corresponding to the linear sRGB color space.
*
* It can display the same colors as the sRGB color space, but it
* does not have a gamma curve.
*
* Returns: (transfer none): the object for the linear sRGB color space.
*
* Since: 4.8
*/
GdkColorSpace *
gdk_color_space_get_srgb_linear (void)
{
static GdkColorSpace *srgb_linear_color_space;
if (g_once_init_enter (&srgb_linear_color_space))
{
cmsToneCurve *curve;
cmsHPROFILE lcms_profile;
GdkColorSpace *color_space;
curve = cmsBuildGamma (NULL, 1.0);
lcms_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);
color_space = gdk_lcms_color_space_new_from_lcms_profile (lcms_profile);
g_assert (color_space);
g_once_init_leave (&srgb_linear_color_space, color_space);
}
return srgb_linear_color_space;
}
typedef struct _GdkColorTransformCache GdkColorTransformCache;
struct _GdkColorTransformCache
{
GdkColorSpace *source;
guint source_type;
GdkColorSpace *dest;
guint dest_type;
};
static void
gdk_color_transform_cache_free (gpointer data)
{
g_free (data);
}
static guint
gdk_color_transform_cache_hash (gconstpointer data)
{
const GdkColorTransformCache *cache = data;
return g_direct_hash (cache->source) ^
(g_direct_hash (cache->dest) >> 2) ^
((cache->source_type << 16) | (cache->source_type >> 16)) ^
cache->dest_type;
}
static gboolean
gdk_color_transform_cache_equal (gconstpointer data1,
gconstpointer data2)
{
const GdkColorTransformCache *cache1 = data1;
const GdkColorTransformCache *cache2 = data2;
return cache1->source == cache2->source &&
cache1->source_type == cache2->source_type &&
cache1->dest == cache2->dest &&
cache1->dest_type == cache2->dest_type;
}
cmsHTRANSFORM *
gdk_color_space_lookup_transform (GdkColorSpace *source,
guint source_type,
GdkColorSpace *dest,
guint dest_type)
{
GdkColorTransformCache *entry;
static GHashTable *cache = NULL;
cmsHTRANSFORM *transform;
if (GDK_IS_CICP_COLOR_SPACE (dest))
dest = gdk_cicp_color_space_get_lcms_color_space (dest);
if (GDK_IS_CICP_COLOR_SPACE (source))
source = gdk_cicp_color_space_get_lcms_color_space (source);
if (cache == NULL)
cache = g_hash_table_new_full (gdk_color_transform_cache_hash,
gdk_color_transform_cache_equal,
gdk_color_transform_cache_free,
cmsDeleteTransform);
transform = g_hash_table_lookup (cache,
&(GdkColorTransformCache) {
source, source_type,
dest, dest_type
});
if (G_UNLIKELY (transform == NULL && source && dest))
{
transform = cmsCreateTransform (gdk_lcms_color_space_get_lcms_profile (source),
source_type,
gdk_lcms_color_space_get_lcms_profile (dest),
dest_type,
INTENT_PERCEPTUAL,
cmsFLAGS_COPY_ALPHA);
entry = g_new (GdkColorTransformCache, 1);
*entry = (GdkColorTransformCache) {
source, source_type,
dest, dest_type
};
g_hash_table_insert (cache, entry, transform);
}
return transform;
}

View File

@@ -0,0 +1,48 @@
/* gdklcmscolorspace.h
*
* Copyright 2021 (c) Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_LCMS_COLOR_SPACE_PRIVATE_H__
#define __GDK_LCMS_COLOR_SPACE_PRIVATE_H__
#include "gdkcolorspaceprivate.h"
#include <lcms2.h>
G_BEGIN_DECLS
#define GDK_TYPE_LCMS_COLOR_SPACE (gdk_lcms_color_space_get_type ())
#define GDK_LCMS_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_LCMS_COLOR_SPACE, GdkLcmsColorSpace))
#define GDK_IS_LCMS_COLOR_SPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_LCMS_COLOR_SPACE))
#define GDK_LCMS_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_LCMS_COLOR_SPACE, GdkLcmsColorSpaceClass))
#define GDK_IS_LCMS_COLOR_SPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_LCMS_COLOR_SPACE))
#define GDK_LCMS_COLOR_SPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_LCMS_COLOR_SPACE, GdkLcmsColorSpaceClass))
typedef struct _GdkLcmsColorSpace GdkLcmsColorSpace;
typedef struct _GdkLcmsColorSpaceClass GdkLcmsColorSpaceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkLcmsColorSpace, g_object_unref)
GType gdk_lcms_color_space_get_type (void) G_GNUC_CONST;
GdkColorSpace * gdk_lcms_color_space_new_from_lcms_profile (cmsHPROFILE lcms_profile);
cmsHPROFILE gdk_lcms_color_space_get_lcms_profile (GdkColorSpace *color_space);
G_END_DECLS
#endif /* __GDK_LCMS_COLOR_SPACE_PRIVATE_H__ */

View File

@@ -21,6 +21,9 @@
#include "gdkmemoryformatprivate.h"
#include "gdklcmscolorspaceprivate.h"
#include "gdkcicpcolorspaceprivate.h"
#include "gdkprofilerprivate.h"
#include "gsk/gl/fp16private.h"
#include <epoxy/gl.h>
@@ -72,6 +75,223 @@ TYPED_FUNCS (b8g8r8, guchar, 2, 1, 0, -1, 3, 255)
TYPED_FUNCS (r16g16b16, guint16, 0, 1, 2, -1, 6, 65535)
TYPED_FUNCS (r16g16b16a16, guint16, 0, 1, 2, 3, 8, 65535)
#define PREMULTIPLY_FUNCS(type, A, scale) \
static void \
type ## _premultiply_ ## A (guchar *dest_data, \
const guchar *src_data, \
gsize n) \
{ \
type *dest = (type *) dest_data; \
const type *src = (const type *) src_data; \
for (gsize i = 0; i < n; i++) \
{ \
unsigned a = src[A]; \
if (A != 0) dest[0] = src[0] * a / scale; \
if (A != 1) dest[1] = src[1] * a / scale; \
if (A != 2) dest[2] = src[2] * a / scale; \
if (A != 3) dest[3] = src[3] * a / scale; \
dest[A] = a; \
src += 4; \
dest += 4; \
} \
} \
\
static void \
type ## _unpremultiply_ ## A (guchar *dest_data, \
const guchar *src_data, \
gsize n) \
{ \
type *dest = (type *) dest_data; \
const type *src = (const type *) src_data; \
for (gsize i = 0; i < n; i++) \
{ \
unsigned a = src[A]; \
if (a == 0) \
{ \
dest[0] = dest[1] = dest[2] = dest[3] = 0; \
} \
else \
{ \
if (A != 0) dest[0] = (src[0] * scale + a / 2) / a; \
if (A != 1) dest[1] = (src[1] * scale + a / 2) / a; \
if (A != 2) dest[2] = (src[2] * scale + a / 2) / a; \
if (A != 3) dest[3] = (src[3] * scale + a / 2) / a; \
dest[A] = a; \
} \
src += 4; \
dest += 4; \
} \
}
PREMULTIPLY_FUNCS (guint8, 0, G_MAXUINT8)
PREMULTIPLY_FUNCS (guint8, 3, G_MAXUINT8)
PREMULTIPLY_FUNCS (guint16, 3, G_MAXUINT16)
static void
half_float_premultiply (guchar *dest_data,
const guchar *src_data,
gsize n)
{
guint16 *dest = (guint16 *) dest_data;
const float *src = (const float *) src_data;
for (gsize i = 0; i < n; i++)
{
float tmp[4];
tmp[0] = src[0] * src[3];
tmp[1] = src[1] * src[3];
tmp[2] = src[2] * src[3];
tmp[3] = src[3];
float_to_half4 (tmp, dest);
dest += 4;
src += 4;
}
}
static void
half_float_unpremultiply (guchar *dest_data,
const guchar *src_data,
gsize n)
{
float *dest = (float *) dest_data;
const guint16 *src = (const guint16 *) src_data;
for (gsize i = 0; i < n; i++)
{
half_to_float4 (src, dest);
if (dest[3] <= 1/255.0)
{
memset (dest, 0, sizeof (guint) * 4);
}
else
{
dest[0] = dest[0] / dest[3];
dest[1] = dest[1] / dest[3];
dest[2] = dest[2] / dest[3];
}
dest += 4;
src += 4;
}
}
static void
float_premultiply (guchar *dest_data,
const guchar *src_data,
gsize n)
{
float *dest = (float *) dest_data;
const float *src = (const float *) src_data;
for (gsize i = 0; i < n; i++)
{
float a = src[3];
dest[0] = src[0] * a;
dest[1] = src[1] * a;
dest[2] = src[2] * a;
dest[3] = a;
dest += 4;
src += 4;
}
}
static void
float_unpremultiply (guchar *dest_data,
const guchar *src_data,
gsize n)
{
float *dest = (float *) dest_data;
const float *src = (const float *) src_data;
for (gsize i = 0; i < n; i++)
{
float a = src[3];
if (a <= 1/255.0)
{
memset (dest, 0, sizeof (float) * 4);
}
else
{
dest[0] = src[0] / a;
dest[1] = src[1] / a;
dest[2] = src[2] / a;
dest[3] = a;
}
dest += 4;
src += 4;
}
}
#define COMPRESS_FUNCS(type, scale) \
static void \
type ## _expand (guchar *dest_data, \
const guchar *src_data, \
gsize n) \
{ \
type *dest = (type *) dest_data; \
const type *src = (const type *) src_data; \
for (gsize i = 0; i < n; i++) \
{ \
dest[0] = src[0]; \
dest[1] = src[1]; \
dest[2] = src[2]; \
dest[3] = scale; \
dest += 4; \
src += 3; \
} \
} \
\
static void \
type ## _compress (guchar *dest_data, \
const guchar *src_data, \
gsize n) \
{ \
type *dest = (type *) dest_data; \
const type *src = (const type *) src_data; \
for (gsize i = 0; i < n; i++) \
{ \
dest[0] = src[0] * src[3] / scale; \
dest[1] = src[1] * src[3] / scale; \
dest[2] = src[2] * src[3] / scale; \
dest += 3; \
src += 4; \
} \
}
COMPRESS_FUNCS (guint8, G_MAXUINT8)
COMPRESS_FUNCS (guint16, G_MAXUINT16)
COMPRESS_FUNCS (float, 1.0f)
static void
half_float_expand (guchar *dest_data,
const guchar *src_data,
gsize n)
{
float *dest = (float *) dest_data;
const guint16 *src = (const guint16 *) src_data;
for (gsize i = 0; i < n; i++)
{
half_to_float (src, dest, 3);
dest[3] = 1.0;
dest += 4;
src += 3;
}
}
static void
half_float_compress (guchar *dest_data,
const guchar *src_data,
gsize n)
{
guint16 *dest = (guint16 *) dest_data;
const float *src = (const float *) src_data;
for (gsize i = 0; i < n; i++)
{
float tmp[3];
tmp[0] = src[0] * src[3];
tmp[1] = src[1] * src[3];
tmp[2] = src[2] * src[3];
float_to_half (tmp, dest, 3);
dest += 3;
src += 4;
}
}
static void
r16g16b16_float_to_float (float *dest,
const guchar *src_data,
@@ -166,56 +386,9 @@ r32g32b32a32_float_from_float (guchar *dest,
memcpy (dest, src, sizeof (float) * n * 4);
}
#define PREMULTIPLY_FUNC(name, R1, G1, B1, A1, R2, G2, B2, A2) \
static void \
name (guchar *dest, \
const guchar *src, \
gsize n) \
{ \
for (; n > 0; n--) \
{ \
guchar a = src[A1]; \
guint16 r = (guint16)src[R1] * a + 127; \
guint16 g = (guint16)src[G1] * a + 127; \
guint16 b = (guint16)src[B1] * a + 127; \
dest[R2] = (r + (r >> 8) + 1) >> 8; \
dest[G2] = (g + (g >> 8) + 1) >> 8; \
dest[B2] = (b + (b >> 8) + 1) >> 8; \
dest[A2] = a; \
dest += 4; \
src += 4; \
} \
}
PREMULTIPLY_FUNC(r8g8b8a8_to_r8g8b8a8_premultiplied, 0, 1, 2, 3, 0, 1, 2, 3)
PREMULTIPLY_FUNC(r8g8b8a8_to_b8g8r8a8_premultiplied, 0, 1, 2, 3, 2, 1, 0, 3)
PREMULTIPLY_FUNC(r8g8b8a8_to_a8r8g8b8_premultiplied, 0, 1, 2, 3, 1, 2, 3, 0)
PREMULTIPLY_FUNC(r8g8b8a8_to_a8b8g8r8_premultiplied, 0, 1, 2, 3, 3, 2, 1, 0)
#define ADD_ALPHA_FUNC(name, R1, G1, B1, R2, G2, B2, A2) \
static void \
name (guchar *dest, \
const guchar *src, \
gsize n) \
{ \
for (; n > 0; n--) \
{ \
dest[R2] = src[R1]; \
dest[G2] = src[G1]; \
dest[B2] = src[B1]; \
dest[A2] = 255; \
dest += 4; \
src += 3; \
} \
}
ADD_ALPHA_FUNC(r8g8b8_to_r8g8b8a8, 0, 1, 2, 0, 1, 2, 3)
ADD_ALPHA_FUNC(r8g8b8_to_b8g8r8a8, 0, 1, 2, 2, 1, 0, 3)
ADD_ALPHA_FUNC(r8g8b8_to_a8r8g8b8, 0, 1, 2, 1, 2, 3, 0)
ADD_ALPHA_FUNC(r8g8b8_to_a8b8g8r8, 0, 1, 2, 3, 2, 1, 0)
struct _GdkMemoryFormatDescription
{
const char *name;
GdkMemoryAlpha alpha;
gsize bytes_per_pixel;
gsize alignment;
@@ -229,6 +402,12 @@ struct _GdkMemoryFormatDescription
/* no premultiplication going on here */
void (* to_float) (float *, const guchar*, gsize);
void (* from_float) (guchar *, const float *, gsize);
struct {
guint type;
gsize bpp;
} lcms;
void (* to_lcms) (guchar *, const guchar *, gsize);
void (* from_lcms) (guchar *, const guchar *, gsize);
};
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
@@ -241,6 +420,7 @@ struct _GdkMemoryFormatDescription
static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
[GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = {
"B8G8R8A8_PREMULTIPLIED",
GDK_MEMORY_ALPHA_PREMULTIPLIED,
4,
G_ALIGNOF (guchar),
@@ -249,8 +429,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE },
b8g8r8a8_premultiplied_to_float,
b8g8r8a8_premultiplied_from_float,
{ TYPE_BGRA_8, 4 },
guint8_unpremultiply_3,
guint8_premultiply_3,
},
[GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = {
"A8R8G8B8_PREMULTIPLIED",
GDK_MEMORY_ALPHA_PREMULTIPLIED,
4,
G_ALIGNOF (guchar),
@@ -259,8 +443,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
a8r8g8b8_premultiplied_to_float,
a8r8g8b8_premultiplied_from_float,
{ TYPE_ARGB_8, 4 },
guint8_unpremultiply_0,
guint8_premultiply_0,
},
[GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = {
"R8G8B8A8_PREMULTIPLIED",
GDK_MEMORY_ALPHA_PREMULTIPLIED,
4,
G_ALIGNOF (guchar),
@@ -269,8 +457,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
r8g8b8a8_premultiplied_to_float,
r8g8b8a8_premultiplied_from_float,
{ TYPE_RGBA_8, 4 },
guint8_unpremultiply_3,
guint8_premultiply_3,
},
[GDK_MEMORY_B8G8R8A8] = {
"B8G8R8A8",
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
@@ -279,8 +471,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA8, GL_BGRA, GL_UNSIGNED_BYTE },
b8g8r8a8_to_float,
b8g8r8a8_from_float,
{ TYPE_BGRA_8, 4 },
NULL,
NULL,
},
[GDK_MEMORY_A8R8G8B8] = {
"A8R8G8B8",
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
@@ -289,8 +485,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA8, GL_RGBA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
a8r8g8b8_to_float,
a8r8g8b8_from_float,
{ TYPE_ARGB_8, 4 },
NULL,
NULL,
},
[GDK_MEMORY_R8G8B8A8] = {
"R8G8B8A8",
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
@@ -299,8 +499,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE },
r8g8b8a8_to_float,
r8g8b8a8_from_float,
{ TYPE_RGBA_8, 4 },
NULL,
NULL,
},
[GDK_MEMORY_A8B8G8R8] = {
"A8B8G8R8",
GDK_MEMORY_ALPHA_STRAIGHT,
4,
G_ALIGNOF (guchar),
@@ -309,8 +513,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA8, GL_BGRA, GDK_GL_UNSIGNED_BYTE_FLIPPED },
a8b8g8r8_to_float,
a8b8g8r8_from_float,
{ TYPE_ABGR_8, 4 },
NULL,
NULL,
},
[GDK_MEMORY_R8G8B8] = {
"R8G8B8",
GDK_MEMORY_ALPHA_OPAQUE,
3,
G_ALIGNOF (guchar),
@@ -319,8 +527,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE },
r8g8b8_to_float,
r8g8b8_from_float,
{ TYPE_RGBA_8, 4 },
guint8_expand,
guint8_compress,
},
[GDK_MEMORY_B8G8R8] = {
"B8G8R8",
GDK_MEMORY_ALPHA_OPAQUE,
3,
G_ALIGNOF (guchar),
@@ -329,8 +541,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGB8, GL_BGR, GL_UNSIGNED_BYTE },
b8g8r8_to_float,
b8g8r8_from_float,
{ TYPE_BGRA_8, 4 },
guint8_expand,
guint8_compress,
},
[GDK_MEMORY_R16G16B16] = {
"R16G16B16",
GDK_MEMORY_ALPHA_OPAQUE,
6,
G_ALIGNOF (guint16),
@@ -339,8 +555,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGB16, GL_RGB, GL_UNSIGNED_SHORT },
r16g16b16_to_float,
r16g16b16_from_float,
{ TYPE_RGBA_16, 8 },
guint16_expand,
guint16_compress,
},
[GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = {
"R16G16B16A16_PREMULTIPLIED",
GDK_MEMORY_ALPHA_PREMULTIPLIED,
8,
G_ALIGNOF (guint16),
@@ -349,8 +569,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT },
r16g16b16a16_to_float,
r16g16b16a16_from_float,
{ TYPE_RGBA_16, 8 },
guint16_unpremultiply_3,
guint16_premultiply_3,
},
[GDK_MEMORY_R16G16B16A16] = {
"R16G16B16A16",
GDK_MEMORY_ALPHA_STRAIGHT,
8,
G_ALIGNOF (guint16),
@@ -359,8 +583,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT },
r16g16b16a16_to_float,
r16g16b16a16_from_float,
{ TYPE_RGBA_16, 8 },
NULL,
NULL,
},
[GDK_MEMORY_R16G16B16_FLOAT] = {
"R16G16B16_FLOAT",
GDK_MEMORY_ALPHA_OPAQUE,
6,
G_ALIGNOF (guint16),
@@ -369,8 +597,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGB16F, GL_RGB, GL_HALF_FLOAT },
r16g16b16_float_to_float,
r16g16b16_float_from_float,
{ TYPE_RGBA_FLT, 16 },
half_float_expand,
half_float_compress,
},
[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = {
"R16G16B16A16_FLOAT_PREMULTIPLIED",
GDK_MEMORY_ALPHA_PREMULTIPLIED,
8,
G_ALIGNOF (guint16),
@@ -379,8 +611,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
r16g16b16a16_float_to_float,
r16g16b16a16_float_from_float,
{ TYPE_RGBA_FLT, 16 },
half_float_unpremultiply,
half_float_premultiply,
},
[GDK_MEMORY_R16G16B16A16_FLOAT] = {
"R16G16B16A16_FLOAT",
GDK_MEMORY_ALPHA_STRAIGHT,
8,
G_ALIGNOF (guint16),
@@ -389,8 +625,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT },
r16g16b16a16_float_to_float,
r16g16b16a16_float_from_float,
{ TYPE_RGBA_FLT, 16 },
NULL,
NULL
},
[GDK_MEMORY_R32G32B32_FLOAT] = {
"R32G32B32_FLOAT",
GDK_MEMORY_ALPHA_OPAQUE,
12,
G_ALIGNOF (float),
@@ -399,8 +639,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGB32F, GL_RGB, GL_FLOAT },
r32g32b32_float_to_float,
r32g32b32_float_from_float,
{ TYPE_RGBA_FLT, 16 },
float_expand,
float_compress,
},
[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = {
"R32G32B32A32_FLOAT_PREMULTIPLIED",
GDK_MEMORY_ALPHA_PREMULTIPLIED,
16,
G_ALIGNOF (float),
@@ -409,8 +653,12 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA32F, GL_RGBA, GL_FLOAT },
r32g32b32a32_float_to_float,
r32g32b32a32_float_from_float,
{ TYPE_RGBA_FLT, 16 },
float_unpremultiply,
float_premultiply,
},
[GDK_MEMORY_R32G32B32A32_FLOAT] = {
"R32G32B32A32_FLOAT",
GDK_MEMORY_ALPHA_STRAIGHT,
16,
G_ALIGNOF (float),
@@ -419,6 +667,9 @@ static const GdkMemoryFormatDescription memory_formats[GDK_MEMORY_N_FORMATS] = {
{ GL_RGBA32F, GL_RGBA, GL_FLOAT },
r32g32b32a32_float_to_float,
r32g32b32a32_float_from_float,
{ TYPE_RGBA_FLT, 16 },
NULL,
NULL,
}
};
@@ -509,86 +760,164 @@ unpremultiply (float *rgba,
}
}
void
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height)
static void
gdk_memory_convert_same_format (guchar *dest_data,
gsize dest_stride,
const guchar *src_data,
gsize src_stride,
gsize width,
gsize height,
GdkMemoryFormat format)
{
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
float *tmp;
gsize y;
void (*func) (guchar *, const guchar *, gsize) = NULL;
const GdkMemoryFormatDescription *desc = &memory_formats[format];
gsize y, stride;
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
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;
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
func = r8g8b8a8_to_b8g8r8a8_premultiplied;
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
func = r8g8b8a8_to_r8g8b8a8_premultiplied;
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
func = r8g8b8a8_to_a8r8g8b8_premultiplied;
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
func = r8g8b8a8_to_a8b8g8r8_premultiplied;
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
func = r8g8b8_to_r8g8b8a8;
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
func = r8g8b8_to_b8g8r8a8;
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
func = r8g8b8_to_b8g8r8a8;
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8_PREMULTIPLIED)
func = r8g8b8_to_r8g8b8a8;
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
func = r8g8b8_to_a8r8g8b8;
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8_PREMULTIPLIED)
func = r8g8b8_to_a8b8g8r8;
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_R8G8B8A8)
func = r8g8b8_to_r8g8b8a8;
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_R8G8B8A8)
func = r8g8b8_to_b8g8r8a8;
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_B8G8R8A8)
func = r8g8b8_to_b8g8r8a8;
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_B8G8R8A8)
func = r8g8b8_to_r8g8b8a8;
else if (src_format == GDK_MEMORY_R8G8B8 && dest_format == GDK_MEMORY_A8R8G8B8)
func = r8g8b8_to_a8r8g8b8;
else if (src_format == GDK_MEMORY_B8G8R8 && dest_format == GDK_MEMORY_A8R8G8B8)
func = r8g8b8_to_a8b8g8r8;
if (func != NULL)
stride = desc->bytes_per_pixel * width;
if (stride == src_stride && stride == dest_stride)
{
memcpy (dest_data, src_data, stride * height);
}
else
{
for (y = 0; y < height; y++)
{
func (dest_data, src_data, width);
memcpy (dest_data + y * dest_stride,
src_data + y * src_stride,
stride);
}
}
}
static void
gdk_memory_convert_no_transform (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height)
{
if (dest_format == src_format)
{
gdk_memory_convert_same_format (dest_data, dest_stride,
src_data, src_stride,
width, height,
dest_format);
}
else
{
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
float *tmp;
gsize y;
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);
dest_desc->from_float (dest_data, tmp, width);
src_data += src_stride;
dest_data += dest_stride;
}
return;
}
tmp = g_new (float, width * 4);
g_free (tmp);
}
}
static void
gdk_memory_convert_transform (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorSpace *dest_color_space,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorSpace *src_color_space,
gsize width,
gsize height)
{
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
cmsHTRANSFORM transform;
guchar *src_tmp, *dest_tmp;
gsize y;
transform = gdk_color_space_lookup_transform (src_color_space,
src_desc->lcms.type,
dest_color_space,
dest_desc->lcms.type);
if (src_desc->to_lcms)
src_tmp = g_malloc_n (src_desc->lcms.bpp, width);
else
src_tmp = NULL;
if (dest_desc->from_lcms)
dest_tmp = g_malloc_n (dest_desc->lcms.bpp, width);
else
dest_tmp = NULL;
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);
dest_desc->from_float (dest_data, tmp, width);
if (src_desc->to_lcms)
src_desc->to_lcms (src_tmp, src_data, width);
cmsDoTransform (transform,
src_tmp ? src_tmp : src_data,
dest_tmp ? dest_tmp : dest_data,
width);
if (dest_desc->from_lcms)
dest_desc->from_lcms (dest_data, dest_tmp, width);
src_data += src_stride;
dest_data += dest_stride;
}
g_free (tmp);
g_free (src_tmp);
g_free (dest_tmp);
}
void
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorSpace *dest_color_space,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorSpace *src_color_space,
gsize width,
gsize height)
{
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
gboolean need_transform;
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
need_transform = !gdk_color_space_equal (src_color_space, dest_color_space);
if (!need_transform)
{
gdk_memory_convert_no_transform (dest_data, dest_stride, dest_format,
src_data, src_stride, src_format,
width, height);
}
else
{
gdk_memory_convert_transform (dest_data, dest_stride, dest_format, dest_color_space,
src_data, src_stride, src_format, src_color_space,
width, height);
}
gdk_profiler_end_markf (start_time, "memory convert", "%zu pixels %s => %s%s",
width * height,
memory_formats[src_format].name,
memory_formats[dest_format].name,
need_transform ? " transformed" : "");
}

View File

@@ -21,6 +21,7 @@
#define __GDK_MEMORY_CONVERT_PRIVATE_H__
#include "gdkenums.h"
#include "gdkcolorspace.h"
G_BEGIN_DECLS
@@ -43,9 +44,11 @@ gboolean gdk_memory_format_gl_format (GdkMemoryFormat
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorSpace *dest_color_space,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorSpace *src_color_space,
gsize width,
gsize height);

View File

@@ -21,7 +21,9 @@
#include "gdkmemorytextureprivate.h"
#include "gdkcolorspaceprivate.h"
#include "gdkmemoryformatprivate.h"
#include "gdkcolorspaceprivate.h"
#include "gsk/gl/fp16private.h"
/**
@@ -58,6 +60,7 @@ gdk_memory_texture_dispose (GObject *object)
static void
gdk_memory_texture_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
@@ -65,9 +68,11 @@ gdk_memory_texture_download (GdkTexture *texture,
gdk_memory_convert (data, stride,
format,
color_space,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
texture->format,
gdk_texture_get_color_space (texture),
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
@@ -136,6 +141,9 @@ gdk_memory_sanitize (GBytes *bytes,
* The `GBytes` must contain @stride × @height pixels
* in the given format.
*
* This function calls [ctor@Gdk.MemoryTexture.new_with_color_space]
* with the sRGB color space.
*
* Returns: (type GdkMemoryTexture): A newly-created `GdkTexture`
*/
GdkTexture *
@@ -145,18 +153,58 @@ gdk_memory_texture_new (int width,
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 (bytes != NULL, NULL);
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
return gdk_memory_texture_new_with_color_space (width, height,
format,
gdk_color_space_get_srgb (),
bytes, stride);
}
/**
* gdk_memory_texture_new_with_color_space:
* @width: the width of the texture
* @height: the height of the texture
* @format: the format of the data
* @color_space: 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 space.
*
* The `GBytes` must contain @stride x @height pixels
* in the given format.
*
* Returns: A newly-created `GdkTexture`
*
* Since: 4.10
*/
GdkTexture *
gdk_memory_texture_new_with_color_space (int width,
int height,
GdkMemoryFormat format,
GdkColorSpace *color_space,
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 (GDK_IS_COLOR_SPACE (color_space), NULL);
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
g_return_val_if_fail (gdk_color_space_supports_format (color_space, format), NULL);
bytes = gdk_memory_sanitize (bytes, width, height, format, stride, &stride);
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
"width", width,
"height", height,
"color-space", color_space,
NULL);
GDK_TEXTURE (self)->format = format;
@@ -201,7 +249,8 @@ gdk_memory_texture_new_subtexture (GdkMemoryTexture *source,
GdkMemoryTexture *
gdk_memory_texture_from_texture (GdkTexture *texture,
GdkMemoryFormat format)
GdkMemoryFormat format,
GdkColorSpace *color_space)
{
GdkTexture *result;
GBytes *bytes;
@@ -214,20 +263,22 @@ gdk_memory_texture_from_texture (GdkTexture *texture,
{
GdkMemoryTexture *memtex = GDK_MEMORY_TEXTURE (texture);
if (gdk_texture_get_format (texture) == format)
if (gdk_texture_get_format (texture) == format &&
gdk_texture_get_color_space (texture) == color_space)
return g_object_ref (memtex);
}
stride = texture->width * gdk_memory_format_bytes_per_pixel (format);
data = g_malloc_n (stride, texture->height);
gdk_texture_do_download (texture, format, data, stride);
gdk_texture_do_download (texture, format, color_space, data, stride);
bytes = g_bytes_new_take (data, stride);
result = gdk_memory_texture_new (texture->width,
texture->height,
format,
bytes,
stride);
result = gdk_memory_texture_new_with_color_space (texture->width,
texture->height,
format,
color_space,
bytes,
stride);
g_bytes_unref (bytes);
return GDK_MEMORY_TEXTURE (result);

View File

@@ -26,6 +26,7 @@
#include <gdk/gdkenums.h>
#include <gdk/gdktexture.h>
#include <gdk/gdkcolorspace.h>
G_BEGIN_DECLS
@@ -68,6 +69,14 @@ GdkTexture * gdk_memory_texture_new (int
GdkMemoryFormat format,
GBytes *bytes,
gsize stride);
GDK_AVAILABLE_IN_4_10
GdkTexture * gdk_memory_texture_new_with_color_space
(int width,
int height,
GdkMemoryFormat format,
GdkColorSpace *color_space,
GBytes *bytes,
gsize stride);
G_END_DECLS

View File

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

View File

@@ -245,7 +245,8 @@ gdk_pixbuf_get_from_texture (GdkTexture *texture)
memtex = gdk_memory_texture_from_texture (texture,
alpha ? GDK_MEMORY_GDK_PIXBUF_ALPHA
: GDK_MEMORY_GDK_PIXBUF_OPAQUE);
: GDK_MEMORY_GDK_PIXBUF_OPAQUE,
gdk_color_space_get_srgb ());
return gdk_pixbuf_new_from_data (gdk_memory_texture_get_data (memtex),
GDK_COLORSPACE_RGB,

View File

@@ -30,6 +30,8 @@
#include "gdksurface.h"
#include "gdkprivate.h"
#include "gdkcolorspace.h"
#include "gdkcairo.h"
#include "gdkcontentprovider.h"
#include "gdkdeviceprivate.h"
#include "gdkdisplayprivate.h"
@@ -88,13 +90,14 @@ enum {
enum {
PROP_0,
PROP_COLOR_SPACE,
PROP_CURSOR,
PROP_DISPLAY,
PROP_FRAME_CLOCK,
PROP_MAPPED,
PROP_WIDTH,
PROP_HEIGHT,
PROP_MAPPED,
PROP_SCALE_FACTOR,
PROP_WIDTH,
LAST_PROP
};
@@ -485,6 +488,8 @@ gdk_surface_init (GdkSurface *surface)
surface->alpha = 255;
surface->color_space = g_object_ref (gdk_color_space_get_srgb ());
surface->device_cursor = g_hash_table_new_full (NULL, NULL,
NULL, g_object_unref);
}
@@ -500,6 +505,25 @@ gdk_surface_class_init (GdkSurfaceClass *klass)
klass->beep = gdk_surface_real_beep;
/**
* GdkSurface:color-space: (attributes org.gtk.Property.get=gdk_surface_get_color_space)
*
* The preferred color space for rendering to the surface
*
* This color space is negotiated between GTK and the compositor.
*
* The color space 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
* space that is going to be used.
*
* Since: 4.10
*/
properties[PROP_COLOR_SPACE] =
g_param_spec_object ("color-space", NULL, NULL,
GDK_TYPE_COLOR_SPACE,
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)
*
@@ -718,6 +742,7 @@ gdk_surface_finalize (GObject *object)
g_clear_object (&surface->cursor);
g_clear_pointer (&surface->device_cursor, g_hash_table_destroy);
g_clear_pointer (&surface->devices_inside, g_list_free);
g_clear_object (&surface->color_space);
g_clear_object (&surface->display);
@@ -772,6 +797,10 @@ gdk_surface_get_property (GObject *object,
switch (prop_id)
{
case PROP_COLOR_SPACE:
g_value_set_object (value, gdk_surface_get_color_space (surface));
break;
case PROP_CURSOR:
g_value_set_object (value, gdk_surface_get_cursor (surface));
break;
@@ -2040,6 +2069,40 @@ gdk_surface_get_height (GdkSurface *surface)
return surface->height;
}
void
gdk_surface_set_color_space (GdkSurface *self,
GdkColorSpace *color_space)
{
/* This way we support unsetting, too */
if (G_UNLIKELY (gdk_display_get_debug_flags (self->display) & GDK_DEBUG_SRGB))
color_space = gdk_color_space_get_srgb ();
if (gdk_color_space_equal (self->color_space, color_space))
return;
g_set_object (&self->color_space, color_space);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_SPACE]);
}
/**
* gdk_surface_get_color_space: (attributes org.gtk.Method.get_property=color-space)
* @self: a `GdkSurface`
*
* Returns the preferred color space for rendering to the given @surface.
*
* Returns: (transfer none): The color space of @surface
*
* Since: 4.10
*/
GdkColorSpace *
gdk_surface_get_color_space (GdkSurface *self)
{
g_return_val_if_fail (GDK_IS_SURFACE (self), gdk_color_space_get_srgb ());
return self->color_space;
}
/*
* gdk_surface_get_origin:
* @surface: a `GdkSurface`
@@ -2360,7 +2423,7 @@ _gdk_windowing_got_event (GdkDisplay *display,
* with it.
*/
cairo_surface_t *
gdk_surface_create_similar_surface (GdkSurface * surface,
gdk_surface_create_similar_surface (GdkSurface * surface,
cairo_content_t content,
int width,
int height)
@@ -2376,6 +2439,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_space (similar_surface, gdk_surface_get_color_space (surface));
return similar_surface;
}

View File

@@ -86,17 +86,19 @@ GDK_AVAILABLE_IN_ALL
GdkCursor *gdk_surface_get_device_cursor (GdkSurface *surface,
GdkDevice *device);
GDK_AVAILABLE_IN_ALL
int gdk_surface_get_width (GdkSurface *surface);
int gdk_surface_get_width (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
int gdk_surface_get_height (GdkSurface *surface);
int gdk_surface_get_height (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
gboolean gdk_surface_translate_coordinates (GdkSurface *from,
GdkSurface *to,
double *x,
double *y);
int gdk_surface_get_scale_factor (GdkSurface *surface);
GDK_AVAILABLE_IN_4_10
GdkColorSpace * gdk_surface_get_color_space (GdkSurface *self);
GDK_AVAILABLE_IN_ALL
gboolean gdk_surface_translate_coordinates (GdkSurface *from,
GdkSurface *to,
double *x,
double *y);
GDK_AVAILABLE_IN_ALL
int gdk_surface_get_scale_factor (GdkSurface *surface);
GDK_AVAILABLE_IN_ALL
gboolean gdk_surface_get_device_position (GdkSurface *surface,

View File

@@ -52,6 +52,7 @@ struct _GdkSurface
int y;
GdkGLContext *gl_paint_context;
GdkColorSpace *color_space;
cairo_region_t *update_area;
guint update_freeze_count;
@@ -171,6 +172,8 @@ void gdk_surface_set_state (GdkSurface *surface,
void gdk_surface_set_is_mapped (GdkSurface *surface,
gboolean is_mapped);
void gdk_surface_set_color_space (GdkSurface *self,
GdkColorSpace *color_space);
GdkMonitor * gdk_surface_get_layout_monitor (GdkSurface *surface,
GdkPopupLayout *layout,

View File

@@ -40,6 +40,9 @@
#include "gdktextureprivate.h"
#include <glib/gi18n-lib.h>
#include "gdkcolorspace.h"
#include "gdkcairo.h"
#include "gdkmemoryformatprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdkpaintable.h"
#include "gdksnapshot.h"
@@ -61,6 +64,7 @@ enum {
PROP_0,
PROP_WIDTH,
PROP_HEIGHT,
PROP_COLOR_SPACE,
N_PROPS
};
@@ -223,6 +227,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
static void
gdk_texture_default_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
@@ -247,6 +252,12 @@ gdk_texture_set_property (GObject *gobject,
self->height = g_value_get_int (value);
break;
case PROP_COLOR_SPACE:
self->color_space = g_value_dup_object (value);
if (self->color_space == NULL)
self->color_space = g_object_ref (gdk_color_space_get_srgb ());
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -271,6 +282,10 @@ gdk_texture_get_property (GObject *gobject,
g_value_set_int (value, self->height);
break;
case PROP_COLOR_SPACE:
g_value_set_object (value, self->color_space);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
@@ -283,6 +298,7 @@ gdk_texture_dispose (GObject *object)
GdkTexture *self = GDK_TEXTURE (object);
gdk_texture_clear_render_data (self);
g_clear_object (&self->color_space);
G_OBJECT_CLASS (gdk_texture_parent_class)->dispose (object);
}
@@ -305,9 +321,7 @@ gdk_texture_class_init (GdkTextureClass *klass)
*/
properties[PROP_WIDTH] =
g_param_spec_int ("width", NULL, NULL,
1,
G_MAXINT,
1,
1, G_MAXINT, 1,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS |
@@ -320,14 +334,27 @@ gdk_texture_class_init (GdkTextureClass *klass)
*/
properties[PROP_HEIGHT] =
g_param_spec_int ("height", NULL, NULL,
1,
G_MAXINT,
1,
1, G_MAXINT, 1,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS |
G_PARAM_EXPLICIT_NOTIFY);
/**
* GdkTexture:color-space: (attributes org.gtk.Property.get=gdk_texture_get_color_space)
*
* The color space associated with texture.
*
* Since: 4.10
*/
properties[PROP_COLOR_SPACE] =
g_param_spec_object ("color-space", NULL, NULL,
GDK_TYPE_COLOR_SPACE,
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);
}
@@ -361,18 +388,43 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
* cairo_image_surface_get_stride (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_space (cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
GDK_MEMORY_DEFAULT,
gdk_cairo_surface_get_color_space (surface),
bytes,
cairo_image_surface_get_stride (surface));
g_bytes_unref (bytes);
return texture;
}
static GdkColorSpace *
gdk_color_space_from_pixbuf (GdkPixbuf *pixbuf)
{
const char *icc_profile_base64;
GdkColorSpace *color_space = 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_space = gdk_color_space_new_from_icc_profile (bytes, NULL);
g_bytes_unref (bytes);
}
if (!color_space)
color_space = g_object_ref (gdk_color_space_get_srgb ());
return color_space;
}
/**
* gdk_texture_new_for_pixbuf:
* @pixbuf: a `GdkPixbuf`
@@ -390,24 +442,31 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
{
GdkTexture *texture;
GBytes *bytes;
GdkColorSpace *color_space;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
color_space = gdk_color_space_from_pixbuf (pixbuf);
bytes = g_bytes_new_with_free_func (gdk_pixbuf_get_pixels (pixbuf),
gdk_pixbuf_get_height (pixbuf)
* 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_space (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_space,
bytes,
gdk_pixbuf_get_rowstride (pixbuf));
g_bytes_unref (bytes);
g_object_unref (color_space);
return texture;
}
@@ -665,32 +724,73 @@ gdk_texture_get_height (GdkTexture *texture)
return texture->height;
}
/**
* gdk_texture_get_color_space: (attributes org.gtk.Method.get_property=color-space)
* @texture: a `GdkTexture`
*
* Returns the color space associsated with @texture.
*
* Returns: (transfer none): the color space of the `GdkTexture`
*
* Since: 4.10
*/
GdkColorSpace *
gdk_texture_get_color_space (GdkTexture *texture)
{
g_return_val_if_fail (GDK_IS_TEXTURE (texture), 0);
return texture->color_space;
}
void
gdk_texture_do_download (GdkTexture *texture,
GdkMemoryFormat format,
GdkColorSpace *color_space,
guchar *data,
gsize stride)
{
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data,stride);
GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, color_space, data, stride);
}
/*<private>
* gdk_texture_download_surface:
* @texture: the texture to download
* @color_space: (nullable): The target color space or %NULL for the default sRGB
*
* Downloads the texture into a newly created Cairo surface.
*
* Returns: A new Cairo surface.
**/
cairo_surface_t *
gdk_texture_download_surface (GdkTexture *texture)
gdk_texture_download_surface (GdkTexture *texture,
GdkColorSpace *color_space)
{
cairo_surface_t *surface;
cairo_status_t surface_status;
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
texture->width, texture->height);
if (color_space != NULL)
gdk_cairo_surface_set_color_space (surface, color_space);
else
color_space = gdk_color_space_get_srgb ();
surface_status = cairo_surface_status (surface);
if (surface_status != CAIRO_STATUS_SUCCESS)
g_warning ("%s: surface error: %s", __FUNCTION__,
cairo_status_to_string (surface_status));
{
g_warning ("%s: surface error: %s", __FUNCTION__,
cairo_status_to_string (surface_status));
}
else
{
gdk_texture_do_download (texture,
GDK_MEMORY_DEFAULT,
color_space,
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;
@@ -734,6 +834,7 @@ gdk_texture_download (GdkTexture *texture,
gdk_texture_do_download (texture,
GDK_MEMORY_DEFAULT,
gdk_color_space_get_srgb (),
data,
stride);
}
@@ -751,7 +852,7 @@ gdk_texture_set_render_data (GdkTexture *self,
GDestroyNotify notify)
{
g_return_val_if_fail (data != NULL, FALSE);
if (self->render_key != NULL)
return FALSE;

View File

@@ -82,6 +82,8 @@ GDK_AVAILABLE_IN_ALL
int gdk_texture_get_width (GdkTexture *texture) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
int gdk_texture_get_height (GdkTexture *texture) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_10
GdkColorSpace * gdk_texture_get_color_space (GdkTexture *texture) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
void gdk_texture_download (GdkTexture *texture,

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