Compare commits

...

175 Commits

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

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

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

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

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

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

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

See merge request GNOME/gtk!7362
2024-06-16 18:16:42 +00:00
Matthias Clasen
153b8399f7 Merge branch 'matthiasc/for-main' into 'main'
css: Move the color space enums to a better place

See merge request GNOME/gtk!7363
2024-06-16 18:14:01 +00:00
Matthias Clasen
da41271dd5 css: Parse interpolation for conic gradients
Parse things like "in hsl hue longer". For details, see the
CSS Images Module Level 4, https://www.w3.org/TR/css-images-4.

This commit fixes preexisting brokenness in conic-gradient parsing
and printing as well, and includes the relevant test changes.

Tests included.

Gradient interpolation color spaces aren't supported for
rendering yet.
2024-06-16 13:22:36 -04:00
Matthias Clasen
5610af1b77 css: Parse interpolation for radial gradients
Parse things like "in hsl hue longer". For details, see the
CSS Images Module Level 4, https://www.w3.org/TR/css-images-4.

Tests included.

Gradient interpolation color spaces aren't supported for
rendering yet.
2024-06-16 13:22:27 -04:00
Matthias Clasen
8da70fec91 css: Parse interpolation for linear gradients
Parse things like "in hsl hue longer". For details, see the
CSS Images Module Level 4, https://www.w3.org/TR/css-images-4.

Tests included.

Gradient interpolation color spaces aren't supported for
rendering yet.
2024-06-16 13:21:56 -04:00
Matthias Clasen
f9cd30a859 css: Better error reporting
I seem to mix up the order of 'longer hue' occasionally, so lets
throw a helpful error message if we see 'hue' first.
2024-06-16 13:04:58 -04:00
Matthias Clasen
763d620a23 css: Parse all supported color spaces
The code parsing interpolation methods hadn't learned about
or latest color space additions. While we're at it, improve
the error reporting a bit.

Tests included.
2024-06-16 13:04:52 -04:00
Matthias Clasen
500a3a6dee css: Add a helper function for parsing
This will be helpful in gradient parsing code, where the color
interpolation is optional.
2024-06-16 13:04:44 -04:00
Matthias Clasen
57073e1057 css: Move the color space enums to a better place
These will be used in the gradient code too, so put them into
a more better place.
2024-06-16 13:04:13 -04:00
Daniel Rusek
6bbfd2f62a Update Czech translation 2024-06-16 13:32:33 +00:00
Gabor Karsay
6c69a96cd7 docs: link some methods in drawing model overview 2024-06-16 10:30:44 +00:00
Gabor Karsay
fa247d5a84 docs: gtk_widget_queue_draw() is a single function, not a set anymore 2024-06-16 10:02:32 +00:00
Matthias Clasen
0320c4ac14 Merge branch 'matthiasc/for-main' into 'main'
gpu: Print some more details

See merge request GNOME/gtk!7360
2024-06-15 21:59:14 +00:00
Matthias Clasen
36993ac707 gpu: Print some more details
Print the variations of mask and blendmode operations.
Just because we can.
2024-06-15 14:00:46 -04:00
Matthias Clasen
2f93eb4a28 Merge branch 'matthiasc/for-main' into 'main'
Fix a copy-paste error

See merge request GNOME/gtk!7358
2024-06-14 23:18:55 +00:00
Matthias Clasen
5a2982ac31 testsuite: Fix one nodeparser error 2024-06-14 14:11:54 -04:00
Matthias Clasen
441b704afd testsuite: Stop relying on xpms
gdk-pixbuf isn't loading those anymore, by default.
2024-06-14 14:11:22 -04:00
Matthias Clasen
abf6ebd7fe label: Only put alpha in attributes when needed
It does not do much harm, but it broke some of our tests.
2024-06-14 14:04:23 -04:00
Matthias Clasen
34fb08af6e Fix a copy-paste error
This was obviously meant to compare two different colors.
2024-06-14 12:30:06 -04:00
Matthias Clasen
0b9dfdd41f Merge branch 'wip/alice/color-fix' into 'main'
More color clamping and redraw fixes

See merge request GNOME/gtk!7357
2024-06-14 11:07:49 +00:00
Alice Mikhaylenko
701e0812e4 treeview: Clamp tree line and grid line colors 2024-06-14 03:04:54 +04:00
Alice Mikhaylenko
4918a46172 textview: Redraw selection on style changes 2024-06-14 03:04:54 +04:00
Alice Mikhaylenko
ef5e3fae64 aboutdialog: Update link colors on css changes 2024-06-14 03:04:54 +04:00
Alice Mikhaylenko
9fcf55571e textlayout: Clamp colors before passing them to Pango 2024-06-14 03:04:54 +04:00
Alice Mikhaylenko
260898ecf6 text: Redraw when selection style changes 2024-06-14 01:41:22 +04:00
Alice Mikhaylenko
66c9132abe label: Update selection on css changes too 2024-06-14 01:41:22 +04:00
Alice Mikhaylenko
c5abdfb72b label: Fix critical when updating styles
Noticed when testing with libadwaita styles instead of GTK styles.
2024-06-13 23:36:38 +04:00
Matthias Clasen
4fe37847ba Merge branch 'wip/alice/color-fix' into 'main'
Fix GtkLabel link color

Closes #6781

See merge request GNOME/gtk!7355
2024-06-13 13:28:58 +00:00
Alice Mikhaylenko
c99a0b0518 label: Track link style changes
If we're gonna have system accents, would be nice to update links reliably
and not wait for other changes like changing color of the label itself.
2024-06-13 16:28:06 +04:00
Alice Mikhaylenko
31f3edec5c label: Clamp out-of-gamut link color
Support alpha too while we're here.

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/6781
2024-06-13 16:28:05 +04:00
Emmanuele Bassi
dee372c08e Merge branch 'ebassi/docs-for-master' into 'main'
docs: Fix link to DragIcon.get_for_drag()

See merge request GNOME/gtk!7347
2024-06-13 11:27:28 +00:00
Matthias Clasen
8c0a4e5a6e Merge branch 'matthiasc/for-main' into 'main'
Silence a compiler warning

See merge request GNOME/gtk!7354
2024-06-12 03:24:29 +00:00
Matthias Clasen
7195514fb5 Silence a compiler warning 2024-06-11 17:47:48 -04:00
Matthias Clasen
420bd5bc16 Merge branch 'more-css-color-spaces' into 'main'
css: Add more color spaces

See merge request GNOME/gtk!7352
2024-06-11 21:05:06 +00:00
Matthias Clasen
f024ee1adf Add more tests for css colors 2024-06-11 16:41:22 -04:00
Matthias Clasen
18c2c71cd5 css: Add support for rec2100-pq colors
This is our first HDR color space. Yay!!

The conversion between rec2020-linear and rec2100-linear
assumes that SDR 1,1,1 has a luminance of 203 cd/m².
2024-06-11 16:41:22 -04:00
Matthias Clasen
2d1bfc84b9 Expose more colorutils
We may want to have a rec2020-linear space available on the gsk
level, so expose the conversion functions for it.
2024-06-11 16:41:22 -04:00
Matthias Clasen
8edfa759fb css: Add support for rec2020 colors
Another extremely wide gamut color space.
2024-06-11 16:41:22 -04:00
Matthias Clasen
2d1e978599 css: Add support for xyz colors
This is somewhat central, and we have all the pieces to support
it, so we might as well add the css syntax for it.
2024-06-11 16:41:22 -04:00
Matthias Clasen
d71fc41152 css: Add support for display-p3 colors
A wide-gamut colorspace.
2024-06-11 16:41:22 -04:00
Matthias Clasen
d141cb7b72 Fix an oversight
This snuck in as part of 098d67f8befdb00d75.
2024-06-11 16:41:22 -04:00
Matthias Clasen
7010067884 Merge branch 'vulkan-high-depth' into 'main'
gpu: Print more info for renderpasses

See merge request GNOME/gtk!7351
2024-06-09 21:10:25 +00:00
Matthias Clasen
0ec29c4176 gsk: Pass the memory format for back buffer
We can now get this information from the Vulkan context,
so use it to accurately represent the back buffer.

Related: #6767
2024-06-09 15:59:56 -04:00
Matthias Clasen
42c6e0249f vulkan: Fix updating swap chains
gdk_vulkan_context_check_swapchain uses priv->current_format,
so we must update it first, and undo that if check_swapchain
falls. This fixes handling of high-depth back buffers in gsk.
2024-06-09 15:59:56 -04:00
Matthias Clasen
54eb85f814 vulkan: Add a getter for the memory format
We need this to accurately set up the gpu image for the
backbuffer in gsk.
2024-06-09 15:59:56 -04:00
Matthias Clasen
18b3b4feed gpu: Print more info for images
Show the memory format.

This helps debugging our depth selection.
2024-06-09 15:59:32 -04:00
Matthias Clasen
0045ac839b Give memory formats a name
This is useful in debugging.

The names I chose are shortened a bit from the enum values. We
use just a single depth, * for premultiplied, and f for float.
2024-06-09 15:59:27 -04:00
Matthias Clasen
a9da807de3 Merge branch 'cmurtag/fix_harfbuzz_subset_wrap' into 'main'
Fix Harfbuzz subset dependency not found in wrap

See merge request GNOME/gtk!7349
2024-06-08 10:26:12 +00:00
cameron
366639b7e4 Fix Harfbuzz subset dependency not found in wrap
Add harfbuzz subset to the harfbuzz wrap file so Meson can find the
dependency.
2024-06-08 13:54:21 +10:00
Emmanuele Bassi
7d2e2171be docs: Fix link to DragIcon.get_for_drag()
It has been marked as a constructor in commit 13013053f7.
2024-06-07 13:33:32 +02:00
Matthias Clasen
e3ceda15ac Merge branch 'gsktransform-improve-docs' into 'main'
gsktransform: Document consuming functions

See merge request GNOME/gtk!7342
2024-06-06 10:53:17 +00:00
Matthias Clasen
7291a21a85 Merge branch 'wip/alice/css' into 'main'
CSS fixes and more tests

See merge request GNOME/gtk!7345
2024-06-05 20:54:12 +00:00
Matthias Clasen
888afe3e46 Merge branch 'wip/alice/opacity' into 'main'
css: Allow percents in opacity

See merge request GNOME/gtk!7346
2024-06-05 20:53:55 +00:00
Alice Mikhaylenko
171bfde133 csscolorvalue: Fix percentage ranges for relative colors
Add tests as well, now that they can be computed at parse time.
2024-06-06 00:35:52 +04:00
Alice Mikhaylenko
82d1fdb714 csscolorvalue: Resolve relative colors at parse time when possible 2024-06-06 00:35:52 +04:00
Alice Mikhaylenko
82b19daa7e csscolorvalue: Don't serialize relative colors as rgb()
Spec says it should be color(srgb).
2024-06-06 00:35:52 +04:00
Alice Mikhaylenko
dc1ff3c2e3 csscolorvalue: Fix oklab() percentage range 2024-06-06 00:35:52 +04:00
Alice Mikhaylenko
6602ac5eae testsuite: Fix css tests
There are a bunch of new deprecations, and some tests weren't in
meson.build.
2024-06-06 00:35:52 +04:00
Alice Mikhaylenko
5dab5bf0e9 css: Allow percents in opacity
Add another missing feature from web css. It's nice to be able to use the
same variables in color-mix() and here.
2024-06-06 00:22:19 +04:00
Matthijs Velsink
721be8fe9f gsktransform: Document consuming functions
Since GskTransform is immutable, a lot of the documented "methods" are
more like "functions", in the sense that they don't keep the instance
alive but rather consume it.

This is annotated with `(transfer full)`, but since these functions are
listed as methods, their first argument is not shown.

Instead, let's add a line to the docs of each consuming function that
clarifies this behavior.
2024-06-05 15:59:49 +02:00
Matthias Clasen
58fe590eae Merge branch 'matthiasc/for-main' into 'main'
css: Plug a memory leak

See merge request GNOME/gtk!7341
2024-06-05 12:18:50 +00:00
Matthias Clasen
c18a7ff5cf css: Plug a memory leak
This snuck in when the relative color support was merged.
2024-06-05 07:22:47 -04:00
Matthias Clasen
24fc38b287 Merge branch 'matthiasc/for-main' into 'main'
docs: Improve css color migration docs

See merge request GNOME/gtk!7340
2024-06-04 18:47:21 +00:00
Matthias Clasen
aa03c50f05 theme: Use better replacements for color expressions
These match what we recommend for migration.
2024-06-04 12:54:41 -04:00
Matthias Clasen
03e971b2e3 Revert "theme: Stop using alpha() and shade()"
This reverts commit 0e94e5ecda.
2024-06-04 12:48:55 -04:00
Matthias Clasen
a595133b77 docs: Improve css color migration docs
With relative colors, we can do better.
2024-06-04 12:39:40 -04:00
Matthias Clasen
e50f4ecccf NEWS: Updates 2024-06-04 12:00:02 -04:00
Matthias Clasen
67913e4af0 docs: Add more details about CSS colors 2024-06-04 12:00:02 -04:00
Matthias Clasen
b3d1795327 Merge branch 'file-chooser-shortcut-new-folder' into 'main'
gtkfilechooserwidget: Add shortcut to create a new folder

Closes #5527

See merge request GNOME/gtk!7338
2024-06-04 15:38:38 +00:00
Matthias Clasen
6edcc8f256 Merge branch 'css-relative-colors' into 'main'
css: Support relative colors

See merge request GNOME/gtk!7326
2024-06-04 14:59:00 +00:00
Matthias Clasen
d5e5f47666 css: Add tests for relative colors 2024-06-04 10:47:54 -04:00
Matthias Clasen
0524c40640 css: Support relative colors
Parse the various color(from <color> ...) syntaxes, and implement
them.

Add a new 'relative color' subtype for color values, and a new
'color coord' subtype for number values. Use these for relative
colors where the original color can't be resolved at parse time.
2024-06-04 10:47:54 -04:00
Matthias Clasen
b5fd894f77 css: Add a function to get color coords
This will be used in the implementation of relative colors.
2024-06-04 10:47:21 -04:00
Matthias Clasen
d8492121aa css: Rewrite the color parsing code
Make this more uniform, and easier to extend.

Also, use gtk_css_number_value_parse_with_context, since we
are going to add context here in the future.
2024-06-04 10:47:21 -04:00
Matthias Clasen
4a0bf603d7 css: Add context for parsing numbers
In the future, parsing numbers will depend one some context, so
add a context struct to the involved apis. This is not used yet.
2024-06-04 10:47:21 -04:00
Matthias Clasen
02fa89df9e css: Change the api for resolving colors
We will need to compute other values in here in the future, and for
that we need all the arguments that get passed to compute(), so carry
them along.

Update all callers.
2024-06-04 10:47:21 -04:00
Martin
5b6dde9a73 Update Slovenian translation 2024-06-04 07:27:42 +00:00
Automeris naranja
e9d8ebdfc9 gtkfilechooserwidget: Add shortcut to create a new folder
Closes https://gitlab.gnome.org/GNOME/gtk/-/issues/5527
2024-06-03 22:49:11 -03:00
Matthias Clasen
366efc3d61 Merge branch 'css-color-deprecations2' into 'main'
css: Deprecate our own color functions

See merge request GNOME/gtk!7311
2024-06-04 00:41:44 +00:00
Matthias Clasen
3b890fd3c1 css: Document replacements for color stuff
Document how named colors and non-standard color expressions
can be replaced.
2024-06-03 20:37:52 -04:00
Matthias Clasen
5de373a14b css: Deprecate our own color functions
We will soon have new standards-conformant color functions from
the css-colors-5 spec, so these can be phased out.
2024-06-03 20:37:52 -04:00
Matthias Clasen
24cb9d2437 docs: Fix the 4to5 migration guide
This was referring to a nonexisting api.
2024-06-03 20:37:52 -04:00
Matthias Clasen
83aa176466 docs: Add the 4to5 migration guide to the docs
Adding this to the built docs ensures that it is buildable.
2024-06-03 20:37:52 -04:00
Matthias Clasen
0e94e5ecda theme: Stop using alpha() and shade()
These are being phased out in favor of color-mix().
2024-06-03 20:37:52 -04:00
Matthias Clasen
130485a583 Merge branch 'wip/alice/colors-2' into 'main'
Implement color-mix()

See merge request GNOME/gtk!7336
2024-06-03 21:17:54 +00:00
Alice Mikhaylenko
f34c10abb5 csscolorvalue: Get rid of the literal type
Just use color with srgb color space and serialize_as_rgb=TRUE.
2024-06-03 23:59:44 +04:00
Alice Mikhaylenko
48b00f0ac1 testsuite: Add color-mix() tests 2024-06-03 23:59:44 +04:00
Alice Mikhaylenko
743329a3af csscolorvalue: Implement color-mix() 2024-06-03 23:59:44 +04:00
Alice Mikhaylenko
f5783f1637 csscolor: Add functions for parsing and printing interpolation method 2024-06-03 23:59:44 +04:00
Matthias Clasen
67f61a8d39 Merge branch 'matthiasc/for-main' into 'main'
Fix the build

See merge request GNOME/gtk!7337
2024-06-03 19:16:22 +00:00
Matthias Clasen
f7df663dea Fix the build
I typoed in a2223c0884.
2024-06-03 15:10:19 -04:00
Alice Mikhaylenko
c99278aa58 csscolor: Allow printing hsl and hwb as color() too 2024-06-03 22:09:26 +04:00
Alice Mikhaylenko
1765e1b7c2 testsuite: Add GTK_DEBUG=css
Make named color tests work, since they expect deprecation warnings atm.
2024-06-03 21:53:52 +04:00
Matthias Clasen
bf1a434d5c Merge branch 'font-subsetting-in-node-files' into 'main'
Use font subsetting in serialized nodes

See merge request GNOME/gtk!7227
2024-06-03 12:47:59 +00:00
Matthias Clasen
9256b5b552 rendernode tool: Add an extract command
This lets one extract the data urls from a node file.
2024-06-03 08:28:21 -04:00
Matthias Clasen
577e4afb3c Improve font deserialization
Even if we disable font fallback, after adding Cantarell Regular
to the custom fontmap, fontconfig will helpfully synthesize
Cantarell Bold for us. So, just don't check for the font at all.
If there is a url, add it to the fontmap and leave it up to the
serializing code to ensure that we don't end up with duplicate
fonts.
2024-06-03 07:45:57 -04:00
Matthias Clasen
2a05c04db7 Use the hb face as key when tracking fonts
The hb face is is a wrapper around the font file, which is what
we need to track here, since we want to subset and serialize each
used font file exactly once.
2024-06-03 07:44:16 -04:00
Matthias Clasen
a6ffd6b3b2 nodeparser: Subset fonts
When serializing nodes, collect the glyphs that are used from
each font, subset the font to that set of glyphs, and embed it
into the node file. We are careful to preserve the glyph IDs,
so our text nodes transparently work with the subsettted fonts.
2024-06-03 07:38:51 -04:00
Matthias Clasen
24eba7c4c1 Merge branch 'matthiasc/for-main' into 'main'
Drop redundant GLib version check

See merge request GNOME/gtk!7334
2024-06-03 00:22:16 +00:00
Matthias Clasen
80de844922 Cosmetics 2024-06-02 20:07:33 -04:00
Matthias Clasen
a2223c0884 Drop redundant GLib version check
We require GLib 2.76 now.
2024-06-02 20:07:33 -04:00
Matthias Clasen
5ffa2b757c Merge branch 'less-vulkan' into 'main'
Don't use Vulkan without dmabufs

See merge request GNOME/gtk!7220
2024-06-02 23:58:24 +00:00
Matthias Clasen
b660fa27d3 Merge branch 'fix-missing-listeners' into 'main'
wayland: Add missing listeners

See merge request GNOME/gtk!7331
2024-06-02 20:42:13 +00:00
Matthias Clasen
77f0e5e1ba wayland: Add missing listeners
Now that we are using version 6 of the compositor interface,
we need to have preferred scale and bufer transform callbacks
everywhere.
2024-06-02 12:07:51 -04:00
Matthias Clasen
32a4f805b8 gsk: Require dmabuf support for Vulkan
Don't use the Vulkan renderer if Vulkan doesn't support any
dmabuf formats.
2024-05-05 15:19:17 -04:00
271 changed files with 13113 additions and 2085 deletions

View File

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

34
NEWS
View File

@@ -1,6 +1,40 @@
Overview of Changes in 4.15.2, xx-xx-xxxx
=========================================
* GtkFileChooserWidget:
- Plug some memory leaks
- Make Ctrl-Shift-N create a new folder
* CSS:
- Support color(), oklab(), etc (https://www.w3.org/TR/css-color-4/)
- Support color-mix() (https://www.w3.org/TR/css-color-5/)
- Support relative colors (https://www.w3.org/TR/css-color-5/)
* Accessibility:
- Avoid markup when reading labels
* GSK:
- Subset fonts when serializing node trees
* Wayland:
- Use xdg-dialog protocol for attached dialogs
* Windows:
- Build with UNICODE
* Debugging:
- Add GTK_DEBUG=css for warning about deprecated css syntax
* Tools:
- nodeparser: Add an extract command for data urls
* Deprecations:
- CSS Color functions shade(), lighter(), darker(), alpha(), mix()
* Translation updates:
Hebrew
Overview of Changes in 4.15.1, 21-05-2024
=========================================

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

View File

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

View File

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

View File

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

View File

@@ -93,11 +93,12 @@ Colors can be expressed in numerous ways in CSS (see the
many (but not all) of these.
You can use rgb(), rgba(), hsl() with both the legacy or the modern CSS
syntax, and calc() can be used as well in color expressions.
syntax, and calc() can be used as well in color expressions. hwb(), oklab(),
oklch(), color(), color-mix() and relative colors are supported as well.
### Non-CSS Colors
GTK extends the CSS syntax with several additional ways to specify colors.
GTK extends the CSS syntax with several additional ways to specify colors.
These extensions are deprecated and should be replaced by the equivalent
standard CSS notions.

View File

@@ -99,16 +99,15 @@ reaches the requested phase. However, in practice most things
happen at higher levels:
- If you are doing an animation, you can use
gtk_widget_add_tick_callback() which will cause a regular
[method@Gtk.Widget.add_tick_callback] which will cause a regular
beating of the clock with a callback in the Update phase
until you stop the tick.
- If some state changes that causes the size of your widget to
change you call gtk_widget_queue_resize() which will request
change you call [method@Gtk.Widget.queue_resize] which will request
a Layout phase and mark your widget as needing relayout.
- If some state changes so you need to redraw some area of
your widget you use the normal gtk_widget_queue_draw()
set of functions. These will request a Paint phase and
mark the region as needing redraw.
- If some state changes so you need to redraw your widget you
use [method@Gtk.Widget.queue_draw] to request a Paint phase for
your widget.
There are also a lot of implicit triggers of these from the
CSS layer (which does animations, resizes and repaints as needed).

View File

@@ -18,6 +18,7 @@ SYNOPSIS
|
| **gtk4-rendernode-tool** benchmark [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** compare [OPTIONS...] <FILE1> <FILE2>
| **gtk4-rendernode-tool** extract [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** info [OPTIONS...] <FILE>
| **gtk4-rendernode-tool** render [OPTIONS...] <FILE> [<FILE>]
| **gtk4-rendernode-tool** show [OPTIONS...] <FILE>
@@ -99,3 +100,15 @@ exit code is 1. If the images are identical, it is 0.
``--quiet``
Don't write results to stdout.
Extract
^^^^^^^
The ``extract`` command saves all the data urls found in a node file to a given
directory. The file names for the extracted files are derived from the mimetype
of the url.
``--dir=DIRECTORY``
Save extracted files in ``DIRECTORY`` (defaults to the current directory).

View File

@@ -77,6 +77,7 @@ content_files = [
"section-tree-widget.md",
"migrating-2to4.md",
"migrating-3to4.md",
"migrating-4to5.md",
"broadway.md",
"osx.md",
"wayland.md",

View File

@@ -14,6 +14,7 @@ expand_content_md_files = [
'running.md',
'migrating-2to4.md',
'migrating-3to4.md',
'migrating-4to5.md',
'actions.md',
'input-handling.md',
'drawing-model.md',

View File

@@ -58,7 +58,7 @@ 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].
[method@Gtk.Widget.get_color].
## Local stylesheets are going away
@@ -73,6 +73,103 @@ 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.
## Non-standard CSS extensions are going away
GTK's CSS machinery has a some non-standard extensions around colors:
named colors with \@define-color and color functions: lighter(), darker(),
shade(), alpha(), mix().
GTK now implements equivalent functionality from the CSS specs.
### \@define-color is going away
\@define-color should be replaced by custom properties in the :root scope.
Instead of
```
@define-color fg_color #2e3436
...
box {
color: @fg_color;
}
```
use
```
:root {
--fg-color: #2e3436;
}
...
box {
color: var(--fg-color);
}
```
For more information about custom CSS properties and variables, see the
[CSS Custom Properties for Cascading Variables](https://www.w3.org/TR/css-variables-1/)
spec.
### Color expressions are going away
The color functions can all be replaced by combinations of calc() and color-mix().
ligher(c) and darker(c) are just shade(c, 1.3) or shade(c, 0.7), respectively, and
thus can be handled the same way as shade in the examples below.
Replace
```
a {
color: mix(red, green, 0.8);
}
b {
color: alpha(green, 0.6);
}
c {
color: shade(red, 1.3);
}
d {
color: shade(red, 0.7);
}
```
with
```
a {
color: color-mix(in srgb, red, green 80%);
}
b {
color: rgb(from green, r g b / calc(alpha * 0.6));
}
c {
color: hsl(from red, h calc(s * 1.3) calc(l * 1.3));
}
d {
color: hsl(from red, h calc(s * 0.7) calc(l * 0.7));
}
```
Variations of these replacements are possible.
Note that GTK has historically computed mix() and shade() values in the SRGB and HSL
colorspaces, but using OKLAB instead might yield slightly better results.
For more information about color-mix(), see the
[CSS Color](https://drafts.csswg.org/css-color-5) spec.
## Chooser interfaces are going away
The GtkColorChooser, GtkFontChooser, GtkFileChooser and GtkAppChooser

View File

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

View File

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

View File

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

View File

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

View File

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

507
gdk/gdkcolor.c Normal file
View File

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

106
gdk/gdkcolor.h Normal file
View File

@@ -0,0 +1,106 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright (C) 2021 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <gdk/gdktypes.h>
#include <gdk/gdkcolorstate.h>
#include <gdk/gdkrgba.h>
/* The interpretation of the first 3 components depends on the color state.
* values[3] is always alpha.
*/
struct _GdkColor
{
GdkColorState *color_state;
float values[4];
};
G_STATIC_ASSERT (sizeof (GdkColor) % sizeof (gpointer) == 0);
#define GDK_TYPE_COLOR (gdk_color_get_type ())
G_BEGIN_DECLS
#define GDK_COLOR_INIT(cs, c1, c2, c3, c4) \
(GdkColor) { (cs), { (c1), (c2), (c3), (c4) } }
#define GDK_COLOR_INIT_SRGB(c1, c2, c3, c4) \
GDK_COLOR_INIT (GDK_COLOR_STATE_SRGB, (c1), (c2), (c3), (c4) )
#define GDK_COLOR_INIT_RGBA(r) \
GDK_COLOR_INIT_SRGB ((r)->red, (r)->green, (r)->blue, (r)->alpha)
GDK_AVAILABLE_IN_4_16
GType gdk_color_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_16
GdkColor * gdk_color_copy (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
void gdk_color_free (GdkColor *self);
GDK_AVAILABLE_IN_4_16
void gdk_color_init (GdkColor *self,
GdkColorState *color_state,
const float components[4]);
GDK_AVAILABLE_IN_4_16
void gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba);
GDK_AVAILABLE_IN_4_16
void gdk_color_convert (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other);
GDK_AVAILABLE_IN_4_16
void gdk_color_convert_rgba (GdkColor *self,
GdkColorState *color_state,
const GdkRGBA *rgba);
GDK_AVAILABLE_IN_4_16
void gdk_color_mix (GdkColor *self,
GdkColorState *color_state,
const GdkColor *src1,
const GdkColor *src2,
double progress);
GDK_AVAILABLE_IN_4_16
void gdk_color_print (const GdkColor *self,
GString *string);
GDK_AVAILABLE_IN_4_16
char * gdk_color_to_string (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_get_color_state (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
const float * gdk_color_get_components (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_equal (const GdkColor *color1,
const GdkColor *color2);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_is_black (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_is_clear (const GdkColor *self);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_is_opaque (const GdkColor *self);
#include "gdkcolorimpl.h"
G_END_DECLS

122
gdk/gdkcolorimpl.h Normal file
View File

@@ -0,0 +1,122 @@
/* GDK - The GIMP Drawing Kit
*
* Copyright (C) 2021 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define gdk_color_init(self, cs, comp) _gdk_color_init ((self), (cs), (comp))
static inline void
_gdk_color_init (GdkColor *self,
GdkColorState *color_state,
const float components[4])
{
self->color_state = color_state;
self->values[0] = components[0];
self->values[1] = components[1];
self->values[2] = components[2];
self->values[3] = components[3];
}
#define gdk_color_init_from_rgb(self, rgba) _gdk_color_init_from_rgba (self, rgba)
static inline void
_gdk_color_init_from_rgba (GdkColor *self,
const GdkRGBA *rgba)
{
self->color_state = GDK_COLOR_STATE_SRGB;
self->values[0] = rgba->red;
self->values[1] = rgba->green;
self->values[2] = rgba->blue;
self->values[3] = rgba->alpha;
}
#define gdk_color_get_color_state(self) _gdk_color_get_color_state (self)
static inline GdkColorState *
_gdk_color_get_color_state (const GdkColor *self)
{
return self->color_state;
}
#define gdk_color_get_components(self) _gdk_color_get_components (self)
static inline const float *
_gdk_color_get_components (const GdkColor *self)
{
return self->values;
}
#define gdk_color_equal(self, other) _gdk_color_equal (self, other)
static inline gboolean
_gdk_color_equal (const GdkColor *self,
const GdkColor *other)
{
return self->values[0] == other->values[0] &&
self->values[1] == other->values[1] &&
self->values[2] == other->values[2] &&
self->values[3] == other->values[3] &&
gdk_color_state_equal (self->color_state, other->color_state);
}
static inline gboolean
all_zero (const GdkColor *c)
{
return c->values[0] == 0 && c->values[1] == 0 && c->values[2] == 0;
}
#define gdk_color_is_black(self) _gdk_color_is_black (self)
static inline gboolean
_gdk_color_is_black (const GdkColor *self)
{
if (gdk_color_state_equal (self->color_state, GDK_COLOR_STATE_SRGB))
return all_zero (self);
else
{
GdkColor c;
gboolean res;
gdk_color_convert (&c, GDK_COLOR_STATE_SRGB, self);
res = all_zero (&c);
return res;
}
}
#define gdk_color_is_clear(self) _gdk_color_is_clear (self)
static inline gboolean
_gdk_color_is_clear (const GdkColor *self)
{
return self->values[3] < ((float) 0x00ff / (float) 0xffff);
}
#define gdk_color_is_opaque(self) _gdk_color_is_opaque (self)
static inline gboolean
_gdk_color_is_opaque (const GdkColor *self)
{
return self->values[3] > ((float)0xff00 / (float)0xffff);
}
#define gdk_color_convert(self, cs, other) _gdk_color_convert (self, cs, other)
static inline void
_gdk_color_convert (GdkColor *self,
GdkColorState *color_state,
const GdkColor *other)
{
if (gdk_color_state_equal (color_state, other->color_state))
{
gdk_color_init (self, color_state, other->values);
return;
}
(gdk_color_convert) (self, color_state, other);
}

27
gdk/gdkcolorprivate.h Normal file
View File

@@ -0,0 +1,27 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2024, Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "gdkcolor.h"
#include "gtk/css/gtkcssparserprivate.h"
gboolean gdk_color_parser_parse (GtkCssParser *parser,
GdkColor *color);

950
gdk/gdkcolorstate.c Normal file
View File

@@ -0,0 +1,950 @@
/* gdkcolorstate.c
*
* Copyright 2024 Matthias Clasen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkcolorstateprivate.h"
#include <glib/gi18n-lib.h>
#include "gtk/gtkcolorutilsprivate.h"
/**
* GdkColorState:
*
* A `GdkColorState` object provides the information to interpret
* colors and pixels in a variety of ways.
*
* They are also known as
* [*color spaces*](https://en.wikipedia.org/wiki/Color_space).
*
* Crucially, GTK knows how to convert colors from one color
* state to another.
*
* `GdkColorState objects are immutable and therefore threadsafe.
*
* Since 4.16
*/
static GdkColorStateClass * get_class (GdkColorState *self);
G_DEFINE_BOXED_TYPE (GdkColorState, gdk_color_state,
gdk_color_state_ref, gdk_color_state_unref);
/* {{{ Public API */
GdkColorState *
(gdk_color_state_ref) (GdkColorState *self)
{
return _gdk_color_state_ref (self);
}
void
(gdk_color_state_unref) (GdkColorState *self)
{
_gdk_color_state_unref (self);
}
GdkColorState *
(gdk_color_state_get_srgb) (void)
{
return _gdk_color_state_get_srgb ();
}
GdkColorState *
(gdk_color_state_get_srgb_linear) (void)
{
return _gdk_color_state_get_srgb_linear ();
}
GdkColorState *
(gdk_color_state_get_hsl) (void)
{
return _gdk_color_state_get_hsl ();
}
GdkColorState *
(gdk_color_state_get_hwb) (void)
{
return _gdk_color_state_get_hwb ();
}
GdkColorState *
(gdk_color_state_get_oklab) (void)
{
return _gdk_color_state_get_oklab ();
}
GdkColorState *
(gdk_color_state_get_oklch) (void)
{
return _gdk_color_state_get_oklch ();
}
GdkColorState *
(gdk_color_state_get_display_p3) (void)
{
return _gdk_color_state_get_display_p3 ();
}
GdkColorState *
(gdk_color_state_get_xyz) (void)
{
return _gdk_color_state_get_xyz ();
}
GdkColorState *
(gdk_color_state_get_rec2020) (void)
{
return _gdk_color_state_get_rec2020 ();
}
GdkColorState *
(gdk_color_state_get_rec2100_pq) (void)
{
return _gdk_color_state_get_rec2100_pq ();
}
GdkColorState *
(gdk_color_state_get_rec2100_linear) (void)
{
return _gdk_color_state_get_rec2100_linear ();
}
/**
* gdk_color_state_equal:
* @self: a `GdkColorState`
* @other: another `GdkColorStatee`
*
* Compares two `GdkColorStates` for equality.
*
* Note that this function is not guaranteed to be perfect and two objects
* describing the same color state may compare not equal. However, different
* color states will never compare equal.
*
* Returns: %TRUE if the two color states compare equal
*
* Since: 4.16
*/
gboolean
(gdk_color_state_equal) (GdkColorState *self,
GdkColorState *other)
{
return _gdk_color_state_equal (self, other);
}
/**
* gdk_color_state_is_linear:
* @self: a `GdkColorState`
*
* Returns whether the color state is linear.
*
* Returns: `TRUE` if the color state is linear
* Since: 4.16
*/
gboolean
gdk_color_state_is_linear (GdkColorState *self)
{
return get_class (self)->is_linear (self);
}
/**
* gdk_color_state_save_to_icc_profile:
* @self: a `GdkColorState`
* @error: Return location for an error
*
* Saves the color state to an
* [ICC profile](https://en.wikipedia.org/wiki/ICC_profile).
*
* Some color states cannot be represented as ICC profiles.
* In that case, @error will be set and %NULL will be returned.
*
* Returns: (nullable): A new `GBytes` containing the ICC profile
*
* Since: 4.16
*/
GBytes *
gdk_color_state_save_to_icc_profile (GdkColorState *self,
GError **error)
{
return get_class (self)->save_to_icc_profile (self, error);
}
/**
* gdk_color_state_save_to_cicp_data:
* @self: a `GdkColorState`
* @color_primaries: return location for color primaries
* @transfer_characteristics: return location for transfer characteristics
* @matrix_coefficients: return location for matrix_coefficients
* @full_range: return location for the full range flag
* @error: Return location for an error
*
* Saves the color state as
* [CICP](https://en.wikipedia.org/wiki/Coding-independent_code_points)
* data.
*
* Some color states cannot be represented as CICP data.
* In that case, @error will be set and `FALSE` will be returned.
*
* Returns: (nullable): `TRUE` if the out arguments were set
*
* Since: 4.16
*/
gboolean
gdk_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error)
{
return get_class (self)->save_to_cicp_data (self,
color_primaries,
transfer_characteristics,
matrix_coefficients,
full_range,
error);
}
/* }}} */
/* {{{ ICC implementation */
#define GDK_LCMS_COLOR_STATE(c) ((GdkLcmsColorState *)(c))
typedef struct {
GdkColorState state;
cmsHPROFILE lcms_profile;
} GdkLcmsColorState;
/* {{{ Helpers */
static cmsHPROFILE
gdk_lcms_color_state_get_lcms_profile (GdkColorState *self)
{
g_return_val_if_fail (GDK_IS_LCMS_COLOR_STATE (self), NULL);
return GDK_LCMS_COLOR_STATE (self)->lcms_profile;
}
static cmsHPROFILE
gdk_lcms_get_srgb_profile (void)
{
return cmsCreate_sRGBProfile ();
}
static cmsHPROFILE
gdk_lcms_get_srgb_linear_profile (void)
{
cmsToneCurve *curve;
cmsHPROFILE profile;
curve = cmsBuildGamma (NULL, 1.0);
profile = cmsCreateRGBProfile (&(cmsCIExyY) {
0.3127, 0.3290, 1.0
},
&(cmsCIExyYTRIPLE) {
{ 0.6400, 0.3300, 1.0 },
{ 0.3000, 0.6000, 1.0 },
{ 0.1500, 0.0600, 1.0 }
},
(cmsToneCurve*[3]) { curve, curve, curve });
cmsFreeToneCurve (curve);
return profile;
}
static GBytes *
gdk_lcms_save_profile (cmsHPROFILE profile,
GError **error)
{
cmsUInt32Number size;
guchar *data;
size = 0;
if (!cmsSaveProfileToMem (profile, NULL, &size))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Could not prepare ICC profile"));
return NULL;
}
data = g_malloc (size);
if (!cmsSaveProfileToMem (profile, data, &size))
{
g_free (data);
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to save ICC profile"));
return NULL;
}
return g_bytes_new_take (data, size);
}
/* }}} */
/* {{{ GdkColorState vfuncs */
static void
gdk_lcms_color_state_free (GdkColorState *state)
{
GdkLcmsColorState *self = (GdkLcmsColorState *) state;
cmsCloseProfile (self->lcms_profile);
g_free (self);
}
static gboolean
gdk_lcms_color_state_equal (GdkColorState *state1,
GdkColorState *state2)
{
GBytes *icc1, *icc2;
gboolean res;
icc1 = gdk_color_state_save_to_icc_profile (state1, NULL);
icc2 = gdk_color_state_save_to_icc_profile (state2, NULL);
res = g_bytes_equal (icc1, icc2);
g_bytes_unref (icc1);
g_bytes_unref (icc2);
return res;
}
static gboolean
gdk_lcms_color_state_is_linear (GdkColorState *state)
{
return FALSE; /* FIXME */
}
static GBytes *
gdk_lcms_color_state_save_to_icc_profile (GdkColorState *state,
GError **error)
{
GdkLcmsColorState *self = GDK_LCMS_COLOR_STATE (state);
return gdk_lcms_save_profile (self->lcms_profile, error);
}
static gboolean
gdk_lcms_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("This color state does not support CICP data"));
return FALSE;
}
static const char *
gdk_lcms_color_state_get_name (GdkColorState *self)
{
static char buffer[48];
g_snprintf (buffer, sizeof (buffer), "lcms color state %p", self);
return buffer;
}
static guint
gdk_lcms_color_state_get_min_depth (GdkColorState *self)
{
return GDK_MEMORY_U16; /* ? */
}
static int
gdk_lcms_color_state_get_hue_coord (GdkColorState *self)
{
return -1;
}
static GdkColorStateClass LCMS_COLOR_STATE_CLASS =
{
GDK_TYPE_LCMS_COLOR_STATE,
gdk_lcms_color_state_free,
gdk_lcms_color_state_equal,
gdk_lcms_color_state_is_linear,
gdk_lcms_color_state_save_to_icc_profile,
gdk_lcms_color_state_save_to_cicp_data,
gdk_lcms_color_state_get_name,
gdk_lcms_color_state_get_min_depth,
gdk_lcms_color_state_get_hue_coord,
};
/* }}} */
/* {{{ Private API */
GdkColorState *
gdk_color_state_new_from_lcms_profile (cmsHPROFILE lcms_profile)
{
GdkLcmsColorState *self;
self= g_new0 (GdkLcmsColorState, 1);
self->state.klass = &LCMS_COLOR_STATE_CLASS;
self->state.ref_count = 1;
self->lcms_profile = lcms_profile;
return (GdkColorState *) self;
}
/* }}} */
/* {{{ Public API */
/**
* gdk_color_state_new_from_icc_profile:
* @icc_profile: The ICC profiles given as a `GBytes`
* @error: Return location for an error
*
* Creates a new color state for the given ICC profile data.
*
* if the profile is not valid, %NULL is returned and an error
* is raised.
*
* Returns: a new `GdkColorState` or %NULL on error
*
* Since: 4.16
*/
GdkColorState *
gdk_color_state_new_from_icc_profile (GBytes *icc_profile,
GError **error)
{
cmsHPROFILE lcms_profile;
const guchar *data;
gsize size;
g_return_val_if_fail (icc_profile != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
data = g_bytes_get_data (icc_profile, &size);
lcms_profile = cmsOpenProfileFromMem (data, size);
if (lcms_profile == NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Failed to load ICC profile"));
return NULL;
}
return gdk_color_state_new_from_lcms_profile (lcms_profile);
}
/* }}} */
/* }}} */
/* {{{ Named implementation */
static gboolean
gdk_named_color_state_is_linear (GdkColorState *self)
{
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return TRUE;
case GDK_COLOR_STATE_ID_SRGB:
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
return FALSE;
default:
g_assert_not_reached ();
}
}
static GBytes *
gdk_named_color_state_save_to_icc_profile (GdkColorState *self,
GError **error)
{
cmsHPROFILE profile;
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_SRGB:
profile = gdk_lcms_get_srgb_profile ();
break;
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
profile = gdk_lcms_get_srgb_linear_profile ();
break;
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
profile = NULL;
break;
default:
g_assert_not_reached ();
}
if (profile)
{
GBytes *bytes;
bytes = gdk_lcms_save_profile (profile, error);
cmsCloseProfile (profile);
return bytes;
}
else
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
_("ICC profile not supported for this color state"));
return NULL;
}
}
static gboolean
gdk_named_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error)
{
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_SRGB:
*color_primaries = 0;
*transfer_characteristics = 13;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
*color_primaries = 0;
*transfer_characteristics = 8;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_REC2100_PQ:
*color_primaries = 9;
*transfer_characteristics = 16;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
*color_primaries = 9;
*transfer_characteristics = 8;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_DISPLAY_P3:
*color_primaries = 12;
*transfer_characteristics = 13;
*matrix_coefficients = 0;
*full_range = TRUE;
return TRUE;
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
break;
default:
g_assert_not_reached ();
}
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
_("This color state does not support CICP data"));
return FALSE;
}
const char *
gdk_color_state_get_name_from_id (GdkColorStateId id)
{
const char *names[] = {
"srgb", "srgb-linear", "hsl", "hwb",
"oklab", "oklch", "display-p3", "xyz",
"rec2020", "rec2100-pq", "rec2100-linear",
};
return names[(id - 1) >> 1];
}
static const char *
gdk_named_color_state_get_name (GdkColorState *self)
{
return gdk_color_state_get_name_from_id (GDK_NAMED_COLOR_STATE_ID (self));
}
static guint
gdk_named_color_state_get_min_depth (GdkColorState *self)
{
switch (GDK_NAMED_COLOR_STATE_ID (self))
{
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_OKLCH:
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
return GDK_MEMORY_FLOAT16;
case GDK_COLOR_STATE_ID_SRGB:
return GDK_MEMORY_U8;
default:
g_assert_not_reached ();
}
}
static int
gdk_named_color_state_get_hue_coord (GdkColorState *in)
{
switch (GDK_NAMED_COLOR_STATE_ID (in))
{
case GDK_COLOR_STATE_ID_SRGB:
case GDK_COLOR_STATE_ID_SRGB_LINEAR:
case GDK_COLOR_STATE_ID_OKLAB:
case GDK_COLOR_STATE_ID_DISPLAY_P3:
case GDK_COLOR_STATE_ID_XYZ:
case GDK_COLOR_STATE_ID_REC2020:
case GDK_COLOR_STATE_ID_REC2100_PQ:
case GDK_COLOR_STATE_ID_REC2100_LINEAR:
return -1;
case GDK_COLOR_STATE_ID_HSL:
case GDK_COLOR_STATE_ID_HWB:
return 0;
case GDK_COLOR_STATE_ID_OKLCH:
return 2;
default:
g_assert_not_reached ();
}
}
static GdkColorStateClass NAMED_COLOR_STATE_CLASS =
{
GDK_TYPE_NAMED_COLOR_STATE,
NULL,
NULL,
gdk_named_color_state_is_linear,
gdk_named_color_state_save_to_icc_profile,
gdk_named_color_state_save_to_cicp_data,
gdk_named_color_state_get_name,
gdk_named_color_state_get_min_depth,
gdk_named_color_state_get_hue_coord,
};
/* }}} */
/* {{{ CICP support */
GdkColorState *
gdk_color_state_new_from_cicp_data (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range)
{
/* FIXME We don't support these */
if (!full_range || matrix_coefficients != 0)
return NULL;
/* Look for cases we can handle */
if (color_primaries == 0 && transfer_characteristics == 13)
return gdk_color_state_get_srgb ();
else if (color_primaries == 0 && transfer_characteristics == 8)
return gdk_color_state_get_srgb_linear ();
else if (color_primaries == 9 && transfer_characteristics == 16)
return gdk_color_state_get_rec2100_pq ();
else if (color_primaries == 9 && transfer_characteristics == 8)
return gdk_color_state_get_rec2100_linear ();
else if (color_primaries == 12 && transfer_characteristics == 13)
return gdk_color_state_get_display_p3 ();
return NULL;
}
/* }}} */
/* {{{ Private API */
static GdkColorStateClass *
get_class (GdkColorState *self)
{
if (GDK_IS_NAMED_COLOR_STATE (self))
return &NAMED_COLOR_STATE_CLASS;
return self->klass;
}
GdkMemoryDepth
gdk_color_state_get_min_depth (GdkColorState *self)
{
return (GdkMemoryDepth) get_class (self)->get_min_depth (self);
}
const char *
gdk_color_state_get_name (GdkColorState *self)
{
return get_class (self)->get_name (self);
}
int
gdk_color_state_get_hue_coord (GdkColorState *self)
{
return get_class (self)->get_hue_coord (self);
}
/* }}} */
/* {{{ Conversion */
#define two_step(name, func1, func2) \
static void \
name (float r, float g, float b, \
float *x, float *y, float *z) \
{ \
func1 (r, g, b, x, y, z); \
func2 (*x, *y, *z, x, y, z); \
}
/* A full complement of xyz <> anything step functions */
two_step (srgb_to_xyz, gtk_rgb_to_linear_srgb, gtk_linear_srgb_to_xyz)
two_step (xyz_to_srgb, gtk_xyz_to_linear_srgb, gtk_linear_srgb_to_rgb)
two_step (hsl_to_xyz, gtk_hsl_to_rgb, srgb_to_xyz)
two_step (xyz_to_hsl, xyz_to_srgb, gtk_rgb_to_hsl)
two_step (hwb_to_xyz, gtk_hwb_to_rgb, srgb_to_xyz)
two_step (xyz_to_hwb, xyz_to_srgb, gtk_rgb_to_hwb)
two_step (oklab_to_xyz, gtk_oklab_to_linear_srgb, gtk_linear_srgb_to_xyz)
two_step (xyz_to_oklab, gtk_xyz_to_linear_srgb, gtk_linear_srgb_to_oklab)
two_step (oklch_to_xyz, gtk_oklch_to_oklab, oklab_to_xyz)
two_step (xyz_to_oklch, xyz_to_oklab, gtk_oklab_to_oklch)
two_step (p3_to_xyz, gtk_p3_to_rgb, srgb_to_xyz)
two_step (xyz_to_p3, xyz_to_srgb, gtk_rgb_to_p3)
two_step (rec2100_linear_to_xyz, gtk_rec2100_linear_to_rec2020_linear, gtk_rec2020_linear_to_xyz)
two_step (xyz_to_rec2100_linear, gtk_xyz_to_rec2020_linear, gtk_rec2020_linear_to_rec2100_linear)
two_step (rec2100_pq_to_xyz, gtk_rec2100_pq_to_rec2100_linear, rec2100_linear_to_xyz)
two_step (xyz_to_rec2100_pq, xyz_to_rec2100_linear, gtk_rec2100_linear_to_rec2100_pq)
static struct {
GdkColorStateId n1;
GdkColorStateId n2;
StepFunc func;
} functions[] = {
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_SRGB_LINEAR, gtk_rgb_to_linear_srgb },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_HSL, gtk_rgb_to_hsl },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_HWB, gtk_rgb_to_hwb },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_OKLAB, gtk_rgb_to_oklab },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_DISPLAY_P3, gtk_rgb_to_p3 },
{ GDK_COLOR_STATE_ID_SRGB, GDK_COLOR_STATE_ID_XYZ, srgb_to_xyz },
{ GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_SRGB, gtk_linear_srgb_to_rgb },
{ GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_OKLAB, gtk_linear_srgb_to_oklab },
{ GDK_COLOR_STATE_ID_SRGB_LINEAR, GDK_COLOR_STATE_ID_XYZ, gtk_linear_srgb_to_xyz },
{ GDK_COLOR_STATE_ID_HSL, GDK_COLOR_STATE_ID_SRGB, gtk_hsl_to_rgb },
{ GDK_COLOR_STATE_ID_HSL, GDK_COLOR_STATE_ID_XYZ, hsl_to_xyz },
{ GDK_COLOR_STATE_ID_HWB, GDK_COLOR_STATE_ID_SRGB, gtk_hwb_to_rgb },
{ GDK_COLOR_STATE_ID_HWB, GDK_COLOR_STATE_ID_XYZ, hwb_to_xyz },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_SRGB, gtk_oklab_to_rgb },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_SRGB_LINEAR, gtk_oklab_to_linear_srgb },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_OKLCH, gtk_oklab_to_oklch },
{ GDK_COLOR_STATE_ID_OKLAB, GDK_COLOR_STATE_ID_XYZ, oklab_to_xyz },
{ GDK_COLOR_STATE_ID_OKLCH, GDK_COLOR_STATE_ID_OKLAB, gtk_oklch_to_oklab },
{ GDK_COLOR_STATE_ID_OKLCH, GDK_COLOR_STATE_ID_XYZ, oklch_to_xyz },
{ GDK_COLOR_STATE_ID_DISPLAY_P3, GDK_COLOR_STATE_ID_SRGB, gtk_p3_to_rgb },
{ GDK_COLOR_STATE_ID_DISPLAY_P3, GDK_COLOR_STATE_ID_XYZ, p3_to_xyz },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_SRGB, xyz_to_srgb },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_SRGB_LINEAR, gtk_xyz_to_linear_srgb },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_HSL, xyz_to_hsl },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_HWB, xyz_to_hwb },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_OKLAB, xyz_to_oklab },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_OKLCH, xyz_to_oklch },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_DISPLAY_P3, xyz_to_p3 },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2020, gtk_xyz_to_rec2020 },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2100_PQ, xyz_to_rec2100_pq },
{ GDK_COLOR_STATE_ID_XYZ, GDK_COLOR_STATE_ID_REC2100_LINEAR, xyz_to_rec2100_linear },
{ GDK_COLOR_STATE_ID_REC2020, GDK_COLOR_STATE_ID_XYZ, gtk_rec2020_to_xyz },
{ GDK_COLOR_STATE_ID_REC2100_PQ, GDK_COLOR_STATE_ID_XYZ, rec2100_pq_to_xyz },
{ GDK_COLOR_STATE_ID_REC2100_PQ, GDK_COLOR_STATE_ID_REC2100_LINEAR, gtk_rec2100_pq_to_rec2100_linear },
{ GDK_COLOR_STATE_ID_REC2100_LINEAR, GDK_COLOR_STATE_ID_REC2100_PQ, gtk_rec2100_linear_to_rec2100_pq },
{ GDK_COLOR_STATE_ID_REC2100_LINEAR, GDK_COLOR_STATE_ID_XYZ, rec2100_linear_to_xyz },
};
static StepFunc
find_function (GdkColorStateId n1, GdkColorStateId n2)
{
for (int k = 0; k < G_N_ELEMENTS (functions); k++)
{
if (functions[k].n1 == n1 && functions[k].n2 == n2)
return functions[k].func;
}
return NULL;
}
void
gdk_color_state_transform_init (GdkColorStateTransform *tf,
GdkColorState *from,
GdkColorState *to,
gboolean copy_alpha)
{
memset (tf, 0, sizeof (GdkColorStateTransform));
if (GDK_IS_NAMED_COLOR_STATE (from) &&
GDK_IS_NAMED_COLOR_STATE (to))
{
tf->step1 = find_function (GDK_NAMED_COLOR_STATE_ID (from),
GDK_NAMED_COLOR_STATE_ID (to));
if (tf->step1 == NULL && from != to)
{
tf->step1 = find_function (GDK_NAMED_COLOR_STATE_ID (from),
GDK_COLOR_STATE_ID_XYZ);
tf->step2 = find_function (GDK_COLOR_STATE_ID_XYZ,
GDK_NAMED_COLOR_STATE_ID (to));
}
}
else
{
cmsHPROFILE profile1, profile2;
if (GDK_IS_LCMS_COLOR_STATE (from))
profile1 = gdk_lcms_color_state_get_lcms_profile (from);
else
profile1 = NULL;
if (GDK_IS_LCMS_COLOR_STATE (to))
profile2 = gdk_lcms_color_state_get_lcms_profile (to);
else
profile2 = NULL;
if (profile1 && profile2)
{
tf->transform = cmsCreateTransform (profile1,
TYPE_RGBA_FLT,
profile2,
TYPE_RGBA_FLT,
INTENT_PERCEPTUAL,
copy_alpha ? cmsFLAGS_COPY_ALPHA : 0);
}
else if (GDK_IS_NAMED_COLOR_STATE (from) && profile2)
{
tf->step1 = find_function (GDK_NAMED_COLOR_STATE_ID (from),
GDK_COLOR_STATE_ID_XYZ);
profile1 = cmsCreateXYZProfile ();
tf->transform = cmsCreateTransform (profile1,
TYPE_RGBA_FLT,
profile2,
TYPE_RGBA_FLT,
INTENT_PERCEPTUAL,
copy_alpha ? cmsFLAGS_COPY_ALPHA : 0);
tf->cms_first = FALSE;
}
else if (profile1 && GDK_IS_NAMED_COLOR_STATE (to))
{
profile2 = cmsCreateXYZProfile ();
tf->transform = cmsCreateTransform (profile1,
TYPE_RGBA_FLT,
profile2,
TYPE_RGBA_FLT,
INTENT_PERCEPTUAL,
copy_alpha ? cmsFLAGS_COPY_ALPHA : 0);
tf->step1 = find_function (GDK_COLOR_STATE_ID_XYZ,
GDK_NAMED_COLOR_STATE_ID (to));
tf->cms_first = TRUE;
}
else
g_assert_not_reached ();
g_clear_pointer (&profile1, cmsCloseProfile);
g_clear_pointer (&profile2, cmsCloseProfile);
}
tf->copy_alpha = copy_alpha;
}
void
gdk_color_state_transform_finish (GdkColorStateTransform *tf)
{
if (tf->transform)
cmsDeleteTransform (tf->transform);
}
void
gdk_color_state_transform (GdkColorStateTransform *tf,
const float *src,
float *dst,
int width)
{
if (tf->copy_alpha)
memcpy (dst, src, sizeof (float) * 4 * width);
else
{
for (int i = 0; i < width * 4; i += 4)
{
dst[i] = src[i];
dst[i + 1] = src[i + 1];
dst[i + 2] = src[i + 2];
}
}
if (tf->cms_first && tf->transform)
cmsDoTransform (tf->transform, dst, dst, width);
if (tf->step1 && tf->step2)
{
for (int i = 0; i < width * 4; i += 4)
{
tf->step1 (dst[i], dst[i+1], dst[i+2], &dst[i], &dst[i+1], &dst[i+2]);
tf->step2 (dst[i], dst[i+1], dst[i+2], &dst[i], &dst[i+1], &dst[i+2]);
}
}
else if (tf->step1)
{
for (int i = 0; i < width * 4; i += 4)
tf->step1 (dst[i], dst[i+1], dst[i+2], &dst[i], &dst[i+1], &dst[i+2]);
}
if (!tf->cms_first && tf->transform)
cmsDoTransform (tf->transform, dst, dst, width);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

104
gdk/gdkcolorstate.h Normal file
View File

@@ -0,0 +1,104 @@
/* gdkcolorstate.h
*
* Copyright 2024 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdktypes.h>
G_BEGIN_DECLS
#define GDK_TYPE_COLOR_STATE (gdk_color_state_get_type ())
GDK_AVAILABLE_IN_4_16
GType gdk_color_state_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_ref (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
void gdk_color_state_unref (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_srgb (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_srgb_linear (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_hsl (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_hwb (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_oklab (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_oklch (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_display_p3 (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_xyz (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_rec2020 (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_rec2100_pq (void);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_get_rec2100_linear (void);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_state_equal (GdkColorState *self,
GdkColorState *other);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_state_is_linear (GdkColorState *self);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_new_from_icc_profile (GBytes *icc_profile,
GError **error);
GDK_AVAILABLE_IN_4_16
GdkColorState * gdk_color_state_new_from_cicp_data (int color_primaries,
int transfer_characteristics,
int matrix_coefficients,
gboolean full_range);
GDK_AVAILABLE_IN_4_16
GBytes * gdk_color_state_save_to_icc_profile (GdkColorState *self,
GError **error);
GDK_AVAILABLE_IN_4_16
gboolean gdk_color_state_save_to_cicp_data (GdkColorState *self,
int *color_primaries,
int *transfer_characteristic,
int *matrix_coefficients,
gboolean *full_range,
GError **error);
#include "gdkcolorstateimpl.h"
G_END_DECLS

204
gdk/gdkcolorstateimpl.h Normal file
View File

@@ -0,0 +1,204 @@
/* gdkcolorstateimpl.h
*
* Copyright 2024 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
typedef enum
{
GDK_COLOR_STATE_ID_SRGB = 1,
GDK_COLOR_STATE_ID_SRGB_LINEAR = 3,
GDK_COLOR_STATE_ID_HSL = 5,
GDK_COLOR_STATE_ID_HWB = 7,
GDK_COLOR_STATE_ID_OKLAB = 9,
GDK_COLOR_STATE_ID_OKLCH = 11,
GDK_COLOR_STATE_ID_DISPLAY_P3 = 13,
GDK_COLOR_STATE_ID_XYZ = 15,
GDK_COLOR_STATE_ID_REC2020 = 17,
GDK_COLOR_STATE_ID_REC2100_PQ = 19,
GDK_COLOR_STATE_ID_REC2100_LINEAR = 21,
} GdkColorStateId;
enum
{
GDK_TYPE_NAMED_COLOR_STATE,
GDK_TYPE_LCMS_COLOR_STATE,
};
typedef struct _GdkColorStateClass GdkColorStateClass;
struct _GdkColorState
{
GdkColorStateClass *klass;
int ref_count;
};
struct _GdkColorStateClass
{
int type;
void (* free) (GdkColorState *self);
gboolean (* equal) (GdkColorState *self,
GdkColorState *other);
gboolean (* is_linear) (GdkColorState *self);
GBytes * (* save_to_icc_profile) (GdkColorState *self,
GError **error);
gboolean (* save_to_cicp_data) (GdkColorState *self,
int *color_primaries,
int *transfer_characteristics,
int *matrix_coefficients,
gboolean *full_range,
GError **error);
const char * (* get_name) (GdkColorState *self);
guint (* get_min_depth) (GdkColorState *self);
int (* get_hue_coord) (GdkColorState *self);
};
#define GDK_NAMED_COLOR_STATE_ID(c) ((GdkColorStateId) (GPOINTER_TO_INT (c)))
#define GDK_IS_NAMED_COLOR_STATE(c) ((GPOINTER_TO_INT(c)) & 1)
#define GDK_IS_LCMS_COLOR_STATE(c) ((c)->klass->type == GDK_TYPE_LCMS_COLOR_STATE)
#define gdk_color_state_ref(self) _gdk_color_state_ref (self)
static inline GdkColorState *
_gdk_color_state_ref (GdkColorState *self)
{
if (GDK_IS_NAMED_COLOR_STATE (self))
return self;
self->ref_count++;
return self;
}
#define gdk_color_state_unref(self) _gdk_color_state_unref (self)
static inline void
_gdk_color_state_unref (GdkColorState *self)
{
if (GDK_IS_NAMED_COLOR_STATE (self))
return;
self->ref_count--;
if (self->ref_count == 0)
self->klass->free (self);
}
#define GDK_COLOR_STATE_SRGB ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_SRGB))
#define GDK_COLOR_STATE_SRGB_LINEAR ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_SRGB_LINEAR))
#define GDK_COLOR_STATE_HSL ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_HSL))
#define GDK_COLOR_STATE_HWB ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_HWB))
#define GDK_COLOR_STATE_OKLAB ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_OKLAB))
#define GDK_COLOR_STATE_OKLCH ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_OKLCH))
#define GDK_COLOR_STATE_DISPLAY_P3 ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_DISPLAY_P3))
#define GDK_COLOR_STATE_XYZ ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_XYZ))
#define GDK_COLOR_STATE_REC2020 ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_REC2020))
#define GDK_COLOR_STATE_REC2100_PQ ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_REC2100_PQ))
#define GDK_COLOR_STATE_REC2100_LINEAR ((GdkColorState *) GINT_TO_POINTER (GDK_COLOR_STATE_ID_REC2100_LINEAR))
#define gdk_color_state_get_srgb() _gdk_color_state_get_srgb ()
static inline GdkColorState *
_gdk_color_state_get_srgb (void)
{
return GDK_COLOR_STATE_SRGB;
}
#define gdk_color_state_get_srgb_linear() _gdk_color_state_get_srgb_linear ()
static inline GdkColorState *
_gdk_color_state_get_srgb_linear (void)
{
return GDK_COLOR_STATE_SRGB_LINEAR;
}
#define gdk_color_state_get_hsl() _gdk_color_state_get_hsl ()
static inline GdkColorState *
_gdk_color_state_get_hsl (void)
{
return GDK_COLOR_STATE_HSL;
}
#define gdk_color_state_get_hwb() _gdk_color_state_get_hwb ()
static inline GdkColorState *
_gdk_color_state_get_hwb (void)
{
return GDK_COLOR_STATE_HWB;
}
#define gdk_color_state_get_oklab() _gdk_color_state_get_oklab ()
static inline GdkColorState *
_gdk_color_state_get_oklab (void)
{
return GDK_COLOR_STATE_OKLAB;
}
#define gdk_color_state_get_oklch() _gdk_color_state_get_oklch ()
static inline GdkColorState *
_gdk_color_state_get_oklch (void)
{
return GDK_COLOR_STATE_OKLCH;
}
#define gdk_color_state_get_display_p3() _gdk_color_state_get_display_p3 ()
static inline GdkColorState *
_gdk_color_state_get_display_p3 (void)
{
return GDK_COLOR_STATE_DISPLAY_P3;
}
#define gdk_color_state_get_xyz() _gdk_color_state_get_xyz ()
static inline GdkColorState *
_gdk_color_state_get_xyz (void)
{
return GDK_COLOR_STATE_XYZ;
}
#define gdk_color_state_get_rec2020() _gdk_color_state_get_rec2020 ()
static inline GdkColorState *
_gdk_color_state_get_rec2020 (void)
{
return GDK_COLOR_STATE_REC2020;
}
#define gdk_color_state_get_rec2100_pq() _gdk_color_state_get_rec2100_pq ()
static inline GdkColorState *
_gdk_color_state_get_rec2100_pq (void)
{
return GDK_COLOR_STATE_REC2100_PQ;
}
#define gdk_color_state_get_rec2100_linear() _gdk_color_state_get_rec2100_linear ()
static inline GdkColorState *
_gdk_color_state_get_rec2100_linear (void)
{
return GDK_COLOR_STATE_REC2100_LINEAR;
}
#define gdk_color_state_equal(a,b) _gdk_color_state_equal ((a), (b))
static inline gboolean
_gdk_color_state_equal (GdkColorState *self,
GdkColorState *other)
{
if (self == other)
return TRUE;
if (GDK_IS_NAMED_COLOR_STATE (self) || GDK_IS_NAMED_COLOR_STATE (other))
return FALSE;
if (self->klass != other->klass)
return FALSE;
return self->klass->equal (self, other);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -23,8 +23,9 @@
#include "gdkdmabuffourccprivate.h"
#include "gdkglcontextprivate.h"
#include "gdkcolorstateprivate.h"
#include "gsk/gl/fp16private.h"
#include "gtk/gtkcolorutilsprivate.h"
#include <epoxy/gl.h>
@@ -327,6 +328,7 @@ ADD_ALPHA_FUNC(r8g8b8_to_a8b8g8r8, 0, 1, 2, 3, 2, 1, 0)
struct _GdkMemoryFormatDescription
{
const char *name;
GdkMemoryAlpha alpha;
GdkMemoryFormat premultiplied;
GdkMemoryFormat straight;
@@ -366,6 +368,7 @@ struct _GdkMemoryFormatDescription
static const GdkMemoryFormatDescription memory_formats[] = {
[GDK_MEMORY_B8G8R8A8_PREMULTIPLIED] = {
.name = "*BGRA8",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.straight = GDK_MEMORY_B8G8R8A8,
@@ -394,6 +397,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = b8g8r8a8_premultiplied_from_float,
},
[GDK_MEMORY_A8R8G8B8_PREMULTIPLIED] = {
.name = "*ARGB8",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
.straight = GDK_MEMORY_A8R8G8B8,
@@ -422,6 +426,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = a8r8g8b8_premultiplied_from_float,
},
[GDK_MEMORY_R8G8B8A8_PREMULTIPLIED] = {
.name = "*RGBA8",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.straight = GDK_MEMORY_R8G8B8A8,
@@ -449,6 +454,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r8g8b8a8_premultiplied_from_float,
},
[GDK_MEMORY_A8B8G8R8_PREMULTIPLIED] = {
.name = "*ABGR8",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
.straight = GDK_MEMORY_A8B8G8R8,
@@ -477,6 +483,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = a8b8g8r8_premultiplied_from_float,
},
[GDK_MEMORY_B8G8R8A8] = {
.name = "BGRA8",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_B8G8R8A8_PREMULTIPLIED,
.straight = GDK_MEMORY_B8G8R8A8,
@@ -505,6 +512,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = b8g8r8a8_from_float,
},
[GDK_MEMORY_A8R8G8B8] = {
.name = "ARGB8",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_A8R8G8B8_PREMULTIPLIED,
.straight = GDK_MEMORY_A8R8G8B8,
@@ -533,6 +541,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = a8r8g8b8_from_float,
},
[GDK_MEMORY_R8G8B8A8] = {
.name = "RGBA8",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
.straight = GDK_MEMORY_R8G8B8A8,
@@ -560,6 +569,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r8g8b8a8_from_float,
},
[GDK_MEMORY_A8B8G8R8] = {
.name = "ABGR8",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_A8B8G8R8_PREMULTIPLIED,
.straight = GDK_MEMORY_A8B8G8R8,
@@ -588,6 +598,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = a8b8g8r8_from_float,
},
[GDK_MEMORY_B8G8R8X8] = {
.name = "BGRX8",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_B8G8R8X8,
.straight = GDK_MEMORY_B8G8R8X8,
@@ -617,6 +628,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = b8g8r8x8_from_float,
},
[GDK_MEMORY_X8R8G8B8] = {
.name = "XRGB8",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_X8R8G8B8,
.straight = GDK_MEMORY_X8R8G8B8,
@@ -646,6 +658,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = x8r8g8b8_from_float,
},
[GDK_MEMORY_R8G8B8X8] = {
.name = "RGBX8",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_R8G8B8X8,
.straight = GDK_MEMORY_R8G8B8X8,
@@ -674,6 +687,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r8g8b8x8_from_float,
},
[GDK_MEMORY_X8B8G8R8] = {
.name = "XBGR8",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_X8B8G8R8,
.straight = GDK_MEMORY_X8B8G8R8,
@@ -703,6 +717,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = x8b8g8r8_from_float,
},
[GDK_MEMORY_R8G8B8] = {
.name = "RGB8",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_R8G8B8,
.straight = GDK_MEMORY_R8G8B8,
@@ -731,6 +746,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r8g8b8_from_float,
},
[GDK_MEMORY_B8G8R8] = {
.name = "BGR8",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_B8G8R8,
.straight = GDK_MEMORY_B8G8R8,
@@ -760,6 +776,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = b8g8r8_from_float,
},
[GDK_MEMORY_R16G16B16] = {
.name = "RGB16",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_R16G16B16,
.straight = GDK_MEMORY_R16G16B16,
@@ -791,6 +808,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r16g16b16_from_float,
},
[GDK_MEMORY_R16G16B16A16_PREMULTIPLIED] = {
.name = "*RGBA16",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.straight = GDK_MEMORY_R16G16B16A16,
@@ -821,6 +839,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r16g16b16a16_from_float,
},
[GDK_MEMORY_R16G16B16A16] = {
.name = "RGBA16",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
.straight = GDK_MEMORY_R16G16B16A16,
@@ -851,6 +870,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r16g16b16a16_from_float,
},
[GDK_MEMORY_R16G16B16_FLOAT] = {
.name = "RGBA16f",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_R16G16B16_FLOAT,
.straight = GDK_MEMORY_R16G16B16_FLOAT,
@@ -881,6 +901,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r16g16b16_float_from_float,
},
[GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED] = {
.name = "*RGBA16f",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
.straight = GDK_MEMORY_R16G16B16A16_FLOAT,
@@ -910,6 +931,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r16g16b16a16_float_from_float,
},
[GDK_MEMORY_R16G16B16A16_FLOAT] = {
.name = "RGBA16f",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
.straight = GDK_MEMORY_R16G16B16A16_FLOAT,
@@ -939,6 +961,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r16g16b16a16_float_from_float,
},
[GDK_MEMORY_R32G32B32_FLOAT] = {
.name = "RGB32f",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_R32G32B32_FLOAT,
.straight = GDK_MEMORY_R32G32B32_FLOAT,
@@ -969,6 +992,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r32g32b32_float_from_float,
},
[GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED] = {
.name = "*RGBA32f",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
.straight = GDK_MEMORY_R32G32B32A32_FLOAT,
@@ -998,6 +1022,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r32g32b32a32_float_from_float,
},
[GDK_MEMORY_R32G32B32A32_FLOAT] = {
.name = "RGBA32f",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
.straight = GDK_MEMORY_R32G32B32A32_FLOAT,
@@ -1027,6 +1052,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = r32g32b32a32_float_from_float,
},
[GDK_MEMORY_G8A8_PREMULTIPLIED] = {
.name = "*GA8",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_G8A8_PREMULTIPLIED,
.straight = GDK_MEMORY_G8A8,
@@ -1055,6 +1081,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = g8a8_premultiplied_from_float,
},
[GDK_MEMORY_G8A8] = {
.name = "GA8",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_G8A8_PREMULTIPLIED,
.straight = GDK_MEMORY_G8A8,
@@ -1083,6 +1110,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = g8a8_from_float,
},
[GDK_MEMORY_G8] = {
.name = "G8",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_G8,
.straight = GDK_MEMORY_G8,
@@ -1111,6 +1139,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = g8_from_float,
},
[GDK_MEMORY_G16A16_PREMULTIPLIED] = {
.name = "*GA16",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_G16A16_PREMULTIPLIED,
.straight = GDK_MEMORY_G16A16,
@@ -1142,6 +1171,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = g16a16_premultiplied_from_float,
},
[GDK_MEMORY_G16A16] = {
.name = "GA16",
.alpha = GDK_MEMORY_ALPHA_STRAIGHT,
.premultiplied = GDK_MEMORY_G16A16_PREMULTIPLIED,
.straight = GDK_MEMORY_G16A16,
@@ -1173,6 +1203,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = g16a16_from_float,
},
[GDK_MEMORY_G16] = {
.name = "G16",
.alpha = GDK_MEMORY_ALPHA_OPAQUE,
.premultiplied = GDK_MEMORY_G16,
.straight = GDK_MEMORY_G16,
@@ -1204,6 +1235,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = g16_from_float,
},
[GDK_MEMORY_A8] = {
.name = "A8",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_A8,
.straight = GDK_MEMORY_A8,
@@ -1232,6 +1264,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = a8_from_float,
},
[GDK_MEMORY_A16] = {
.name = "A16",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_A16,
.straight = GDK_MEMORY_A16,
@@ -1263,6 +1296,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = a16_from_float,
},
[GDK_MEMORY_A16_FLOAT] = {
.name = "A16f",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_A16_FLOAT,
.straight = GDK_MEMORY_A16_FLOAT,
@@ -1293,6 +1327,7 @@ static const GdkMemoryFormatDescription memory_formats[] = {
.from_float = a16_float_from_float,
},
[GDK_MEMORY_A32_FLOAT] = {
.name = "A32f",
.alpha = GDK_MEMORY_ALPHA_PREMULTIPLIED,
.premultiplied = GDK_MEMORY_A32_FLOAT,
.straight = GDK_MEMORY_A32_FLOAT,
@@ -1661,6 +1696,12 @@ gdk_memory_format_get_dmabuf_fourcc (GdkMemoryFormat format)
#endif
}
const char *
gdk_memory_format_get_name (GdkMemoryFormat format)
{
return memory_formats[format].name;
}
static void
premultiply (float *rgba,
gsize n)
@@ -1694,14 +1735,18 @@ void
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorState *dest_color_state,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorState *src_color_state,
gsize width,
gsize height)
{
const GdkMemoryFormatDescription *dest_desc = &memory_formats[dest_format];
const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format];
GdkColorStateTransform transform;
gboolean has_transform;
float *tmp;
gsize y;
void (*func) (guchar *, const guchar *, gsize) = NULL;
@@ -1709,7 +1754,8 @@ gdk_memory_convert (guchar *dest_data,
g_assert (dest_format < GDK_MEMORY_N_FORMATS);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
if (src_format == dest_format)
if (gdk_color_state_equal (src_color_state, dest_color_state) &&
src_format == dest_format)
{
gsize bytes_per_row = src_desc->bytes_per_pixel * width;
@@ -1729,7 +1775,9 @@ gdk_memory_convert (guchar *dest_data,
return;
}
if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
if (!gdk_color_state_equal (src_color_state, dest_color_state))
func = NULL;
else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
func = r8g8b8a8_to_r8g8b8a8_premultiplied;
else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
func = r8g8b8a8_to_b8g8r8a8_premultiplied;
@@ -1777,19 +1825,43 @@ gdk_memory_convert (guchar *dest_data,
return;
}
if (!gdk_color_state_equal (src_color_state, dest_color_state))
{
gdk_color_state_transform_init (&transform, src_color_state, dest_color_state, TRUE);
has_transform = TRUE;
}
else
{
has_transform = FALSE;
}
tmp = g_new (float, width * 4);
for (y = 0; y < height; y++)
{
src_desc->to_float (tmp, src_data, width);
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
unpremultiply (tmp, width);
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
if (has_transform)
{
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED)
unpremultiply (tmp, width);
gdk_color_state_transform (&transform, tmp, tmp, width);
if (dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
}
else
{
if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT)
unpremultiply (tmp, width);
else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT)
premultiply (tmp, width);
}
dest_desc->from_float (dest_data, tmp, width);
src_data += src_stride;
dest_data += dest_stride;
}
if (has_transform)
gdk_color_state_transform_finish (&transform);
g_free (tmp);
}

View File

@@ -75,14 +75,16 @@ VkFormat gdk_memory_format_vk_rgba_format (GdkMemoryFormat
VkComponentMapping *out_swizzle);
#endif
guint32 gdk_memory_format_get_dmabuf_fourcc (GdkMemoryFormat format);
const char * gdk_memory_format_get_name (GdkMemoryFormat format);
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
GdkColorState *dest_color_state,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
GdkColorState *src_color_state,
gsize width,
gsize height);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -30,6 +30,7 @@
#include "gdkdmabuftextureprivate.h"
#include "gdkdisplayprivate.h"
#include "gdkprofilerprivate.h"
#include "gdkmemorytexture.h"
#include <glib/gi18n-lib.h>
#include <math.h>
@@ -647,15 +648,18 @@ gdk_vulkan_context_begin_frame (GdkDrawContext *draw_context,
{
if (priv->formats[depth].gdk_format != priv->formats[priv->current_format].gdk_format)
{
GdkMemoryDepth old_format = priv->current_format;
GError *error = NULL;
priv->current_format = depth;
if (!gdk_vulkan_context_check_swapchain (context, &error))
{
g_warning ("%s", error->message);
g_error_free (error);
priv->current_format = old_format;
return;
}
}
priv->current_format = depth;
}
for (i = 0; i < priv->n_images; i++)
{
@@ -1294,6 +1298,15 @@ gdk_vulkan_context_get_image_format (GdkVulkanContext *context)
return priv->formats[priv->current_format].vk_format.format;
}
GdkMemoryFormat
gdk_vulkan_context_get_memory_format (GdkVulkanContext *context)
{
GdkVulkanContextPrivate *priv = gdk_vulkan_context_get_instance_private (context);
g_return_val_if_fail (GDK_IS_VULKAN_CONTEXT (context), GDK_MEMORY_DEFAULT);
return priv->formats[priv->current_format].gdk_format;
}
/**
* gdk_vulkan_context_get_n_images:
* @context: a `GdkVulkanContext`

View File

@@ -94,6 +94,7 @@ VkDevice gdk_vulkan_context_get_device (GdkVulk
VkQueue gdk_vulkan_context_get_queue (GdkVulkanContext *context);
uint32_t gdk_vulkan_context_get_queue_family_index (GdkVulkanContext *context);
VkFormat gdk_vulkan_context_get_image_format (GdkVulkanContext *context);
GdkMemoryFormat gdk_vulkan_context_get_memory_format (GdkVulkanContext *context);
uint32_t gdk_vulkan_context_get_n_images (GdkVulkanContext *context);
VkImage gdk_vulkan_context_get_image (GdkVulkanContext *context,
guint id);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -3866,9 +3866,25 @@ pointer_surface_leave (void *data,
pointer_surface_update_scale (device);
}
static void
pointer_surface_preferred_buffer_scale (void *data,
struct wl_surface *wl_surface,
int32_t factor)
{
}
static void
pointer_surface_preferred_buffer_transform (void *data,
struct wl_surface *wl_surface,
uint32_t transform)
{
}
static const struct wl_surface_listener pointer_surface_listener = {
pointer_surface_enter,
pointer_surface_leave
pointer_surface_leave,
pointer_surface_preferred_buffer_scale,
pointer_surface_preferred_buffer_transform,
};
static void

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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