Compare commits

..

120 Commits

Author SHA1 Message Date
Matthias Clasen 91e19bc36d jpeg: Set errors 2021-09-13 21:08:39 -04:00
Matthias Clasen 30d21ef791 png: loader set error 2021-09-13 21:08:34 -04:00
Matthias Clasen 57b419ebb1 texture: Add error enum 2021-09-13 21:08:27 -04:00
Matthias Clasen 9d303723b0 rendernodeparser: Avoid gdk_texture_new_for_pixbuf
We can just use gdk_texture_new_from_bytes here now.

Update affected test output.
2021-09-13 21:08:21 -04:00
Benjamin Otte 08bd1129ad !fixup gdk_pixbuf_save_to_png_bytes() documentation 2021-09-14 02:46:39 +02:00
Benjamin Otte 0cb0fc8317 testsuite: Add png and tiff methods
We encode the texture to a PNG or TIFF and then decode it again.
2021-09-14 02:46:39 +02:00
Benjamin Otte 874a3837d9 texture: Add gdk_texture_save_to_tiff_bytes() 2021-09-14 02:46:39 +02:00
Benjamin Otte 31fc5a5a54 !fixup tiff save can't fail 2021-09-14 02:46:39 +02:00
Benjamin Otte 40d81f5959 !fixup can't fail 2021-09-14 02:46:39 +02:00
Benjamin Otte 4fad97d8ab Redo tiff load/save without streams
Less code.
2021-09-14 02:46:39 +02:00
Julian Sparber f1a8c95ca4 stack: Dispose children before emitting items-changed
This makes sure that the `GListModel` returned by
`gtk_stack_get_pages()` actually has the items removed before
`items-changed` is emitted.

Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/4255
2021-09-14 02:46:39 +02:00
Matthias Clasen 65a1804f05 rendernodeparser: Use gdk_texture_save_to_png_bytes
Avoid cairo, and use our own api for saving png data.

Update affected test output.
2021-09-13 16:39:09 -04:00
Matthias Clasen 92873e62ed Add tests for the jpeg loader 2021-09-13 15:15:20 -04:00
Matthias Clasen 0f7c33f894 Load jpegs without gdk-pixbuf
Use our own loader for jpeg files.
2021-09-13 15:15:20 -04:00
Matthias Clasen 6a83d38e7b Add code to load jpegs
This lets us avoid gdk-pixbuf for loading
textures from the common image formats.

As a consequence, we are now linking against libjpeg.
2021-09-13 15:15:20 -04:00
Matthias Clasen f89be80562 Add contentserializer tests for textures 2021-09-13 15:15:20 -04:00
Matthias Clasen b66fa84161 Use our own loaders for content (de)serialization
Use our own loader to (de)serialiaze textures
to and from png and tiff.

We still fall back to gdk-pixbuf for handling all
the other image formats, and for pixbufs.
2021-09-13 15:15:20 -04:00
Matthias Clasen ee7f2f9702 Add gdk_texture_save_to_tiff
This is a companion to gdk_texture_save_to_png, using
the tiff format, which will let us avoid lossy conversion
of HDR data, since we can store floating point data.
2021-09-13 15:15:20 -04:00
Matthias Clasen 900011808a Add tests for the tiff loader 2021-09-13 15:15:20 -04:00
Matthias Clasen b8ee9873f3 Load tiffs without gdk-pixbuf
This will let us load floating point data, in
the future.
2021-09-13 15:15:20 -04:00
Matthias Clasen 0c9faea358 Add code to load and save tiff files
Add support for the tiff format, which is flexible
enough to handle all our memory texture formats
without loss.

As a consequence, we are now linking against libtiff.
2021-09-13 15:15:20 -04:00
Matthias Clasen 2568611a8c Add gdk_texture_save_to_png_bytes
Just expose what we already have available
internally, so e.g. tests can use it without
static linking.
2021-09-13 15:15:20 -04:00
Matthias Clasen 4c64111b5b Add tests for the png loader 2021-09-13 15:15:20 -04:00
Matthias Clasen 4f18a34dfa Save pngs without cairo
Use our own loader for pngs, which will allow
us to save e.g. 16-bit data in the future.
2021-09-13 15:15:20 -04:00
Matthias Clasen bc0d315e6c Load pngs without gdk-pixbuf
Use our own loader for pngs, which will allow
us to get e.g. 16-bit data in the future.
2021-09-13 15:15:20 -04:00
Matthias Clasen 13d72eed2d Add code to load and save pngs
Using libpng instead of the lowest-common-denominator
gdk-pixbuf loader. This will allow us to load >8bit data,
and apply gamma and color correction in the future.
For now, this still just provides RGBA8 data.

As a consequence, we are now linking against libpng.
2021-09-13 15:15:20 -04:00
Matthias Clasen 7bafbeffcf Add gdk_texture_new_from_bytes
Add this new api, and make gdk_texture_new_from_file
a wrapper around it.
2021-09-13 14:03:15 -04:00
Benjamin Otte f572ca52d2 Merge branch 'wip/otte/texture-threads' into 'master'
gltexture: Make sure downloading textures works in a different thread

See merge request GNOME/gtk!3942
2021-09-13 00:16:30 +00:00
Benjamin Otte 193b383739 ngl: Simplify and unbug texture download
If we can't handle the texture, always just download_texture() it,
that way we are sure it's a memory texture.
2021-09-13 01:56:47 +02:00
Benjamin Otte 6785461c26 gltexture: Make sure downloading textures works in a different thread
This happens in the real world when using the inspector to look at a
node recording of a GStreamer video while the video is still playing.

GStreamer will use the GL context in a different thread while we are
busy trying to download it.

A test is included.
2021-09-13 01:40:03 +02:00
Philipp Kiemle b9ee9979e7 Update German translation
(cherry picked from commit 17d828fda2)
2021-09-12 21:45:48 +00:00
Benjamin Otte 6bbec87700 Merge branch 'wip/otte/float-textures' into 'master'
Add float texture formats

See merge request GNOME/gtk!3940
2021-09-12 12:55:00 +00:00
Balázs Úr b35608a351 Update Hungarian translation 2021-09-12 06:03:58 +00:00
Benjamin Otte 416763bf2d testsuite: Add tests for gdk_texture_download_float() 2021-09-12 05:54:37 +02:00
Benjamin Otte 9179ebb28e testsuite: Add memory test support for OpenGL up/downloads
Use a GL renderer to upload textures (and then optionally download them
via release() again). This way, we can test that the GL renderer
properly uploads textures to the right formats (not losing information
for HDR for example) and downloads them again.
2021-09-12 05:54:37 +02:00
Benjamin Otte bcc17b3033 testsuite: Add tests uploading the memorytextures
Use a GL renderer and render_texture() them.
2021-09-12 05:54:37 +02:00
Benjamin Otte 00439f9e5c testsuite: Rework memorytexture test some more
Instead of predefined colors, generate them randomly.
2021-09-12 05:54:37 +02:00
Benjamin Otte c9d748fc51 testsuite: Overhaul memorytexture test
Instead of hardcoding pixel values, allow construction of textures by
filling them with GdkRGBA values.
2021-09-12 05:54:37 +02:00
Benjamin Otte 719eafa60c gl: Implement uploading and downloading HDR formats
Also refactor the GL uploading so it does the fallback in a
GLES-compatible way, which means we only need one fallback.
2021-09-12 05:54:37 +02:00
Benjamin Otte 1759d27da9 memorytexture: Add support for HDR formats
Also sanitize the input bytes so the strides match alignment
requirements of the data types.
2021-09-12 05:54:37 +02:00
Benjamin Otte 53275481a5 texture: Add gdk_texture_download_float() 2021-09-12 05:54:37 +02:00
Benjamin Otte cbe6d0da76 gdk: Deprecate gdk_cairo_draw_from_gl()
It's broken with various pixel formats and OpenGL ES, it's hard to
understand what everything does, and gdk_texture_download() can be used
instead.
2021-09-12 05:54:37 +02:00
Benjamin Otte c349ed9562 gltexture: Implement download() via glGetTexImage()
1. The download via gdk_cairo_draw_from_gl() was broken sometimes

2. We get easy conversion on fallback by chaining up and using
   download_texture().

3. One more place where Cairo is no longer necessary.
2021-09-12 05:22:21 +02:00
Benjamin Otte 74ce69a8a1 gltexture: Make release() use download_texture()
1. It avoids Cairo, and in particular conversion to Cairo.

2. Keeping a texture allows easy chaining in the vfuncs.

3. Using a texture means releasing will work for HDR formats
   too, once we add them.
2021-09-12 05:22:21 +02:00
Benjamin Otte 4f17f3ac24 texture: Add gdk_texture_download_texture()
A private vfunc that downloads a texture as a GdkMemoryTexture in
whatever format the texture deems best.

There are multiple reasons for this:

 * GLES cannot download the Cairo format. But it can download some
   format and then just delegate to the GdkMemoryTexture implementation.

 * All the other download vfuncs (including the ones still coming) can
   be implemented via download_texture() and delegation, making the
   interface easier.

 * We want to implement image loading and saving support. By using
   download_texture(), we can save in the actual format of the texture.

 * A potential GdkCompressedTexture could be implemented by just
   providing this one vfunc as a compress() step.
2021-09-12 05:22:21 +02:00
Benjamin Otte 9c8e464b04 texture: Add GdkMemoryConversion private enum
Now gdk_memory_convert() converts to one of these conversions instead of
re(ab)using parts of the GdkMemoryFormat enum.
2021-09-12 05:22:21 +02:00
Benjamin Otte 51d0d13a9e gltexture: release() to a texture, not a cairo_surface
This makes forwarding vfuncs a lot easier, because we can just call them
on the texture.
2021-09-12 05:22:21 +02:00
Benjamin Otte 0ee3b1c861 texture: Remove unused argument from vfunc 2021-09-12 05:22:21 +02:00
Balázs Úr 46f88c69a1 Update Hungarian translation 2021-09-11 23:45:21 +00:00
Benjamin Otte 140976a670 Merge branch 'wip/otte/for-master' into 'master'
rendernode: Write the whole node

See merge request GNOME/gtk!3938
2021-09-11 20:56:39 +00:00
Benjamin Otte 9f2b847835 rendernode: Write the whole node
It turns out g_output_stream_write_bytes() does not write the bytes.
It should be renamed to g_output_stream_write_some_of_the_bytes() maybe.
2021-09-11 22:28:40 +02:00
Benjamin Otte 9e11ea699c Merge branch 'hsl' into 'master'
gdk_rgba_parse: Support HSL colors

See merge request GNOME/gtk!3899
2021-09-11 12:57:25 +00:00
Guillaume Bernard 1a4eebe022 Update French translation
(cherry picked from commit 8ffd7e9f87)
2021-09-11 09:41:32 +00:00
Guillaume Bernard 2963468019 Update French translation
(cherry picked from commit f433c543fe)
2021-09-11 09:36:48 +00:00
Matthias Clasen bfbd95d7d6 Merge branch 'matthiasc/for-master' into 'master'
Stop using config.h.meson

See merge request GNOME/gtk!3936
2021-09-11 02:53:43 +00:00
Matthias Clasen c1c1d4431d Refactor gdk_gl_context_upload_texture slightly
Introduce a gl_internalformat variable. This will
let us handle more formats in a uniform way in
future commits.
2021-09-10 22:17:31 -04:00
Matthias Clasen 155a4fac5c Add vectorized half-float conversion
We can't make the -4 versions inline, since
we use ifuncs for them, so make vectorized
versions.

Test included.
2021-09-10 22:17:31 -04:00
Matthias Clasen 76f481eb7b Stop using config.h.meson
It isn't necessary and makes us miss defines when
we forget to update it.
2021-09-10 21:08:07 -04:00
James Westman 0782c8a051 gdk_rgba_parse: Support HSL colors 2021-09-10 16:56:42 -05:00
Philipp Kiemle 3d27ff1177 Update German translation
(cherry picked from commit 6228954524)
2021-09-10 19:55:59 +00:00
Matthias Clasen 3ada664a89 Merge branch 'matthiasc/for-master' into 'master'
Fix the testupload test

See merge request GNOME/gtk!3934
2021-09-10 13:54:37 +00:00
Matthias Clasen 643a91bd08 Fix the testupload test
This can only ever have worked by accident.
2021-09-10 08:28:32 -04:00
Emin Tufan Çetin c86733b4fa Update Turkish translation 2021-09-10 06:40:43 +00:00
Anders Jonsson 55099b7d0e Update Swedish translation 2021-09-08 20:25:27 +00:00
Boyuan Yang db3858a204 Update Chinese (China) translation 2021-09-05 20:33:21 +00:00
Daniel Șerbănescu 07bff74544 Update Romanian translation
(cherry picked from commit bb72acf9cd)
2021-09-05 18:43:44 +00:00
Daniel Șerbănescu b4262883a8 Update Romanian translation
(cherry picked from commit 63d829bbc1)
2021-09-05 18:34:37 +00:00
Matthias Clasen 563c85e222 Merge branch 'matthiasc/for-master' into 'master'
inspector: Cosmetics

See merge request GNOME/gtk!3925
2021-09-05 17:26:13 +00:00
Matthias Clasen d75246a543 inspector: Cosmetics
Make some settings entries smaller, and make the
scales match in size. Also, inline adjustments
in the ui file, since we can do that now.
2021-09-05 12:59:11 -04:00
Matthias Clasen b3856a3ea0 Merge branch 'matthiasc/for-master' into 'master'
Avoid hand-rolled color glyph information

See merge request GNOME/gtk!3924
2021-09-05 16:12:34 +00:00
Matthias Clasen bd4d24f8ed Bump pango req to 1.49.1
We are using pango api that was introduced in 1.49.1
without ifdefs, so we should require it.
2021-09-05 10:58:50 -04:00
Matthias Clasen 65ce3eb207 Avoid hand-rolled color glyph information
Followup to b244f31337. Pango provides color glyph
information for us now, so we don't need to steal a
bit anymore.
2021-09-05 10:58:50 -04:00
Anders Jonsson 865ac44963 Update Swedish translation
(cherry picked from commit 19af960163)
2021-09-05 14:11:51 +00:00
Yaron Shahrabani 55a935db53 Update Hebrew translation 2021-09-05 13:45:49 +00:00
Matthias Clasen 6fefae3dbb Merge branch 'better-font-rendering-demo' into 'master'
gtk-demo: Improve the font rendering demo

See merge request GNOME/gtk!3923
2021-09-05 04:21:29 +00:00
Matthias Clasen f7c84ddc7f gtk-demo: Font rendering - Add some bling
Fade the outlines and pixels in and out.
2021-09-04 23:41:44 -04:00
Matthias Clasen f4a4dd2615 gtk-demo: Font rendering - expand docs 2021-09-04 23:05:55 -04:00
Matthias Clasen b718d99d1f gtk-demo: Font rendering - Add keynav
Add mnemonics to most controls, and make
Ctrl+/- change the zoom.
2021-09-04 23:00:17 -04:00
Matthias Clasen c7215d1199 gtk-demo: Font rendering - add outlines
Should outlines as well.
2021-09-04 22:56:07 -04:00
Matthias Clasen 24d69ef125 gtk-demo: Font rendering - better start
Turn antialiasing on initially, and turn the
extents and grid off. Otherwise we show pretty
shocking rendering right from the start.
2021-09-04 22:56:07 -04:00
Matthias Clasen 7c3fbdecf2 gtk-demo: Font rendering - improve the grid
Allow changing the character shown in the grid.
2021-09-04 22:56:07 -04:00
Matthias Clasen b77938f40f Cosmetics
Remove an unused object from the font rendering
demo ui file.
2021-09-04 22:55:47 -04:00
Matthias Clasen f703744564 Merge branch 'ebassi/accel-parse-doc' into 'master'
Improve the gtk_accelerator_parse() docs

See merge request GNOME/gtk!3921
2021-09-04 23:39:10 +00:00
Matthias Clasen a3ccff3773 Merge branch 'text-fixes' into 'master'
textview: fix pango context invalidation

See merge request GNOME/gtk!3922
2021-09-04 21:39:30 +00:00
Asier Sarasua Garmendia 9869082c1c Update Basque translation
(cherry picked from commit 0768addbb3)
2021-09-04 20:54:41 +00:00
Matthias Clasen 754212d0f9 textview: Invalidate Pango contexts
We need to invalidate the Pango contexts when
font settings change. Use the new helper
gtk_widget_update_pango_context to make it less
likely that we forget to update some things.
2021-09-04 15:42:05 -04:00
Matthias Clasen a9b81577c6 widget: Provide a helper for updating pango contexts 2021-09-04 15:42:05 -04:00
Matthias Clasen eaa2dada54 Rename an internal function
It occupies a name I want to reuse for something else.
2021-09-04 15:42:05 -04:00
Matthias Clasen ce2b2128bb Revert "gsk: Add font options to text nodes"
This reverts commit f1347f5841.
2021-09-04 15:42:05 -04:00
Matthias Clasen 41c25b8809 Revert "gsk: Add font options to the glyph cache"
This reverts commit 6599cb001f.
2021-09-04 15:42:05 -04:00
Matthias Clasen b5ff35ff3e Revert "gsk: Pass font options along"
This reverts commit 299c7c3514.
2021-09-04 15:42:05 -04:00
Matthias Clasen 06423d807f Revert "gtk: Pass font options along"
This reverts commit 062a15310a.
2021-09-04 15:42:05 -04:00
Goran Vidović 0395395d52 Update Croatian translation
(cherry picked from commit 6fe3b21a01)
2021-09-04 18:12:03 +00:00
Emmanuele Bassi c3ca48b249 Improve the gtk_accelerator_parse() docs
We need to escape the modifiers in angular brackets, or Markdown will
consider them as HTML tags.

We also should document the modifiers we're parsing.
2021-09-04 18:56:08 +01:00
Boyuan Yang 464e0aed04 Update Chinese (China) translation 2021-09-04 17:38:16 +00:00
Goran Vidović d46e4fcecd Update Croatian translation
(cherry picked from commit 543b7defec)
2021-09-04 17:16:26 +00:00
Changwoo Ryu 363fb96e81 Update Korean translation 2021-09-04 09:02:48 +00:00
Changwoo Ryu 2382bd3bb2 Update Korean translation
(cherry picked from commit 0a5af76932)
2021-09-04 08:59:40 +00:00
Anders Jonsson 3b0a9e84ab Update Swedish translation
(cherry picked from commit 2dbcad428a)
2021-09-03 22:59:37 +00:00
Matthias Clasen 850aebea5d Merge branch 'matthiasc/for-master' into 'master'
widget: Redraw when font options change

See merge request GNOME/gtk!3917
2021-09-03 18:16:33 +00:00
Matthias Clasen 26e632e549 widget: Redraw when font options change
Its the right thing to do, even if it is a rare event.
2021-09-03 13:56:29 -04:00
Matthias Clasen 64d2d7074f Merge branch 'small-text-fixes' into 'master'
gsk: Pass font options down

See merge request GNOME/gtk!3908
2021-09-03 17:21:08 +00:00
Matthias Clasen 062a15310a gtk: Pass font options along
Pass the widget's font options along when we
are creating text nodes.
2021-09-03 12:52:05 -04:00
Matthias Clasen 299c7c3514 gsk: Pass font options along
Use the font options from the text node when
looking up glyphs.
2021-09-03 12:52:05 -04:00
Matthias Clasen 6599cb001f gsk: Add font options to the glyph cache
The cairo_t that we create to render glyphs for
the glyph cache needs to match the font options
that are supposedly governing how glyphs are
drawn.

Since we allow font options to be different per
widget in gtk, we need to have them at least at
the level of individual render nodes. Adding them
to the lookup key for the glyph cache has the
side effect of solving another problem: We are
not flushing the cache when font options change.
2021-09-03 12:52:05 -04:00
Matthias Clasen f1347f5841 gsk: Add font options to text nodes
Since font options affect how the glyphs get rendered,
we need to pass the font options down from the gtk level
to where the glyph cache is populated.

Add a new gsk_text_node_new_full api that takes a
cairo_font_options_t in addition to the other parameters.
2021-09-03 12:43:35 -04:00
Matthias Clasen f3ccf62463 gtk-demo: Improve the font rendering demo
Add a toggle for antialiasing, and make the metrics
hinting turn on rounding of positions, to match what
we do with settings now.
2021-09-03 11:29:44 -04:00
Matthias Clasen 44fea33c5d Merge branch 'wip/exalm/buttons' into 'master'
Allow custom children on GtkMenuButton

Closes #4205

See merge request GNOME/gtk!3904
2021-09-03 14:49:09 +00:00
Alexander Mikhaylenko 8b48cf11f9 menubutton: Support custom children
Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/4205
2021-09-03 17:52:46 +05:00
Matthias Clasen e681fdd958 Merge branch 'matthiasc/for-master' into 'master'
Add a README in gtk/compose

See merge request GNOME/gtk!3916
2021-09-03 00:55:45 +00:00
Matthias Clasen d4b7a78c54 Add a README in gtk/compose 2021-09-02 20:10:19 -04:00
Matthias Clasen a45cbad553 Merge branch 'wip/smcv/transparent-is-transparent' into 'master'
reftest-compare: Treat colour channels as undefined if alpha is zero

Closes #4227

See merge request GNOME/gtk!3914
2021-09-02 22:19:27 +00:00
Simon McVittie 16b9a30655 reftest-compare: Treat colour channels as undefined if alpha is zero
If the alpha channel is zero, it doesn't matter what the values of the
red, green and blue channels are: the pixel is still fully transparent.
On most architectures, fully transparent pixels end up all-zeroes
(fully transparent black), matching what's in the reference PNG file;
but on mips*el the blend-difference and blend-normal tests get all-ones
(fully transparent white) and a test failure.

Resolves: https://gitlab.gnome.org/GNOME/gtk/-/issues/4227
Signed-off-by: Simon McVittie <smcv@debian.org>
2021-09-02 22:34:48 +01:00
Jiri Grönroos 82a184a7b7 Update Finnish translation
(cherry picked from commit 33a4ae12ef)
2021-09-02 16:06:57 +00:00
Aurimas Černius 9e198a59b6 Updated Lithuanian translation 2021-09-02 13:51:39 +03:00
Matthias Clasen c002678085 Merge branch 'fix-gst-subproject' into 'master'
media: Check for gstreamer verion instead of using cc.links()

See merge request GNOME/gtk!3910
2021-09-02 01:33:06 +00:00
Matthias Clasen 486cffc361 Merge branch 'hint-metrics-setting' into 'master'
Add a gtk-hint-font-metrics setting

See merge request GNOME/gtk!3912
2021-09-01 23:15:50 +00:00
Matthias Clasen 67495fcc77 Update settings tests
We have a new setting, so the test that is counting
settings needs an update.
2021-09-01 17:16:08 -04:00
Matthias Clasen b26a370ce4 Add a gtk-hint-font-metrics setting
This lets people switch back to font rendering that is closer
to what GTK 3 does. It is not perfect - subpixel antialiasing
is not going to work. But it give us an Escape hatch while
we shake out the bugs in our linear layout.

Related: #3787
2021-09-01 15:52:07 -04:00
Xavier Claessens 2c060663cf media: Check for gstreamer verion instead of using cc.links()
This fix error when gstgl_dep comes from a subproject because in that
case it cannot be used in compiler checks.
2021-09-01 12:04:05 -04:00
101 changed files with 34899 additions and 30577 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ if ! pkg-config --atleast-version=2.66.0 glib-2.0; then
fi
pkg-config --modversion glib-2.0
if ! pkg-config --atleast-version=1.49.0 pango; then
if ! pkg-config --atleast-version=1.49.1 pango; then
git clone https://gitlab.gnome.org/GNOME/pango.git _pango
meson setup _pango_build _pango
meson compile -C _pango_build
-286
View File
@@ -1,286 +0,0 @@
/* always defined to indicate that i18n is enabled */
#define ENABLE_NLS 1
/* Use structured logging */
#define G_LOG_STRUCTURED 1
/* The prefix for our gettext translation domains. */
#mesondefine GETTEXT_PACKAGE
/* Disable deprecation warnings from glib */
#mesondefine GLIB_DISABLE_DEPRECATION_WARNINGS
/* Define the location where the catalogs will be installed */
#mesondefine GTK_LOCALEDIR
/* Define to 1 if you have the `bind_textdomain_codeset' function. */
#mesondefine HAVE_BIND_TEXTDOMAIN_CODESET
/* Have the cloudproviders library */
#mesondefine HAVE_CLOUDPROVIDERS
/* define if we have colord */
#mesondefine HAVE_COLORD
/* Define to 1 if you have the <crt_externs.h> header file. */
#mesondefine HAVE_CRT_EXTERNS_H
/* Define to 1 if you have the `dcgettext' function. */
#mesondefine HAVE_DCGETTEXT
/* Define to 1 if you have the <dlfcn.h> header file. */
#mesondefine HAVE_DLFCN_H
/* Have the ffmpeg library */
#mesondefine HAVE_FFMPEG
/* Define to 1 if you have the <ftw.h> header file. */
#mesondefine HAVE_FTW_H
/* Define to 1 if you have the `getpagesize' function. */
#mesondefine HAVE_GETPAGESIZE
/* Define to 1 if you have the `getresuid' function. */
#mesondefine HAVE_GETRESUID
/* Define if gio-unix is available */
#mesondefine HAVE_GIO_UNIX
/* Define if GStreamer support is available */
#mesondefine HAVE_GSTREAMER
/* Define to 1 if you have the <inttypes.h> header file. */
#mesondefine HAVE_INTTYPES_H
/* Define to 1 if the system has the type `IPrintDialogCallback'. */
#mesondefine HAVE_IPRINTDIALOGCALLBACK
/* Define to 1 if you have the <locale.h> header file. */
#mesondefine HAVE_LOCALE_H
/* Define to 1 if you have the `lstat' function. */
#mesondefine HAVE_LSTAT
/* Define to 1 if you have the `mallinfo' function. */
#mesondefine HAVE_MALLINFO
/* Define to 1 if you have the <memory.h> header file. */
#mesondefine HAVE_MEMORY_H
/* Define to 1 if you have the `mkstemp' function. */
#mesondefine HAVE_MKSTEMP
/* Define to 1 if you have the `mlock` function. */
#mesondefine HAVE_MLOCK
/* Define to 1 if you have a working `mmap' system call. */
#mesondefine HAVE_MMAP
/* Define to 1 if you have a working `madvise' system call. */
#mesondefine HAVE_MADVISE
/* Define to 1 if you have the `posix_fallocate' function. */
#mesondefine HAVE_POSIX_FALLOCATE
/* Have the Xrandr extension library */
#mesondefine HAVE_RANDR
/* Have the Xrandr 1.5 extension library */
#mesondefine HAVE_RANDR15
/* Define to 1 if you have the `sincos' function. */
#mesondefine HAVE_SINCOS
/* Define to 1 if you have the <stdint.h> header file. */
#mesondefine HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#mesondefine HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#mesondefine HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#mesondefine HAVE_STRING_H
/* Define to 1 if you have the <sys/mman.h> header file. */
#mesondefine HAVE_SYS_MMAN_H
/* Define to 1 if you have the <sys/param.h> header file. */
#mesondefine HAVE_SYS_PARAM_H
/* Have the sysprof-capture library */
#mesondefine HAVE_SYSPROF
/* Define to 1 if you have the <sys/stat.h> header file. */
#mesondefine HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/time.h> header file. */
#mesondefine HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#mesondefine HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
#mesondefine HAVE_UNISTD_H
/* Have the Xcursor library */
#mesondefine HAVE_XCURSOR
/* Have the XDAMAGE X extension */
#mesondefine HAVE_XDAMAGE
/* Have the XFIXES X extension */
#mesondefine HAVE_XFIXES
/* Define to 1 if XFree Xinerama is available */
#mesondefine HAVE_XFREE_XINERAMA
/* Have XGenericEvent */
#mesondefine HAVE_XGENERICEVENTS
/* Define to use XKB extension */
#mesondefine HAVE_XKB
/* Have the SYNC extension library */
#mesondefine HAVE_XSYNC
/* Define to 1 if you have the `_lock_file' function */
#mesondefine HAVE__LOCK_FILE
/* Define to 1 if you have the `flockfile' function */
#mesondefine HAVE_FLOCKFILE
/* Define if _NL_MEASUREMENT_MEASUREMENT is available */
#mesondefine HAVE__NL_MEASUREMENT_MEASUREMENT
/* Define if _NL_PAPER_HEIGHT is available */
#mesondefine HAVE__NL_PAPER_HEIGHT
/* Define if _NL_PAPER_WIDTH is available */
#mesondefine HAVE__NL_PAPER_WIDTH
/* Define if _NL_TIME_FIRST_WEEKDAY is available */
#mesondefine HAVE__NL_TIME_FIRST_WEEKDAY
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#mesondefine LT_OBJDIR
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#mesondefine NO_MINUS_C_MINUS_O
/* Define to the address where bug reports for this package should be sent. */
#mesondefine PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#mesondefine PACKAGE_NAME
/* Define to the full name and version of this package. */
#mesondefine PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#mesondefine PACKAGE_TARNAME
/* Define to the home page for this package. */
#mesondefine PACKAGE_URL
/* Define to the version of this package. */
#mesondefine PACKAGE_VERSION
/* Use NSBundle functions to determine load paths for libraries, translations,
etc. */
#mesondefine QUARTZ_RELOCATION
/* Define to 1 if you have the ANSI C header files. */
#mesondefine STDC_HEADERS
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
#endif
/* Enable GNU extensions on systems that have them. */
#ifndef _GNU_SOURCE
# undef _GNU_SOURCE
#endif
/* Enable threading extensions on Solaris. */
#ifndef _POSIX_PTHREAD_SEMANTICS
# undef _POSIX_PTHREAD_SEMANTICS
#endif
/* Enable extensions on HP NonStop. */
#ifndef _TANDEM_SOURCE
# undef _TANDEM_SOURCE
#endif
/* Enable general extensions on Solaris. */
#ifndef __EXTENSIONS__
# undef __EXTENSIONS__
#endif
/* Define to 1 if XInput 2.2 is available */
#mesondefine XINPUT_2_2
/* Define to 1 if the X Window System is missing or not being used. */
#mesondefine X_DISPLAY_MISSING
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
#mesondefine _FILE_OFFSET_BITS
/* defines how to decorate public symbols while building */
#mesondefine _GDK_EXTERN
/* Define for large files, on AIX-style hosts. */
#mesondefine _LARGE_FILES
/* Define to 1 if on MINIX. */
#mesondefine _MINIX
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
#mesondefine _POSIX_1_SOURCE
/* Define to 1 if you need to in order for `stat' and other things to work. */
#mesondefine _POSIX_SOURCE
/* Define to `int' if <sys/types.h> doesn't define. */
#mesondefine gid_t
/* Define to `int' if <sys/types.h> doesn't define. */
#mesondefine uid_t
/* Define to 1 if linux/memfd.h exists */
#mesondefine HAVE_LINUX_MEMFD_H
#mesondefine HAVE_LINUX_INPUT_H
#mesondefine HAVE_DEV_EVDEV_INPUT_H
#mesondefine GTK_SYSCONFDIR
#mesondefine GTK_LOCALEDIR
#mesondefine GTK_DATADIR
#mesondefine GTK_LIBDIR
#mesondefine GTK_PRINT_BACKENDS
#mesondefine HAVE_CAIRO_SCRIPT_INTERPRETER
#mesondefine HAVE_HARFBUZZ
#mesondefine HAVE_PANGOFT
#mesondefine ISO_CODES_PREFIX
/* Define if tracker3 is available */
#mesondefine HAVE_TRACKER3
#mesondefine HAVE_F16C
/* Does the OS support GDesktopAppInfo? */
#mesondefine HAVE_DESKTOPAPPINFO
+3 -4
View File
@@ -287,11 +287,10 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
INT_ATTR (baseline_shift);
break;
/* Ignore font scale, since we treat baseline-shift as indicating
* both. And in practice, they will basically always occur together
* (from a <sup> or <sub>)
*/
case PANGO_ATTR_FONT_SCALE:
INT_ATTR (font_scale);
break;
case PANGO_ATTR_SHAPE:
case PANGO_ATTR_ABSOLUTE_SIZE:
case PANGO_ATTR_GRAVITY:
+163 -13
View File
@@ -1,6 +1,11 @@
/* Pango/Font Rendering
*
* Demonstrates various aspects of font rendering.
* Demonstrates various aspects of font rendering,
* such as hinting, antialiasing and grid alignment.
*
* The demo lets you explore font rendering options
* interactively to get a feeling for they affect the
* shape and positioning of the glyphs.
*/
#include <gtk/gtk.h>
@@ -10,16 +15,21 @@ static GtkWidget *font_button = NULL;
static GtkWidget *entry = NULL;
static GtkWidget *image = NULL;
static GtkWidget *hinting = NULL;
static GtkWidget *anti_alias = NULL;
static GtkWidget *hint_metrics = NULL;
static GtkWidget *up_button = NULL;
static GtkWidget *down_button = NULL;
static GtkWidget *text_radio = NULL;
static GtkWidget *show_grid = NULL;
static GtkWidget *show_extents = NULL;
static GtkWidget *show_pixels = NULL;
static GtkWidget *show_outlines = NULL;
static PangoContext *context;
static int scale = 9;
static int scale = 7;
static double pixel_alpha = 1.0;
static double outline_alpha = 0.0;
static void
update_image (void)
@@ -37,6 +47,8 @@ update_image (void)
cairo_font_options_t *fopt;
cairo_hint_style_t hintstyle;
cairo_hint_metrics_t hintmetrics;
cairo_antialias_t antialias;
cairo_path_t *path;
if (!context)
context = gtk_widget_create_pango_context (image);
@@ -65,6 +77,13 @@ update_image (void)
hintmetrics = CAIRO_HINT_METRICS_OFF;
cairo_font_options_set_hint_metrics (fopt, hintmetrics);
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (anti_alias)))
antialias = CAIRO_ANTIALIAS_GRAY;
else
antialias = CAIRO_ANTIALIAS_NONE;
cairo_font_options_set_antialias (fopt, antialias);
pango_context_set_round_glyph_positions (context, hintmetrics == CAIRO_HINT_METRICS_ON);
pango_cairo_context_set_font_options (context, fopt);
cairo_font_options_destroy (fopt);
pango_context_changed (context);
@@ -85,10 +104,14 @@ update_image (void)
cairo_set_source_rgb (cr, 1, 1, 1);
cairo_paint (cr);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_set_source_rgba (cr, 0, 0, 0, pixel_alpha);
cairo_move_to (cr, 10, 10);
pango_cairo_show_layout (cr, layout);
pango_cairo_layout_path (cr, layout);
path = cairo_copy_path (cr);
cairo_destroy (cr);
g_object_unref (layout);
@@ -127,7 +150,7 @@ update_image (void)
if (gtk_check_button_get_active (GTK_CHECK_BUTTON (show_extents)))
{
cairo_set_source_rgba (cr, 0, 0, 1, 1);
cairo_set_source_rgb (cr, 0, 0, 1);
cairo_rectangle (cr,
scale * (10 + pango_units_to_double (logical.x)) - 0.5,
@@ -140,7 +163,7 @@ update_image (void)
cairo_line_to (cr, scale * (10 + pango_units_to_double (logical.x + logical.width)) + 1,
scale * (10 + pango_units_to_double (baseline)) - 0.5);
cairo_stroke (cr);
cairo_set_source_rgba (cr, 1, 0, 0, 1);
cairo_set_source_rgb (cr, 1, 0, 0);
cairo_rectangle (cr,
scale * (10 + pango_units_to_double (pink.x)) + 0.5,
scale * (10 + pango_units_to_double (pink.y)) + 0.5,
@@ -149,8 +172,36 @@ update_image (void)
cairo_stroke (cr);
}
for (int i = 0; i < path->num_data; i += path->data[i].header.length)
{
cairo_path_data_t *data = &path->data[i];
switch (data->header.type)
{
case CAIRO_PATH_CURVE_TO:
data[3].point.x *= scale; data[3].point.y *= scale;
data[2].point.x *= scale; data[2].point.y *= scale;
data[1].point.x *= scale; data[1].point.y *= scale;
break;
case CAIRO_PATH_LINE_TO:
case CAIRO_PATH_MOVE_TO:
data[1].point.x *= scale; data[1].point.y *= scale;
break;
case CAIRO_PATH_CLOSE_PATH:
break;
default:
g_assert_not_reached ();
}
}
cairo_set_source_rgba (cr, 0, 0, 1, outline_alpha);
cairo_move_to (cr, scale * 20 - 0.5, scale * 20 - 0.5);
cairo_append_path (cr, path);
cairo_stroke (cr);
cairo_surface_destroy (surface);
cairo_destroy (cr);
cairo_path_destroy (path);
}
else
{
@@ -158,10 +209,26 @@ update_image (void)
PangoLayoutRun *run;
PangoGlyphInfo *g;
int i, j;
GString *str;
gunichar ch;
if (*text == '\0')
text = " ";
ch = g_utf8_get_char (text);
str = g_string_new ("");
for (i = 0; i < 4; i++)
{
g_string_append_unichar (str, ch);
g_string_append_unichar (str, 0x200c);
}
layout = pango_layout_new (context);
pango_layout_set_font_description (layout, desc);
pango_layout_set_text (layout, "aaaa", -1);
pango_layout_set_text (layout, str->str, -1);
g_string_free (str, TRUE);
pango_layout_get_extents (layout, &ink, &logical);
pango_extents_to_pixels (&logical, NULL);
@@ -176,7 +243,7 @@ update_image (void)
cairo_set_source_rgb (cr, 0, 0, 0);
for (i = 0; i < 4; i++)
{
g = &(run->glyphs->glyphs[i]);
g = &(run->glyphs->glyphs[2*i]);
g->geometry.width = PANGO_UNITS_ROUND (g->geometry.width * 3 / 2);
}
@@ -184,7 +251,7 @@ update_image (void)
{
for (i = 0; i < 4; i++)
{
g = &(run->glyphs->glyphs[i]);
g = &(run->glyphs->glyphs[2*i]);
g->geometry.x_offset = i * (PANGO_SCALE / 4);
g->geometry.y_offset = j * (PANGO_SCALE / 4);
}
@@ -203,7 +270,6 @@ update_image (void)
cairo_surface_destroy (surface);
}
gtk_picture_set_pixbuf (GTK_PICTURE (image), pixbuf2);
g_object_unref (pixbuf2);
@@ -211,6 +277,78 @@ update_image (void)
pango_font_description_free (desc);
}
static gboolean fading = FALSE;
static double start_pixel_alpha;
static double end_pixel_alpha;
static double start_outline_alpha;
static double end_outline_alpha;
static gint64 start_time;
static gint64 end_time;
static double
ease_out_cubic (double t)
{
double p = t - 1;
return p * p * p + 1;
}
static gboolean
change_alpha (GtkWidget *widget,
GdkFrameClock *clock,
gpointer user_data)
{
gint64 now = g_get_monotonic_time ();
double t;
t = ease_out_cubic ((now - start_time) / (double) (end_time - start_time));
pixel_alpha = start_pixel_alpha + (end_pixel_alpha - start_pixel_alpha) * t;
outline_alpha = start_outline_alpha + (end_outline_alpha - start_outline_alpha) * t;
update_image ();
if (now >= end_time)
{
fading = FALSE;
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}
static void
start_alpha_fade (void)
{
gboolean pixels;
gboolean outlines;
if (fading)
return;
pixels = gtk_check_button_get_active (GTK_CHECK_BUTTON (show_pixels));
outlines = gtk_check_button_get_active (GTK_CHECK_BUTTON (show_outlines));
start_pixel_alpha = pixel_alpha;
if (pixels && outlines)
end_pixel_alpha = 0.5;
else if (pixels)
end_pixel_alpha = 1;
else
end_pixel_alpha = 0;
start_outline_alpha = outline_alpha;
if (outlines)
end_outline_alpha = 1.0;
else
end_outline_alpha = 0.0;
start_time = g_get_monotonic_time ();
end_time = start_time + G_TIME_SPAN_SECOND / 2;
fading = TRUE;
gtk_widget_add_tick_callback (window, change_alpha, NULL, NULL);
}
static void
update_buttons (void)
{
@@ -218,20 +356,26 @@ update_buttons (void)
gtk_widget_set_sensitive (down_button, scale > 1);
}
static void
scale_up (void)
static gboolean
scale_up (GtkWidget *widget,
GVariant *args,
gpointer user_data)
{
scale += 1;
update_buttons ();
update_image ();
return TRUE;
}
static void
scale_down (void)
static gboolean
scale_down (GtkWidget *widget,
GVariant *args,
gpointer user_data)
{
scale -= 1;
update_buttons ();
update_image ();
return TRUE;
}
GtkWidget *
@@ -252,20 +396,26 @@ do_fontrendering (GtkWidget *do_widget)
entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry"));
image = GTK_WIDGET (gtk_builder_get_object (builder, "image"));
hinting = GTK_WIDGET (gtk_builder_get_object (builder, "hinting"));
anti_alias = GTK_WIDGET (gtk_builder_get_object (builder, "antialias"));
hint_metrics = GTK_WIDGET (gtk_builder_get_object (builder, "hint_metrics"));
text_radio = GTK_WIDGET (gtk_builder_get_object (builder, "text_radio"));
show_grid = GTK_WIDGET (gtk_builder_get_object (builder, "show_grid"));
show_extents = GTK_WIDGET (gtk_builder_get_object (builder, "show_extents"));
show_pixels = GTK_WIDGET (gtk_builder_get_object (builder, "show_pixels"));
show_outlines = GTK_WIDGET (gtk_builder_get_object (builder, "show_outlines"));
g_signal_connect (up_button, "clicked", G_CALLBACK (scale_up), NULL);
g_signal_connect (down_button, "clicked", G_CALLBACK (scale_down), NULL);
g_signal_connect (entry, "notify::text", G_CALLBACK (update_image), NULL);
g_signal_connect (font_button, "notify::font-desc", G_CALLBACK (update_image), NULL);
g_signal_connect (hinting, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (anti_alias, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (hint_metrics, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (text_radio, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_grid, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_extents, "notify::active", G_CALLBACK (update_image), NULL);
g_signal_connect (show_pixels, "notify::active", G_CALLBACK (start_alpha_fade), NULL);
g_signal_connect (show_outlines, "notify::active", G_CALLBACK (start_alpha_fade), NULL);
update_image ();
+87 -33
View File
@@ -1,13 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkAdjustment" id="scale_adj">
<property name="upper">24</property>
<property name="step-increment">1</property>
<property name="page-increment">4</property>
</object>
<object class="GtkWindow" id="window">
<property name="default-width">1080</property>
<property name="default-height">430</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child type="title">
@@ -87,35 +82,62 @@
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label">Hinting</property>
<property name="xalign">1</property>
<style>
<class name="dim-label"/>
</style>
<object class="GtkCheckButton" id="show_pixels">
<property name="label">Show _Pixels</property>
<property name="use-underline">1</property>
<property name="active">1</property>
<layout>
<property name="column">3</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="hinting">
<property name="active">0</property>
<property name="valign">center</property>
<items>
<item translatable="yes" id="none">None</item>
<item translatable="yes" id="slight">Slight</item>
<item translatable="yes" id="medium">Medium</item>
<item translatable="yes" id="full">Full</item>
</items>
<object class="GtkCheckButton" id="show_outlines">
<property name="label">Show _Outline</property>
<property name="use-underline">1</property>
<layout>
<property name="column">3</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label">_Hinting</property>
<property name="use-underline">1</property>
<property name="mnemonic-widget">hinting</property>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="hinting">
<property name="active">0</property>
<property name="valign">center</property>
<items>
<item translatable="yes" id="none">None</item>
<item translatable="yes" id="slight">Slight</item>
<item translatable="yes" id="medium">Medium</item>
<item translatable="yes" id="full">Full</item>
</items>
</object>
</child>
<layout>
<property name="column">4</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="hint_metrics">
<property name="label">Hint Metrics</property>
<object class="GtkCheckButton" id="antialias">
<property name="label">_Antialias</property>
<property name="use-underline">1</property>
<property name="active">1</property>
<layout>
<property name="column">4</property>
<property name="row">1</property>
@@ -123,21 +145,31 @@
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_extents">
<property name="label">Show Extents</property>
<property name="active">1</property>
<object class="GtkCheckButton" id="hint_metrics">
<property name="label">Hint _Metrics</property>
<property name="use-underline">1</property>
<layout>
<property name="column">5</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_extents">
<property name="label">Show _Extents</property>
<property name="use-underline">1</property>
<layout>
<property name="column">6</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="show_grid">
<property name="active">1</property>
<property name="label">Show Grid</property>
<property name="label">Show _Grid</property>
<property name="use-underline">1</property>
<layout>
<property name="column">5</property>
<property name="column">6</property>
<property name="row">1</property>
</layout>
</object>
@@ -148,8 +180,19 @@
<style>
<class name="circular"/>
</style>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">&lt;Control&gt;plus</property>
<property name="action">activate</property>
</object>
</child>
</object>
</child>
<layout>
<property name="column">6</property>
<property name="column">7</property>
<property name="row">0</property>
</layout>
</object>
@@ -160,8 +203,19 @@
<style>
<class name="circular"/>
</style>
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">&lt;Control&gt;minus</property>
<property name="action">activate</property>
</object>
</child>
</object>
</child>
<layout>
<property name="column">6</property>
<property name="column">7</property>
<property name="row">1</property>
</layout>
</object>
@@ -170,7 +224,7 @@
<object class="GtkLabel">
<property name="hexpand">1</property>
<layout>
<property name="column">7</property>
<property name="column">8</property>
</layout>
</object>
</child>
+1 -1
View File
@@ -11,7 +11,7 @@ Colorful <span underline="low" underline-color="blue"><span underline="double" u
Colorful <span strikethrough="true" strikethrough-color="magenta">strikethroughs</span> and <span overline="single" overline_color="green">overlines</span>
Superscripts and subscripts: <span font="italic">ε<sub><span size='smaller'>0</span></sub> = ω<sup>ω<sup>ω<sup>.<sup>.<sup>.</sup></sup></sup></sup></sup></span>
Superscripts and subscripts: 𝜀<span rise="-6000" size="x-small" font_desc="italic">0</span> = 𝜔<span rise="8000" size="smaller">𝜔<span rise="14000" size="smaller">𝜔<span rise="20000">.<span rise="23000">.<span rise="26000">.</span></span></span></span></span>
<span letter_spacing="3000">Letterspacing</span>
+1 -1
View File
@@ -50,7 +50,7 @@ cairo_region_t *
gdk_cairo_region_create_from_surface
(cairo_surface_t *surface);
GDK_AVAILABLE_IN_ALL
GDK_DEPRECATED_IN_4_6_FOR(gdk_gl_texture_new)
void gdk_cairo_draw_from_gl (cairo_t *cr,
GdkSurface *surface,
int source,
+118 -17
View File
@@ -25,6 +25,8 @@
#include "filetransferportalprivate.h"
#include "gdktexture.h"
#include "gdkrgbaprivate.h"
#include "loaders/gdkpngprivate.h"
#include "loaders/gdktiffprivate.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
@@ -655,6 +657,88 @@ pixbuf_deserializer (GdkContentDeserializer *deserializer)
deserializer);
}
static void
texture_deserializer_finish (GObject *source,
GAsyncResult *res,
gpointer data)
{
GdkContentDeserializer *deserializer = GDK_CONTENT_DESERIALIZER (source);
GdkTexture *texture;
GValue *value;
GError *error = NULL;
texture = g_task_propagate_pointer (G_TASK (res), &error);
if (texture == NULL)
{
gdk_content_deserializer_return_error (deserializer, error);
return;
}
value = gdk_content_deserializer_get_value (deserializer);
g_value_take_object (value, texture);
gdk_content_deserializer_return_success (deserializer);
}
static GBytes *
read_all_data (GInputStream *source,
GError **error)
{
GOutputStream *output;
gssize size;
GBytes *bytes;
output = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
size = g_output_stream_splice (output, source, 0, NULL, error);
if (size == -1)
{
g_object_unref (output);
return NULL;
}
g_output_stream_close (output, NULL, NULL);
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (output));
g_object_unref (output);
return bytes;
}
static void
deserialize_texture_in_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
GdkContentDeserializer *deserializer = source_object;
GBytes *bytes;
GError *error = NULL;
GdkTexture *texture = NULL;
bytes = read_all_data (gdk_content_deserializer_get_input_stream (deserializer), &error);
if (bytes)
{
texture = gdk_texture_new_from_bytes (bytes, &error);
g_bytes_unref (bytes);
}
if (texture)
g_task_return_pointer (task, texture, g_object_unref);
else
g_task_return_error (task, error);
}
static void
texture_deserializer (GdkContentDeserializer *deserializer)
{
GTask *task;
task = g_task_new (deserializer,
gdk_content_deserializer_get_cancellable (deserializer),
texture_deserializer_finish,
NULL);
g_task_run_in_thread (task, deserialize_texture_in_thread);
g_object_unref (task);
}
static void
string_deserializer_finish (GObject *source,
GAsyncResult *result,
@@ -863,48 +947,65 @@ init (void)
initialized = TRUE;
gdk_content_register_deserializer ("image/png",
GDK_TYPE_TEXTURE,
texture_deserializer,
NULL,
NULL);
gdk_content_register_deserializer ("image/tiff",
GDK_TYPE_TEXTURE,
texture_deserializer,
NULL,
NULL);
formats = gdk_pixbuf_get_formats ();
/* Make sure png comes first */
for (f = formats; f; f = f->next)
{
GdkPixbufFormat *fmt = f->data;
char *name;
char *name;
name = gdk_pixbuf_format_get_name (fmt);
if (g_str_equal (name, "png"))
{
formats = g_slist_delete_link (formats, f);
formats = g_slist_prepend (formats, fmt);
{
formats = g_slist_delete_link (formats, f);
formats = g_slist_prepend (formats, fmt);
g_free (name);
break;
}
g_free (name);
break;
}
g_free (name);
}
}
for (f = formats; f; f = f->next)
{
GdkPixbufFormat *fmt = f->data;
char **mimes, **m;
char *name;
name = gdk_pixbuf_format_get_name (fmt);
mimes = gdk_pixbuf_format_get_mime_types (fmt);
for (m = mimes; *m; m++)
{
gdk_content_register_deserializer (*m,
GDK_TYPE_TEXTURE,
pixbuf_deserializer,
NULL,
NULL);
{
/* Turning pngs and tiffs into textures is handled above */
if (!g_str_equal (name, "png") &&
!g_str_equal (name, "tiff"))
gdk_content_register_deserializer (*m,
GDK_TYPE_TEXTURE,
pixbuf_deserializer,
NULL,
NULL);
gdk_content_register_deserializer (*m,
GDK_TYPE_PIXBUF,
pixbuf_deserializer,
NULL,
NULL);
}
}
g_strfreev (mimes);
g_free (name);
}
g_slist_free (formats);
+113 -18
View File
@@ -26,6 +26,9 @@
#include "filetransferportalprivate.h"
#include "gdktextureprivate.h"
#include "gdkrgba.h"
#include "loaders/gdkpngprivate.h"
#include "loaders/gdktiffprivate.h"
#include "gdkmemorytextureprivate.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <string.h>
@@ -606,6 +609,7 @@ gdk_content_serialize_finish (GAsyncResult *result,
/*** SERIALIZERS ***/
static void
pixbuf_serializer_finish (GObject *source,
GAsyncResult *res,
@@ -658,6 +662,82 @@ pixbuf_serializer (GdkContentSerializer *serializer)
g_object_unref (pixbuf);
}
static void
texture_serializer_finish (GObject *source,
GAsyncResult *res,
gpointer user_data)
{
GdkContentSerializer *serializer = GDK_CONTENT_SERIALIZER (source);
GError *error = NULL;
if (!g_task_propagate_boolean (G_TASK (res), &error))
gdk_content_serializer_return_error (serializer, error);
else
gdk_content_serializer_return_success (serializer);
}
static void
serialize_texture_in_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
GdkContentSerializer *serializer = source_object;
const GValue *value;
GdkTexture *texture;
GBytes *bytes = NULL;
GError *error = NULL;
gboolean result = FALSE;
value = gdk_content_serializer_get_value (serializer);
texture = g_value_get_object (value);
if (strcmp (gdk_content_serializer_get_mime_type (serializer), "image/png") == 0)
bytes = gdk_save_png (texture);
else if (strcmp (gdk_content_serializer_get_mime_type (serializer), "image/tiff") == 0)
bytes = gdk_save_tiff (texture);
else
g_assert_not_reached ();
if (bytes)
{
GInputStream *input = g_memory_input_stream_new_from_bytes (bytes);
gssize spliced;
spliced = g_output_stream_splice (gdk_content_serializer_get_output_stream (serializer),
input,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
gdk_content_serializer_get_cancellable (serializer),
&error);
g_object_unref (input);
g_bytes_unref (bytes);
result = spliced != -1;
}
else
g_set_error_literal (&error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"Saving png failed");
if (result)
g_task_return_boolean (task, result);
else
g_task_return_error (task, error);
}
static void
texture_serializer (GdkContentSerializer *serializer)
{
GTask *task;
task = g_task_new (serializer,
gdk_content_serializer_get_cancellable (serializer),
texture_serializer_finish,
NULL);
g_task_run_in_thread (task, serialize_texture_in_thread);
g_object_unref (task);
}
static void
string_serializer_finish (GObject *source,
GAsyncResult *result,
@@ -877,51 +957,66 @@ init (void)
initialized = TRUE;
gdk_content_register_serializer (GDK_TYPE_TEXTURE,
"image/png",
texture_serializer,
NULL, NULL);
gdk_content_register_serializer (GDK_TYPE_TEXTURE,
"image/tiff",
texture_serializer,
NULL, NULL);
formats = gdk_pixbuf_get_formats ();
/* Make sure png comes first */
for (f = formats; f; f = f->next)
{
GdkPixbufFormat *fmt = f->data;
char *name;
char *name;
name = gdk_pixbuf_format_get_name (fmt);
if (g_str_equal (name, "png"))
{
formats = g_slist_delete_link (formats, f);
formats = g_slist_prepend (formats, fmt);
{
formats = g_slist_delete_link (formats, f);
formats = g_slist_prepend (formats, fmt);
g_free (name);
break;
}
g_free (name);
break;
}
g_free (name);
}
}
for (f = formats; f; f = f->next)
{
GdkPixbufFormat *fmt = f->data;
char **mimes, **m;
char *name;
if (!gdk_pixbuf_format_is_writable (fmt))
continue;
continue;
name = gdk_pixbuf_format_get_name (fmt);
mimes = gdk_pixbuf_format_get_mime_types (fmt);
for (m = mimes; *m; m++)
{
gdk_content_register_serializer (GDK_TYPE_TEXTURE,
*m,
pixbuf_serializer,
gdk_pixbuf_format_get_name (fmt),
g_free);
{
/* Turning textures into pngs or tiffs is handled above */
if (!g_str_equal (name, "png") &&
!g_str_equal (name, "tiff"))
gdk_content_register_serializer (GDK_TYPE_TEXTURE,
*m,
pixbuf_serializer,
gdk_pixbuf_format_get_name (fmt),
g_free);
gdk_content_register_serializer (GDK_TYPE_PIXBUF,
*m,
pixbuf_serializer,
gdk_pixbuf_format_get_name (fmt),
g_free);
}
}
g_strfreev (mimes);
g_free (name);
}
g_slist_free (formats);
+7 -1
View File
@@ -301,7 +301,7 @@ gdk_gl_texture_quads (GdkGLContext *paint_context,
* @width: The width of the region to draw
* @height: The height of the region to draw
*
* The main way to draw GL content in GTK.
* The main way to not draw GL content in GTK.
*
* It takes a render buffer ID (@source_type == GL_RENDERBUFFER) or a texture
* id (@source_type == GL_TEXTURE) and draws it onto @cr with an OVER operation,
@@ -319,6 +319,12 @@ gdk_gl_texture_quads (GdkGLContext *paint_context,
* with alpha components, so make sure you use GL_TEXTURE if using alpha.
*
* Calling this may change the current GL context.
*
* Deprecated: 4.6: The function is overly complex and produces broken output
* in various combinations of arguments. If you want to draw with GL textures
* in GTK, use [ctor@Gdk.GLTexture.new]; if you want to use that texture in
* Cairo, use [method@Gdk.Texture.download] to download the data into a Cairo
* image surface.
*/
void
gdk_cairo_draw_from_gl (cairo_t *cr,
+73 -54
View File
@@ -229,64 +229,83 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
guchar *copy = NULL;
guint gl_format;
guint gl_type;
guint bpp;
GLint gl_internalformat;
GLint gl_format;
GLint gl_type;
gsize bpp;
g_return_if_fail (GDK_IS_GL_CONTEXT (context));
if (priv->use_es)
if (!priv->use_es && data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
{
/* GLES only supports rgba, so convert if necessary */
if (data_format != GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
{
copy = g_malloc (width * height * 4);
gdk_memory_convert (copy, width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
data, stride, data_format,
width, height);
stride = width * 4;
data = copy;
}
bpp = 4;
gl_internalformat = GL_RGBA8;
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
{
gl_internalformat = GL_RGBA8;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_BYTE;
}
else if (priv->use_es && data_format == GDK_MEMORY_B8G8R8)
{
gl_internalformat = GL_RGBA8;
gl_format = GL_BGR;
gl_type = GL_UNSIGNED_BYTE;
}
else if (data_format == GDK_MEMORY_R16G16B16)
{
gl_internalformat = GL_RGBA16;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_SHORT;
}
else if (data_format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
{
gl_internalformat = GL_RGBA16;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_SHORT;
}
else if (data_format == GDK_MEMORY_R16G16B16_FLOAT)
{
gl_internalformat = GL_RGB16F;
gl_format = GL_RGB;
gl_type = GL_HALF_FLOAT;
}
else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED)
{
gl_internalformat = GL_RGBA16F;
gl_format = GL_RGBA;
gl_type = GL_HALF_FLOAT;
}
else if (data_format == GDK_MEMORY_R32G32B32_FLOAT)
{
gl_internalformat = GL_RGB32F;
gl_format = GL_RGB;
gl_type = GL_FLOAT;
}
else if (data_format == GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED)
{
gl_internalformat = GL_RGBA32F;
gl_format = GL_RGBA;
gl_type = GL_FLOAT;
}
else /* Fall-back, convert to GLES format */
{
copy = g_malloc (width * height * 4);
gdk_memory_convert (copy, width * 4,
GDK_MEMORY_CONVERT_GLES_RGBA,
data, stride, data_format,
width, height);
data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
stride = width * 4;
data = copy;
gl_internalformat = GL_RGBA8;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
}
else
{
if (data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
{
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
bpp = 4;
}
else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
{
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_BYTE;
bpp = 3;
}
else if (data_format == GDK_MEMORY_B8G8R8)
{
gl_format = GL_BGR;
gl_type = GL_UNSIGNED_BYTE;
bpp = 3;
}
else /* Fall-back, convert to cairo-surface-format */
{
copy = g_malloc (width * height * 4);
gdk_memory_convert (copy, width * 4,
GDK_MEMORY_DEFAULT,
data, stride, data_format,
width, height);
stride = width * 4;
bpp = 4;
data = copy;
gl_format = GL_BGRA;
gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
}
}
bpp = gdk_memory_format_bytes_per_pixel (data_format);
/* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
* the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
@@ -295,7 +314,7 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
{
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
}
else if ((!priv->use_es ||
@@ -303,14 +322,14 @@ gdk_gl_context_upload_texture (GdkGLContext *context,
{
glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
}
else
{
int i;
glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, NULL);
glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
for (i = 0; i < height; i++)
glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
}
+223 -45
View File
@@ -20,7 +20,8 @@
#include "gdkgltextureprivate.h"
#include "gdkcairo.h"
#include "gdkdisplayprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gdktextureprivate.h"
#include <epoxy/gl.h>
@@ -37,7 +38,7 @@ struct _GdkGLTexture {
GdkGLContext *context;
guint id;
cairo_surface_t *saved;
GdkTexture *saved;
GDestroyNotify destroy;
gpointer data;
@@ -64,50 +65,239 @@ gdk_gl_texture_dispose (GObject *object)
g_clear_object (&self->context);
self->id = 0;
if (self->saved)
{
cairo_surface_destroy (self->saved);
self->saved = NULL;
}
g_clear_object (&self->saved);
G_OBJECT_CLASS (gdk_gl_texture_parent_class)->dispose (object);
}
typedef struct _InvokeData
{
GdkGLTexture *self;
volatile int spinlock;
GFunc func;
gpointer data;
} InvokeData;
static gboolean
gdk_gl_texture_invoke_callback (gpointer data)
{
InvokeData *invoke = data;
GdkGLContext *context;
context = gdk_display_get_gl_context (gdk_gl_context_get_display (invoke->self->context));
gdk_gl_context_make_current (context);
glBindTexture (GL_TEXTURE_2D, invoke->self->id);
invoke->func (invoke->self, invoke->data);
g_atomic_int_set (&invoke->spinlock, 1);
return FALSE;
}
static void
gdk_gl_texture_download (GdkTexture *texture,
const GdkRectangle *area,
guchar *data,
gsize stride)
gdk_gl_texture_run (GdkGLTexture *self,
GFunc func,
gpointer data)
{
InvokeData invoke = { self, 0, func, data };
g_main_context_invoke (NULL, gdk_gl_texture_invoke_callback, &invoke);
while (g_atomic_int_get (&invoke.spinlock) == 0);
}
static void
gdk_gl_texture_do_download_texture (gpointer texture_,
gpointer result_)
{
GdkTexture *texture = texture_;
GdkTexture **result = result_;
GdkMemoryFormat format;
GLint internal_format, gl_format, gl_type;
guchar *data;
gsize stride;
GBytes *bytes;
glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
switch (internal_format)
{
case GL_RGB8:
format = GDK_MEMORY_R8G8B8;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_BYTE;
break;
case GL_RGBA8:
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
case GL_RGB16:
format = GDK_MEMORY_R16G16B16;
gl_format = GL_RGB;
gl_type = GL_UNSIGNED_SHORT;
break;
case GL_RGBA16:
format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_SHORT;
break;
case GL_RGB16F:
format = GDK_MEMORY_R16G16B16_FLOAT;
gl_format = GL_RGB;
gl_type = GL_HALF_FLOAT;
break;
case GL_RGBA16F:
format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_HALF_FLOAT;
break;
case GL_RGB32F:
format = GDK_MEMORY_R32G32B32_FLOAT;
gl_format = GL_RGB;
gl_type = GL_FLOAT;
break;
case GL_RGBA32F:
format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_FLOAT;
break;
default:
g_warning ("Texture in unexpected format 0x%X (%d). File a bug about adding it to GTK", internal_format, internal_format);
/* fallback to the dumbest possible format
* so that even age old GLES can do it */
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
gl_format = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
}
stride = gdk_memory_format_bytes_per_pixel (format) * texture->width;
data = g_malloc (stride * texture->height);
glGetTexImage (GL_TEXTURE_2D,
0,
gl_format,
gl_type,
data);
bytes = g_bytes_new_take (data, stride * texture->height);
*result = gdk_memory_texture_new (texture->width,
texture->height,
format,
bytes,
stride);
g_bytes_unref (bytes);
}
static GdkTexture *
gdk_gl_texture_download_texture (GdkTexture *texture)
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
cairo_surface_t *surface;
cairo_t *cr;
GdkTexture *result;
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
area->width, area->height,
stride);
if (self->saved)
return g_object_ref (self->saved);
cr = cairo_create (surface);
gdk_gl_texture_run (self, gdk_gl_texture_do_download_texture, &result);
return result;
}
static void
gdk_gl_texture_do_download (gpointer texture,
gpointer data)
{
glGetTexImage (GL_TEXTURE_2D,
0,
GL_BGRA,
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
GL_UNSIGNED_INT_8_8_8_8_REV,
#elif G_BYTE_ORDER == G_BIG_ENDIAN
GL_UNSIGNED_BYTE,
#else
#error "Unknown byte order for gdk_gl_texture_download()"
#endif
data);
}
static void
gdk_gl_texture_download (GdkTexture *texture,
guchar *data,
gsize stride)
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
if (self->saved)
{
cairo_set_source_surface (cr, self->saved, 0, 0);
cairo_paint (cr);
gdk_texture_download (self->saved, data, stride);
return;
}
else
if (gdk_gl_context_get_use_es (self->context) ||
stride != texture->width * 4)
{
GdkSurface *gl_surface;
gl_surface = gdk_gl_context_get_surface (self->context);
gdk_cairo_draw_from_gl (cr, gl_surface, self->id, GL_TEXTURE, 1,
area->x, area->y,
area->width, area->height);
GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download (texture, data, stride);
return;
}
cairo_destroy (cr);
cairo_surface_finish (surface);
cairo_surface_destroy (surface);
gdk_gl_texture_run (self, gdk_gl_texture_do_download, data);
}
static void
gdk_gl_texture_do_download_float (gpointer texture,
gpointer data)
{
glGetTexImage (GL_TEXTURE_2D,
0,
GL_RGBA,
GL_FLOAT,
data);
}
static void
gdk_gl_texture_download_float (GdkTexture *texture,
float *data,
gsize stride)
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
int width, height, y;
float *copy;
if (self->saved)
{
gdk_texture_download_float (self->saved, data, stride);
return;
}
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
if (stride == width * 4)
{
gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, data);
return;
}
copy = g_new (float, width * height * 4);
gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, copy);
for (y = 0; y < height; y++)
memcpy (data + y * stride, copy + y * 4 * width, 4 * width);
g_free (copy);
}
static void
@@ -116,7 +306,9 @@ gdk_gl_texture_class_init (GdkGLTextureClass *klass)
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
texture_class->download_texture = gdk_gl_texture_download_texture;
texture_class->download = gdk_gl_texture_download;
texture_class->download_float = gdk_gl_texture_download_float;
gobject_class->dispose = gdk_gl_texture_dispose;
}
@@ -150,24 +342,10 @@ gdk_gl_texture_get_id (GdkGLTexture *self)
void
gdk_gl_texture_release (GdkGLTexture *self)
{
GdkSurface *surface;
GdkTexture *texture;
cairo_t *cr;
g_return_if_fail (GDK_IS_GL_TEXTURE (self));
g_return_if_fail (self->saved == NULL);
texture = GDK_TEXTURE (self);
self->saved = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
texture->width, texture->height);
cr = cairo_create (self->saved);
surface = gdk_gl_context_get_surface (self->context);
gdk_cairo_draw_from_gl (cr, surface, self->id, GL_TEXTURE, 1, 0, 0,
texture->width, texture->height);
cairo_destroy (cr);
self->saved = gdk_texture_download_texture (GDK_TEXTURE (self));
if (self->destroy)
{
+21 -21
View File
@@ -17,12 +17,12 @@
#include "config.h"
#include "gtkhslaprivate.h"
#include "gdkhslaprivate.h"
#include <math.h>
void
_gtk_hsla_init_from_rgba (GtkHSLA *hsla,
_gdk_hsla_init_from_rgba (GdkHSLA *hsla,
const GdkRGBA *rgba)
{
float min;
@@ -31,21 +31,21 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla,
float green;
float blue;
float delta;
g_return_if_fail (hsla != NULL);
g_return_if_fail (rgba != NULL);
red = rgba->red;
green = rgba->green;
blue = rgba->blue;
if (red > green)
{
if (red > blue)
max = red;
else
max = blue;
if (green < blue)
min = green;
else
@@ -57,25 +57,25 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla,
max = green;
else
max = blue;
if (red < blue)
min = red;
else
min = blue;
}
hsla->lightness = (max + min) / 2;
hsla->saturation = 0;
hsla->hue = 0;
hsla->alpha = rgba->alpha;
if (max != min)
{
if (hsla->lightness <= 0.5)
hsla->saturation = (max - min) / (max + min);
else
hsla->saturation = (max - min) / (2 - max - min);
delta = max -min;
if (red == max)
hsla->hue = (green - blue) / delta;
@@ -83,7 +83,7 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla,
hsla->hue = 2 + (blue - red) / delta;
else if (blue == max)
hsla->hue = 4 + (red - green) / delta;
hsla->hue *= 60;
if (hsla->hue < 0.0)
hsla->hue += 360;
@@ -92,22 +92,22 @@ _gtk_hsla_init_from_rgba (GtkHSLA *hsla,
void
_gdk_rgba_init_from_hsla (GdkRGBA *rgba,
const GtkHSLA *hsla)
const GdkHSLA *hsla)
{
float hue;
float lightness;
float saturation;
float m1, m2;
lightness = hsla->lightness;
saturation = hsla->saturation;
if (lightness <= 0.5)
m2 = lightness * (1 + saturation);
else
m2 = lightness + saturation - lightness * saturation;
m1 = 2 * lightness - m2;
rgba->alpha = hsla->alpha;
if (saturation == 0)
@@ -123,7 +123,7 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba,
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->red = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
@@ -132,13 +132,13 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba,
rgba->red = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->red = m1;
hue = hsla->hue;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->green = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
@@ -147,13 +147,13 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba,
rgba->green = m1 + (m2 - m1) * (240 - hue) / 60;
else
rgba->green = m1;
hue = hsla->hue - 120;
while (hue > 360)
hue -= 360;
while (hue < 0)
hue += 360;
if (hue < 60)
rgba->blue = m1 + (m2 - m1) * hue / 60;
else if (hue < 180)
@@ -166,8 +166,8 @@ _gdk_rgba_init_from_hsla (GdkRGBA *rgba,
}
void
_gtk_hsla_shade (GtkHSLA *dest,
const GtkHSLA *src,
_gdk_hsla_shade (GdkHSLA *dest,
const GdkHSLA *src,
float factor)
{
g_return_if_fail (dest != NULL);
@@ -22,23 +22,23 @@
G_BEGIN_DECLS
typedef struct _GtkHSLA GtkHSLA;
typedef struct _GdkHSLA GdkHSLA;
struct _GtkHSLA {
struct _GdkHSLA {
float hue;
float saturation;
float lightness;
float alpha;
};
void _gtk_hsla_init_from_rgba (GtkHSLA *hsla,
void _gdk_hsla_init_from_rgba (GdkHSLA *hsla,
const GdkRGBA *rgba);
/* Yes, I can name that function like this! */
void _gdk_rgba_init_from_hsla (GdkRGBA *rgba,
const GtkHSLA *hsla);
const GdkHSLA *hsla);
void _gtk_hsla_shade (GtkHSLA *dest,
const GtkHSLA *src,
void _gdk_hsla_shade (GdkHSLA *dest,
const GdkHSLA *src,
float factor);
G_END_DECLS
+410 -23
View File
@@ -20,6 +20,7 @@
#include "config.h"
#include "gdkmemorytextureprivate.h"
#include "gsk/ngl/fp16private.h"
/**
* GdkMemoryTexture:
@@ -49,6 +50,10 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
return 3;
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
@@ -58,9 +63,19 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
case GDK_MEMORY_A8B8G8R8:
return 4;
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
return 3;
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16_FLOAT:
return 6;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return 8;
case GDK_MEMORY_R32G32B32_FLOAT:
return 12;
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
return 16;
case GDK_MEMORY_N_FORMATS:
default:
@@ -69,6 +84,41 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
}
}
static gsize
gdk_memory_format_alignment (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
return G_ALIGNOF (guchar);
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16_FLOAT:
return G_ALIGNOF (guint16);
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return G_ALIGNOF (guint16);
case GDK_MEMORY_R32G32B32_FLOAT:
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
return G_ALIGNOF (float);
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
return G_ALIGNOF (double);
}
}
static void
gdk_memory_texture_dispose (GObject *object)
{
@@ -79,22 +129,41 @@ gdk_memory_texture_dispose (GObject *object)
G_OBJECT_CLASS (gdk_memory_texture_parent_class)->dispose (object);
}
static GdkTexture *
gdk_memory_texture_download_texture (GdkTexture *texture)
{
return g_object_ref (texture);
}
static void
gdk_memory_texture_download (GdkTexture *texture,
const GdkRectangle *area,
guchar *data,
gsize stride)
gdk_memory_texture_download (GdkTexture *texture,
guchar *data,
gsize stride)
{
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
gdk_memory_convert (data, stride,
GDK_MEMORY_CAIRO_FORMAT_ARGB32,
(guchar *) g_bytes_get_data (self->bytes, NULL)
+ area->x * gdk_memory_format_bytes_per_pixel (self->format)
+ area->y * self->stride,
GDK_MEMORY_CONVERT_DOWNLOAD,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
self->format,
area->width, area->height);
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
static void
gdk_memory_texture_download_float (GdkTexture *texture,
float *data,
gsize stride)
{
GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
gdk_memory_convert_to_float (data, stride,
(guchar *) g_bytes_get_data (self->bytes, NULL),
self->stride,
self->format,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
}
static void
@@ -103,7 +172,9 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
texture_class->download_texture = gdk_memory_texture_download_texture;
texture_class->download = gdk_memory_texture_download;
texture_class->download_float = gdk_memory_texture_download_float;
gobject_class->dispose = gdk_memory_texture_dispose;
}
@@ -112,6 +183,41 @@ gdk_memory_texture_init (GdkMemoryTexture *self)
{
}
static GBytes *
gdk_memory_sanitize (GBytes *bytes,
int width,
int height,
GdkMemoryFormat format,
gsize stride,
gsize *out_stride)
{
gsize align, size, copy_stride, bpp;
const guchar *data;
guchar *copy;
int y;
data = g_bytes_get_data (bytes, &size);
align = gdk_memory_format_alignment (format);
if (GPOINTER_TO_SIZE (data) % align == 0 &&
stride % align == 0)
{
*out_stride = stride;
return g_bytes_ref (bytes);
}
bpp = gdk_memory_format_bytes_per_pixel (format);
copy_stride = bpp * width;
/* align to multiples of 4, just to be sure */
copy_stride = (copy_stride + 3) & ~3;
copy = g_malloc (copy_stride * height);
for (y = 0; y < height; y++)
memcpy (copy + y * copy_stride, data + y * stride, bpp * width);
*out_stride = copy_stride;
return g_bytes_new_take (copy, copy_stride * height);
}
/**
* gdk_memory_texture_new:
* @width: the width of the texture
@@ -136,13 +242,20 @@ gdk_memory_texture_new (int width,
{
GdkMemoryTexture *self;
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL);
bytes = gdk_memory_sanitize (bytes, width, height, format, stride, &stride);
self = g_object_new (GDK_TYPE_MEMORY_TEXTURE,
"width", width,
"height", height,
NULL);
self->format = format;
self->bytes = g_bytes_ref (bytes);
self->bytes = bytes;
self->stride = stride;
return GDK_TEXTURE (self);
@@ -283,6 +396,109 @@ SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3)
SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2)
SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1)
#define CONVERT_FUNC(name,suffix,R,G,B,A,step) \
static void \
convert_ ## name ## _to_ ## suffix (guchar *dest_data, \
gsize dest_stride, \
const guchar *src_data, \
gsize src_stride, \
gsize width, \
gsize height) \
{ \
gsize x, y; \
\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
guchar conv[4]; \
convert_pixel_ ## name (conv, src_data + step * x); \
dest_data[4 * x + R] = conv[0]; \
dest_data[4 * x + G] = conv[1]; \
dest_data[4 * x + B] = conv[2]; \
dest_data[4 * x + A] = conv[3]; \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}
#define CONVERT_FUNCS(name,step) \
CONVERT_FUNC(name, download_le, 2, 1, 0, 3, step) \
CONVERT_FUNC(name, download_be, 1, 2, 3, 0, step) \
CONVERT_FUNC(name, gles_rgba, 0, 1, 2, 3, step) \
static inline void
convert_pixel_rgb16 (guchar *dest_data, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest_data[0] = (guchar)(src[0] >> 8);
dest_data[1] = (guchar)(src[1] >> 8);
dest_data[2] = (guchar)(src[2] >> 8);
dest_data[3] = 0xFF;
}
CONVERT_FUNCS(rgb16, 3 * sizeof (guint16))
static inline void
convert_pixel_rgba16 (guchar *dest_data, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest_data[0] = (guchar)(src[0] >> 8);
dest_data[1] = (guchar)(src[1] >> 8);
dest_data[2] = (guchar)(src[2] >> 8);
dest_data[3] = (guchar)(src[3] >> 8);
}
CONVERT_FUNCS(rgba16, 4 * sizeof (guint16))
static inline void
convert_pixel_rgb16f (guchar *dest_data, const guchar *src_data)
{
float src[4];
guint16 tmp[4];
memcpy(tmp, src_data, sizeof(guint16) * 3);
half_to_float4(tmp, src);
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = 0xFF;
}
CONVERT_FUNCS(rgb16f, 3 * sizeof (guint16))
static inline void
convert_pixel_rgba16f (guchar *dest_data, const guchar *src_data)
{
float src[4];
half_to_float4((const guint16 *) src_data, src);
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
}
CONVERT_FUNCS(rgba16f, 4 * sizeof (guint16))
static inline void
convert_pixel_rgb32f (guchar *dest_data, const guchar *src_data)
{
float *src = (float *) src_data;
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = 0xFF;
}
CONVERT_FUNCS(rgb32f, 3 * sizeof (float))
static inline void
convert_pixel_rgba32f (guchar *dest_data, const guchar *src_data)
{
float *src = (float *) src_data;
dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f);
dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f);
dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f);
dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f);
}
CONVERT_FUNCS(rgba32f, 4 * sizeof (float))
typedef void (* ConversionFunc) (guchar *dest_data,
gsize dest_stride,
const guchar *src_data,
@@ -290,7 +506,7 @@ typedef void (* ConversionFunc) (guchar *dest_data,
gsize width,
gsize height);
static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] =
static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] =
{
{ convert_memcpy, convert_swizzle3210, convert_swizzle2103 },
{ convert_swizzle3210, convert_memcpy, convert_swizzle3012 },
@@ -300,21 +516,192 @@ static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] =
{ convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 },
{ convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 },
{ convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 },
{ convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 }
{ convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 },
{ convert_rgb16_to_download_le, convert_rgb16_to_download_be, convert_rgb16_to_gles_rgba },
{ convert_rgba16_to_download_le, convert_rgba16_to_download_be, convert_rgba16_to_gles_rgba },
{ convert_rgb16f_to_download_le, convert_rgb16f_to_download_be, convert_rgb16f_to_gles_rgba },
{ convert_rgba16f_to_download_le, convert_rgba16f_to_download_be, convert_rgba16f_to_gles_rgba },
{ convert_rgb32f_to_download_le, convert_rgb32f_to_download_be, convert_rgb32f_to_gles_rgba },
{ convert_rgba32f_to_download_le, convert_rgba32f_to_download_be, convert_rgba32f_to_gles_rgba }
};
void
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height)
gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryConversion dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height)
{
g_assert (dest_format < 3);
g_assert (src_format < GDK_MEMORY_N_FORMATS);
converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);
}
#define CONVERT_FLOAT(R,G,B,A,premultiply) G_STMT_START {\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
if (A >= 0) \
{ \
dest_data[4 * x + 0] = src_data[4 * x + R] / 255.0f; \
dest_data[4 * x + 1] = src_data[4 * x + G] / 255.0f; \
dest_data[4 * x + 2] = src_data[4 * x + B] / 255.0f; \
dest_data[4 * x + 3] = src_data[4 * x + A] / 255.0f; \
if (premultiply) \
{ \
dest_data[4 * x + 0] *= dest_data[4 * x + 3]; \
dest_data[4 * x + 1] *= dest_data[4 * x + 3]; \
dest_data[4 * x + 2] *= dest_data[4 * x + 3]; \
} \
} \
else \
{ \
dest_data[4 * x + 0] = src_data[3 * x + R] / 255.0f; \
dest_data[4 * x + 1] = src_data[3 * x + G] / 255.0f; \
dest_data[4 * x + 2] = src_data[3 * x + B] / 255.0f; \
dest_data[4 * x + 3] = 1.0; \
} \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}G_STMT_END
#define CONVERT_FLOAT_PIXEL(func,step) G_STMT_START{\
for (y = 0; y < height; y++) \
{ \
for (x = 0; x < width; x++) \
{ \
func (dest_data + 4 * x, src_data + step * x); \
} \
\
dest_data += dest_stride; \
src_data += src_stride; \
} \
}G_STMT_END
static inline void
convert_rgb16_to_float (float *dest, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest[0] = src[0] / 65535.f;
dest[1] = src[1] / 65535.f;
dest[2] = src[2] / 65535.f;
dest[3] = 1.0;
}
static inline void
convert_rgba16_to_float (float *dest, const guchar *src_data)
{
const guint16 *src = (const guint16 *) src_data;
dest[0] = src[0] / 65535.f;
dest[1] = src[1] / 65535.f;
dest[2] = src[2] / 65535.f;
dest[3] = 1.0;
}
static inline void
convert_rgb16f_to_float (float *dest, const guchar *src_data)
{
guint16 tmp[4];
memcpy(tmp, src_data, sizeof(guint16) * 3);
tmp[3] = FP16_ONE;
half_to_float4 (tmp, dest);
}
static inline void
convert_rgba16f_to_float (float *dest, const guchar *src_data)
{
half_to_float4 ((const guint16 *) src_data, dest);
}
static inline void
convert_rgb32f_to_float (float *dest, const guchar *src_data)
{
const float *src = (const float *) src_data;
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = 1.0;
}
static inline void
convert_rgba32f_to_float (float *dest, const guchar *src_data)
{
const float *src = (const float *) src_data;
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
}
void
gdk_memory_convert_to_float (float *dest_data,
gsize dest_stride,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height)
{
gsize x, y;
switch (src_format)
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
CONVERT_FLOAT (2, 1, 0, 3, FALSE);
break;
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
CONVERT_FLOAT (1, 2, 3, 0, FALSE);
break;
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
CONVERT_FLOAT (0, 1, 2, 3, FALSE);
break;
case GDK_MEMORY_B8G8R8A8:
CONVERT_FLOAT (2, 1, 0, 3, TRUE);
break;
case GDK_MEMORY_A8R8G8B8:
CONVERT_FLOAT (1, 2, 3, 0, TRUE);
break;
case GDK_MEMORY_R8G8B8A8:
CONVERT_FLOAT (0, 1, 2, 3, TRUE);
break;
case GDK_MEMORY_A8B8G8R8:
CONVERT_FLOAT (3, 2, 1, 0, TRUE);
break;
case GDK_MEMORY_R8G8B8:
CONVERT_FLOAT (0, 1, 2, -1, FALSE);
break;
case GDK_MEMORY_B8G8R8:
CONVERT_FLOAT (2, 1, 0, -1, FALSE);
break;
case GDK_MEMORY_R16G16B16:
CONVERT_FLOAT_PIXEL (convert_rgb16_to_float, 3 * sizeof (guint16));
break;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
CONVERT_FLOAT_PIXEL (convert_rgba16_to_float, 4 * sizeof (guint16));
break;
case GDK_MEMORY_R16G16B16_FLOAT:
CONVERT_FLOAT_PIXEL (convert_rgb16f_to_float, 3 * sizeof (guint16));
break;
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
CONVERT_FLOAT_PIXEL (convert_rgba16f_to_float, 4 * sizeof (guint16));
break;
case GDK_MEMORY_R32G32B32_FLOAT:
CONVERT_FLOAT_PIXEL (convert_rgb32f_to_float, 3 * sizeof (float));
break;
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
CONVERT_FLOAT_PIXEL (convert_rgba32f_to_float, 4 * sizeof (float));
break;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached();
}
}
+20
View File
@@ -42,6 +42,20 @@ G_BEGIN_DECLS
* @GDK_MEMORY_A8B8G8R8: 4 bytes; for alpha, blue, green, red.
* @GDK_MEMORY_R8G8B8: 3 bytes; for red, green, blue. The data is opaque.
* @GDK_MEMORY_B8G8R8: 3 bytes; for blue, green, red. The data is opaque.
* @GDK_MEMORY_R16G16B16: 3 guint16 values; for red, green, blue. Since 4.6
* @GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: 4 guint16 values; for red, green,
* blue, alpha. The color values are premultiplied with the alpha value.
* Since 4.6
* @GDK_MEMORY_R16G16B16_FLOAT: 3 half-float values; for red, green, blue.
* The data is opaque. Since 4.6
* @GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: 4 half-float values; for
* red, green, blue and alpha. The color values are premultiplied with
* the alpha value. Since 4.6
* @GDK_MEMORY_B32G32R32_FLOAT: 3 float values; for blue, green, red.
* The data is opaque. Since 4.6
* @GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: 4 float values; for
* red, green, blue and alpha. The color values are premultiplied with
* the alpha value. Since 4.6
* @GDK_MEMORY_N_FORMATS: The number of formats. This value will change as
* more formats get added, so do not rely on its concrete integer.
*
@@ -67,6 +81,12 @@ typedef enum {
GDK_MEMORY_A8B8G8R8,
GDK_MEMORY_R8G8B8,
GDK_MEMORY_B8G8R8,
GDK_MEMORY_R16G16B16,
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED,
GDK_MEMORY_R16G16B16_FLOAT,
GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED,
GDK_MEMORY_R32G32B32_FLOAT,
GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED,
GDK_MEMORY_N_FORMATS
} GdkMemoryFormat;
+31 -9
View File
@@ -29,7 +29,21 @@ G_BEGIN_DECLS
#define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8
#define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8
#define GDK_MEMORY_CAIRO_FORMAT_ARGB32 GDK_MEMORY_DEFAULT
typedef enum {
GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN,
GDK_MEMORY_CONVERT_DOWNLOAD_BIT_ENDIAN,
GDK_MEMORY_CONVERT_GLES_RGBA,
GDK_MEMORY_N_CONVERSIONS
} GdkMemoryConversion;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN
#elif G_BYTE_ORDER == G_BIG_ENDIAN
#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_BIG_ENDIAN
#else
#error "Unknown byte order for GDK_MEMORY_CONVERT_DOWNLOAD"
#endif
gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format);
@@ -37,14 +51,22 @@ GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture *
const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self);
gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self);
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryFormat dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height);
void gdk_memory_convert (guchar *dest_data,
gsize dest_stride,
GdkMemoryConversion dest_format,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height);
void gdk_memory_convert_to_float (float *dest_data,
gsize dest_stride,
const guchar *src_data,
gsize src_stride,
GdkMemoryFormat src_format,
gsize width,
gsize height);
G_END_DECLS
+86 -4
View File
@@ -30,6 +30,7 @@
#include <errno.h>
#include <math.h>
#include "gdkhslaprivate.h"
G_DEFINE_BOXED_TYPE (GdkRGBA, gdk_rgba,
gdk_rgba_copy, gdk_rgba_free)
@@ -186,6 +187,7 @@ gdk_rgba_parse (GdkRGBA *rgba,
const char *spec)
{
gboolean has_alpha;
gboolean is_hsl;
double r, g, b, a;
char *str = (char *) spec;
char *p;
@@ -196,11 +198,26 @@ gdk_rgba_parse (GdkRGBA *rgba,
if (strncmp (str, "rgba", 4) == 0)
{
has_alpha = TRUE;
is_hsl = FALSE;
str += 4;
}
else if (strncmp (str, "rgb", 3) == 0)
{
has_alpha = FALSE;
is_hsl = FALSE;
a = 1;
str += 3;
}
else if (strncmp (str, "hsla", 4) == 0)
{
has_alpha = TRUE;
is_hsl = TRUE;
str += 4;
}
else if (strncmp (str, "hsl", 3) == 0)
{
has_alpha = FALSE;
is_hsl = TRUE;
a = 1;
str += 3;
}
@@ -291,10 +308,22 @@ gdk_rgba_parse (GdkRGBA *rgba,
if (rgba)
{
rgba->red = CLAMP (r, 0, 1);
rgba->green = CLAMP (g, 0, 1);
rgba->blue = CLAMP (b, 0, 1);
rgba->alpha = CLAMP (a, 0, 1);
if (is_hsl)
{
GdkHSLA hsla;
hsla.hue = r * 255;
hsla.saturation = CLAMP (g, 0, 1);
hsla.lightness = CLAMP (b, 0, 1);
hsla.alpha = CLAMP (a, 0, 1);
_gdk_rgba_init_from_hsla (rgba, &hsla);
}
else
{
rgba->red = CLAMP (r, 0, 1);
rgba->green = CLAMP (g, 0, 1);
rgba->blue = CLAMP (b, 0, 1);
rgba->alpha = CLAMP (a, 0, 1);
}
}
return TRUE;
@@ -462,6 +491,47 @@ parse_color_channel (GtkCssParser *parser,
}
}
static guint
parse_hsla_color_channel (GtkCssParser *parser,
guint arg,
gpointer data)
{
GdkHSLA *hsla = data;
double dvalue;
switch (arg)
{
case 0:
if (!gtk_css_parser_consume_number (parser, &dvalue))
return 0;
hsla->hue = dvalue;
return 1;
case 1:
if (!gtk_css_parser_consume_percentage (parser, &dvalue))
return 0;
hsla->saturation = CLAMP (dvalue, 0.0, 100.0) / 100.0;
return 1;
case 2:
if (!gtk_css_parser_consume_percentage (parser, &dvalue))
return 0;
hsla->lightness = CLAMP (dvalue, 0.0, 100.0) / 100.0;
return 1;
case 3:
if (!gtk_css_parser_consume_number (parser, &dvalue))
return 0;
hsla->alpha = CLAMP (dvalue, 0.0, 1.0) / 1.0;
return 1;
default:
g_assert_not_reached ();
return 0;
}
}
static gboolean
rgba_init_chars (GdkRGBA *rgba,
const char s[8])
@@ -501,6 +571,18 @@ gdk_rgba_parser_parse (GtkCssParser *parser,
{
return gtk_css_parser_consume_function (parser, 4, 4, parse_color_channel, rgba);
}
else if (gtk_css_token_is_function (token, "hsl") || gtk_css_token_is_function (token, "hsla"))
{
GdkHSLA hsla;
hsla.alpha = 1.0;
if (!gtk_css_parser_consume_function (parser, 3, 4, parse_hsla_color_channel, &hsla))
return FALSE;
_gdk_rgba_init_from_hsla (rgba, &hsla);
return TRUE;
}
else if (gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_ID) ||
gtk_css_token_is (token, GTK_CSS_TOKEN_HASH_UNRESTRICTED))
{
+266 -55
View File
@@ -46,6 +46,11 @@
#include "gdksnapshot.h"
#include <graphene.h>
#include "loaders/gdkpngprivate.h"
#include "loaders/gdktiffprivate.h"
#include "loaders/gdkjpegprivate.h"
G_DEFINE_QUARK (gdk-texture-error-quark, gdk_texture_error)
/* HACK: So we don't need to include any (not-yet-created) GSK or GTK headers */
void
@@ -115,13 +120,35 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
#define GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
g_critical ("Texture of type '%s' does not implement GdkTexture::" # method, G_OBJECT_TYPE_NAME (obj))
static void
gdk_texture_real_download (GdkTexture *self,
const GdkRectangle *area,
guchar *data,
gsize stride)
static GdkTexture *
gdk_texture_real_download_texture (GdkTexture *self)
{
GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download);
GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download_texture);
return NULL;
}
static void
gdk_texture_real_download (GdkTexture *texture,
guchar *data,
gsize stride)
{
GdkTexture *memory_texture;
memory_texture = gdk_texture_download_texture (texture);
gdk_texture_download (memory_texture, data, stride);
g_object_unref (memory_texture);
}
static void
gdk_texture_real_download_float (GdkTexture *self,
float *data,
gsize stride)
{
GdkTexture *memory_texture;
memory_texture = gdk_texture_download_texture (self);
gdk_texture_download_float (memory_texture, data, stride);
g_object_unref (memory_texture);
}
static void
@@ -187,7 +214,9 @@ gdk_texture_class_init (GdkTextureClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
klass->download_texture = gdk_texture_real_download_texture;
klass->download = gdk_texture_real_download;
klass->download_float = gdk_texture_real_download_float;
gobject_class->set_property = gdk_texture_set_property;
gobject_class->get_property = gdk_texture_get_property;
@@ -263,7 +292,7 @@ gdk_texture_new_for_surface (cairo_surface_t *surface)
texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface),
cairo_image_surface_get_height (surface),
GDK_MEMORY_CAIRO_FORMAT_ARGB32,
GDK_MEMORY_DEFAULT,
bytes,
cairo_image_surface_get_stride (surface));
@@ -359,28 +388,92 @@ GdkTexture *
gdk_texture_new_from_file (GFile *file,
GError **error)
{
GBytes *bytes;
GdkTexture *texture;
GdkPixbuf *pixbuf;
GInputStream *stream;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
stream = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (stream == NULL)
bytes = g_file_load_bytes (file, NULL, NULL, error);
if (bytes == NULL)
return NULL;
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
g_object_unref (stream);
if (pixbuf == NULL)
return NULL;
texture = gdk_texture_new_from_bytes (bytes, error);
texture = gdk_texture_new_for_pixbuf (pixbuf);
g_object_unref (pixbuf);
g_bytes_unref (bytes);
return texture;
}
/**
* gdk_texture_new_from_bytes:
* @bytes: a `GBytes` containing the data to load
* @error: Return location for an error
*
* Creates a new texture by loading an image from memory,
*
* The file format is detected automatically. The supported formats
* are PNG and JPEG, though more formats might be available.
*
* If %NULL is returned, then @error will be set.
*
* Return value: A newly-created `GdkTexture`
*
* Since: 4.6
*/
GdkTexture *
gdk_texture_new_from_bytes (GBytes *bytes,
GError **error)
{
const char *data;
gsize size;
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
data = g_bytes_get_data (bytes, &size);
if (size > strlen (PNG_SIGNATURE) &&
memcmp (data, PNG_SIGNATURE, strlen (PNG_SIGNATURE)) == 0)
{
return gdk_load_png (bytes, error);
}
else if ((size > strlen (TIFF_SIGNATURE1) &&
memcmp (data, TIFF_SIGNATURE1, strlen (TIFF_SIGNATURE1)) == 0) ||
(size > strlen (TIFF_SIGNATURE2) &&
memcmp (data, TIFF_SIGNATURE2, strlen (TIFF_SIGNATURE2)) == 0))
{
return gdk_load_tiff (bytes, error);
}
else if (size > strlen (JPEG_SIGNATURE) &&
memcmp (data, JPEG_SIGNATURE, strlen (JPEG_SIGNATURE)) == 0)
{
return gdk_load_jpeg (bytes, error);
}
else
{
GInputStream *stream;
GdkPixbuf *pixbuf;
stream = g_memory_input_stream_new_from_bytes (bytes);
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
g_object_unref (stream);
if (pixbuf)
{
GdkTexture *texture;
texture = gdk_texture_new_for_pixbuf (pixbuf);
g_object_unref (pixbuf);
return texture;
}
}
return NULL;
}
/**
* gdk_texture_get_width: (attributes org.gtk.Method.get_property=width)
* @texture: a `GdkTexture`
@@ -435,20 +528,6 @@ gdk_texture_download_surface (GdkTexture *texture)
return surface;
}
void
gdk_texture_download_area (GdkTexture *texture,
const GdkRectangle *area,
guchar *data,
gsize stride)
{
g_assert (area->x >= 0);
g_assert (area->y >= 0);
g_assert (area->x + area->width <= texture->width);
g_assert (area->y + area->height <= texture->height);
GDK_TEXTURE_GET_CLASS (texture)->download (texture, area, data, stride);
}
/**
* gdk_texture_download:
* @texture: a `GdkTexture`
@@ -485,10 +564,62 @@ gdk_texture_download (GdkTexture *texture,
g_return_if_fail (data != NULL);
g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
gdk_texture_download_area (texture,
&(GdkRectangle) { 0, 0, texture->width, texture->height },
data,
stride);
GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride);
}
/**
* gdk_texture_download_float:
* @texture: a `GdkTexture`
* @data: (array): pointer to enough memory to be filled with the
* downloaded data of @texture
* @stride: rowstride in elements, will usually be equal to
* gdk_texture_get_width() * 4
*
* Downloads the @texture into local memory in a high dynamic range format.
*
* This may be an expensive operation, as the actual texture data
* may reside on a GPU or on a remote display server and because the data
* may need to be upsampled if it was not already available in this
* format.
*
* You may want to use [method@Gdk.Texture.download] instead if you don't
* need high dynamic range support.
*
* The data format of the downloaded data is equivalent to
* GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, so every downloaded
* pixel requires 16 bytes of memory.
*
* Note that the caller is responsible to provide sufficiently
* aligned memory to access the resulting data directly as floats.
*
* Since: 4.6
*/
void
gdk_texture_download_float (GdkTexture *texture,
float *data,
gsize stride)
{
g_return_if_fail (GDK_IS_TEXTURE (texture));
g_return_if_fail (data != NULL);
g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
GDK_TEXTURE_GET_CLASS (texture)->download_float (texture, data, stride);
}
GdkTexture *
gdk_texture_download_texture (GdkTexture *texture)
{
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
g_object_ref (texture);
while (!GDK_IS_MEMORY_TEXTURE (texture))
{
GdkTexture *downloaded = GDK_TEXTURE_GET_CLASS (texture)->download_texture (texture);
g_object_unref (texture);
texture = downloaded;
}
return texture;
}
gboolean
@@ -540,7 +671,8 @@ gdk_texture_get_render_data (GdkTexture *self,
* This is a utility function intended for debugging and testing.
* If you want more control over formats, proper error handling or
* want to store to a `GFile` or other location, you might want to
* look into using the gdk-pixbuf library.
* use gdk_texture_save_to_png_bytes() or look into the
* gdk-pixbuf library.
*
* Returns: %TRUE if saving succeeded, %FALSE on failure.
*/
@@ -548,30 +680,109 @@ gboolean
gdk_texture_save_to_png (GdkTexture *texture,
const char *filename)
{
cairo_surface_t *surface;
cairo_status_t status;
GBytes *bytes;
gboolean result;
g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
gdk_texture_download (texture,
cairo_image_surface_get_data (surface),
cairo_image_surface_get_stride (surface));
cairo_surface_mark_dirty (surface);
status = cairo_surface_write_to_png (surface, filename);
if (status != CAIRO_STATUS_SUCCESS ||
cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
result = FALSE;
else
result = TRUE;
cairo_surface_destroy (surface);
bytes = gdk_save_png (texture);
result = g_file_set_contents (filename,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes),
NULL);
g_bytes_unref (bytes);
return result;
}
/**
* gdk_texture_save_to_png_bytes:
* @texture: a `GdkTexture`
*
* Store the given @texture in memory as a PNG file.
* Use gdk_texture_new_from_bytes() to read it back.
*
* If you want to serialize a texture, this is a convenient and
* portable way to do that.
*
* If you need more control over the generated image, such as
* attaching metadata, you should look into an image handling
* library such as the gdk-pixbuf library.
*
* If you are dealing with high dynamic range float data, you
* might also want to consider gdk_texture_save_to_tiff_bytes()
* instead.
*
* Returns: a newly allocated `GBytes` containing PNG data
*
* Since: 4.6
*/
GBytes *
gdk_texture_save_to_png_bytes (GdkTexture *texture)
{
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
return gdk_save_png (texture);
}
/**
* gdk_texture_save_to_tiff:
* @texture: a `GdkTexture`
* @filename: (type filename): the filename to store to
*
* Store the given @texture to the @filename as a TIFF file.
*
* GTK will attempt to store data without loss.
* Returns: %TRUE if saving succeeded, %FALSE on failure.
*
* Since: 4.6
*/
gboolean
gdk_texture_save_to_tiff (GdkTexture *texture,
const char *filename)
{
GBytes *bytes;
gboolean result;
g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE);
g_return_val_if_fail (filename != NULL, FALSE);
bytes = gdk_save_tiff (texture);
result = g_file_set_contents (filename,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes),
NULL);
g_bytes_unref (bytes);
return result;
}
/**
* gdk_texture_save_to_tiff_bytes:
* @texture: a `GdkTexture`
*
* Store the given @texture in memory as a TIFF file.
* Use gdk_texture_new_from_bytes() to read it back.
*
* This function is intended to store a representation of the
* texture's data that is as accurate as possible. This is
* particularly relevant when working with high dynamic range
* images and floating-point texture data.
*
* If that is not your concern and you are interested in a
* smaller size and a more portable format, you might want to
* use gdk_texture_save_to_png_bytes().
*
* Returns: a newly allocated `GBytes` containing TIFF data
*
* Since: 4.6
*/
GBytes *
gdk_texture_save_to_tiff_bytes (GdkTexture *texture)
{
g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
return gdk_save_tiff (texture);
}
+33
View File
@@ -38,6 +38,25 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GdkTexture, g_object_unref)
typedef struct _GdkTextureClass GdkTextureClass;
#define GDK_TEXTURE_ERROR (gdk_texture_error_quark ())
GDK_AVAILABLE_IN_4_6
GQuark gdk_texture_error_quark (void);
/**
* GdkTextureError:
* @GDK_TEXTURE_ERROR_INSUFFICIENT_MEMORY: Not enough memory to handle this image
* @GDK_TEXTURE_ERROR_CORRUPT_IMAGE: The image data appears corrupted
* @GDK_TEXTURE_ERROR_UNSUPPORTED: The image format is not supported
*
* Possible errors that can be returned by `GdkTexture` constructors.
*/
typedef enum
{
GDK_TEXTURE_ERROR_INSUFFICIENT_MEMORY,
GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
GDK_TEXTURE_ERROR_UNSUPPORTED,
} GdkTextureError;
GDK_AVAILABLE_IN_ALL
GType gdk_texture_get_type (void) G_GNUC_CONST;
@@ -49,6 +68,9 @@ GdkTexture * gdk_texture_new_from_resource (const char
GDK_AVAILABLE_IN_ALL
GdkTexture * gdk_texture_new_from_file (GFile *file,
GError **error);
GDK_AVAILABLE_IN_4_6
GdkTexture * gdk_texture_new_from_bytes (GBytes *bytes,
GError **error);
GDK_AVAILABLE_IN_ALL
int gdk_texture_get_width (GdkTexture *texture) G_GNUC_PURE;
@@ -59,9 +81,20 @@ GDK_AVAILABLE_IN_ALL
void gdk_texture_download (GdkTexture *texture,
guchar *data,
gsize stride);
GDK_AVAILABLE_IN_4_6
void gdk_texture_download_float (GdkTexture *texture,
float *data,
gsize stride);
GDK_AVAILABLE_IN_ALL
gboolean gdk_texture_save_to_png (GdkTexture *texture,
const char *filename);
GDK_AVAILABLE_IN_4_6
GBytes * gdk_texture_save_to_png_bytes (GdkTexture *texture);
GDK_AVAILABLE_IN_4_6
gboolean gdk_texture_save_to_tiff (GdkTexture *texture,
const char *filename);
GDK_AVAILABLE_IN_4_6
GBytes * gdk_texture_save_to_tiff_bytes (GdkTexture *texture);
G_END_DECLS
+8 -5
View File
@@ -24,10 +24,15 @@ struct _GdkTexture
struct _GdkTextureClass {
GObjectClass parent_class;
/* mandatory: Download into a GdkMemoryTexture */
GdkTexture * (* download_texture) (GdkTexture *texture);
/* optional */
void (* download) (GdkTexture *texture,
const GdkRectangle *area,
guchar *data,
gsize stride);
void (* download_float) (GdkTexture *texture,
float *data,
gsize stride);
};
gpointer gdk_texture_new (const GdkTextureClass *klass,
@@ -35,10 +40,8 @@ gpointer gdk_texture_new (const GdkTextureClass
int height);
GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface);
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture);
void gdk_texture_download_area (GdkTexture *texture,
const GdkRectangle *area,
guchar *data,
gsize stride);
/* NB: GdkMemoryTexture */
GdkTexture * gdk_texture_download_texture (GdkTexture *texture);
gboolean gdk_texture_set_render_data (GdkTexture *self,
gpointer key,
+146
View File
@@ -0,0 +1,146 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkjpegprivate.h"
#include "gdktexture.h"
#include "gdkmemorytextureprivate.h"
#include <jpeglib.h>
#include <jerror.h>
#include <setjmp.h>
/* {{{ Error handling */
/* No sigsetjmp on Windows */
#ifndef HAVE_SIGSETJMP
#define sigjmp_buf jmp_buf
#define sigsetjmp(jb, x) setjmp(jb)
#define siglongjmp longjmp
#endif
struct error_handler_data {
struct jpeg_error_mgr pub;
sigjmp_buf setjmp_buffer;
GError **error;
};
static void
fatal_error_handler (j_common_ptr cinfo)
{
struct error_handler_data *errmgr;
char buffer[JMSG_LENGTH_MAX];
errmgr = (struct error_handler_data *) cinfo->err;
cinfo->err->format_message (cinfo, buffer);
if (errmgr->error && *errmgr->error == NULL)
g_set_error (errmgr->error,
GDK_TEXTURE_ERROR,
cinfo->err->msg_code == JERR_OUT_OF_MEMORY
? GDK_TEXTURE_ERROR_INSUFFICIENT_MEMORY
: GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
"Error interpreting JPEG image file (%s)", buffer);
siglongjmp (errmgr->setjmp_buffer, 1);
g_assert_not_reached ();
}
static void
output_message_handler (j_common_ptr cinfo)
{
/* do nothing */
}
/* }}} */
/* {{{ Public API */
GdkTexture *
gdk_load_jpeg (GBytes *input_bytes,
GError **error)
{
struct jpeg_decompress_struct info;
struct error_handler_data jerr;
struct jpeg_error_mgr err;
int width, height;
int size;
unsigned char *data;
unsigned char *row[1];
GBytes *bytes;
GdkTexture *texture;
info.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = fatal_error_handler;
jerr.pub.output_message = output_message_handler;
jerr.error = error;
if (sigsetjmp (jerr.setjmp_buffer, 1))
{
jpeg_destroy_decompress (&info);
return NULL;
}
info.err = jpeg_std_error (&err);
jpeg_create_decompress (&info);
jpeg_mem_src (&info,
g_bytes_get_data (input_bytes, NULL),
g_bytes_get_size (input_bytes));
jpeg_read_header (&info, TRUE);
jpeg_start_decompress (&info);
width = info.output_width;
height = info.output_height;
size = width * height * 3;
data = g_try_malloc_n (width * 3, height);
if (!data)
{
g_set_error_literal (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_INSUFFICIENT_MEMORY,
"Not enough memory to load jpeg");
jpeg_destroy_decompress (&info);
return NULL;
}
while (info.output_scanline < info.output_height)
{
row[0] = (unsigned char *)(&data[3 *info.output_width * info.output_scanline]);
jpeg_read_scanlines (&info, row, 1);
}
jpeg_finish_decompress (&info);
jpeg_destroy_decompress (&info);
bytes = g_bytes_new_take (data, size);
texture = gdk_memory_texture_new (width, height,
GDK_MEMORY_R8G8B8,
bytes, width * 3);
g_bytes_unref (bytes);
return texture;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+29
View File
@@ -0,0 +1,29 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_JPEG_PRIVATE_H__
#define __GDK_JPEG_PRIVATE_H__
#include "gdkmemorytexture.h"
#include <gio/gio.h>
#define JPEG_SIGNATURE "\xff\xd8"
GdkTexture *gdk_load_jpeg (GBytes *bytes,
GError **error);
#endif
+242
View File
@@ -0,0 +1,242 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdkpngprivate.h"
#include "gdktexture.h"
#include "gdktextureprivate.h"
#include "gdkmemorytextureprivate.h"
#include "gsk/ngl/fp16private.h"
#include <png.h>
#include <stdio.h>
/* The main difference between the png load/save code here and
* gdk-pixbuf is that we can support loading 16-bit data in the
* future, and we can extract gamma and colorspace information
* to produce linear, color-corrected data.
*/
/* {{{ Format conversion */
static void
flip_02 (guchar *data,
int width,
int height,
int stride)
{
gsize x, y;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
guchar tmp;
tmp = data[x * 4];
data[x * 4] = data[x * 4 + 2];
data[x * 4 + 2] = tmp;
}
data += stride;
}
}
static void
convert_float_to_16bit_inplace (float *src,
int width,
int height)
{
gsize x, y;
guint16 *dest = (guint16 *)src;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
dest[4 * x ] = (guint16) CLAMP(65536.f * src[x * 4 ], 0.f, 65535.f);
dest[4 * x + 1] = (guint16) CLAMP(65536.f * src[x * 4 + 1], 0.f, 65535.f);
dest[4 * x + 2] = (guint16) CLAMP(65536.f * src[x * 4 + 2], 0.f, 65535.f);
dest[4 * x + 3] = (guint16) CLAMP(65536.f * src[x * 4 + 3], 0.f, 65535.f);
}
dest += width * 4;
src += width * 4;
}
}
/* }}} */
/* {{{ Public API */
GdkTexture *
gdk_load_png (GBytes *bytes,
GError **error)
{
png_image image = { NULL, PNG_IMAGE_VERSION, 0, };
gsize size;
gsize stride;
guchar *buffer;
GdkTexture *texture;
GBytes *out_bytes;
png_image_begin_read_from_memory (&image,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
if (PNG_IMAGE_FAILED (image))
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED,
"Failed to parse png image (%s)", image.message);
png_image_free (&image);
return NULL;
}
image.format = PNG_FORMAT_RGBA;
stride = PNG_IMAGE_ROW_STRIDE (image);
size = PNG_IMAGE_BUFFER_SIZE (image, stride);
buffer = g_try_malloc (size);
if (!buffer)
{
g_set_error_literal (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_INSUFFICIENT_MEMORY,
"Not enough memory to load png");
png_image_free (&image);
return NULL;
}
png_image_finish_read (&image, NULL, buffer, stride, NULL);
if (PNG_IMAGE_FAILED (image))
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED,
"Failed to parse png image (%s)", image.message);
png_image_free (&image);
return NULL;
}
if (image.format & PNG_FORMAT_FLAG_LINEAR)
stride *= 2;
out_bytes = g_bytes_new_take (buffer, size);
texture = gdk_memory_texture_new (image.width, image.height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
out_bytes, stride);
g_bytes_unref (out_bytes);
png_image_free (&image);
return texture;
}
GBytes *
gdk_save_png (GdkTexture *texture)
{
png_image image = { NULL, PNG_IMAGE_VERSION, 0, };
int stride;
const guchar *data;
guchar *new_data = NULL;
png_alloc_size_t size;
gpointer buffer;
GdkTexture *memory_texture;
GdkMemoryFormat format;
gboolean result G_GNUC_UNUSED;
image.width = gdk_texture_get_width (texture);
image.height = gdk_texture_get_height (texture);
memory_texture = gdk_texture_download_texture (texture);
format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (memory_texture));
switch (format)
{
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
data = gdk_memory_texture_get_data (GDK_MEMORY_TEXTURE (memory_texture));
stride = gdk_memory_texture_get_stride (GDK_MEMORY_TEXTURE (memory_texture));
image.format = PNG_FORMAT_RGBA;
break;
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
stride = image.width * 4;
new_data = g_malloc (stride * image.height);
gdk_texture_download (memory_texture, new_data, stride);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
flip_02 (new_data, image.width, image.height, stride);
#endif
data = new_data;
image.format = PNG_FORMAT_RGBA;
break;
case GDK_MEMORY_R16G16B16:
data = gdk_memory_texture_get_data (GDK_MEMORY_TEXTURE (memory_texture));
stride = gdk_memory_texture_get_stride (GDK_MEMORY_TEXTURE (memory_texture));
image.format = PNG_FORMAT_LINEAR_RGB;
break;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
data = gdk_memory_texture_get_data (GDK_MEMORY_TEXTURE (memory_texture));
stride = gdk_memory_texture_get_stride (GDK_MEMORY_TEXTURE (memory_texture));
image.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
break;
case GDK_MEMORY_R16G16B16_FLOAT:
case GDK_MEMORY_R32G32B32_FLOAT:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
/* This isn't very efficient */
new_data = g_malloc (image.width * image.height * 16);
gdk_texture_download_float (memory_texture, (float *)new_data, image.width * 16);
convert_float_to_16bit_inplace ((float *)new_data, image.width, image.height);
data = new_data;
stride = image.width * 8;
image.format = PNG_FORMAT_LINEAR_RGB_ALPHA;
break;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
}
if (image.format & PNG_FORMAT_FLAG_LINEAR)
stride /= 2;
png_image_write_get_memory_size (image, size, FALSE, data, stride, NULL);
buffer = g_malloc (size);
result = png_image_write_to_memory (&image, buffer, &size, FALSE, data, stride, NULL);
g_assert (result);
g_object_unref (memory_texture);
png_image_free (&image);
g_free (new_data);
return g_bytes_new_take (buffer, size);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+31
View File
@@ -0,0 +1,31 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_PNG_PRIVATE_H__
#define __GDK_PNG_PRIVATE_H__
#include "gdktexture.h"
#include <gio/gio.h>
#define PNG_SIGNATURE "\x89PNG"
GdkTexture *gdk_load_png (GBytes *bytes,
GError **error);
GBytes *gdk_save_png (GdkTexture *texture);
#endif
+502
View File
@@ -0,0 +1,502 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gdktiffprivate.h"
#include "gdktexture.h"
#include "gdktextureprivate.h"
#include "gdkmemorytextureprivate.h"
#include <tiffio.h>
/* Our main interest in tiff as an image format is that it is
* flexible enough to save all our texture formats without
* lossy conversions.
*
* The loader isn't meant to be a very versatile. It just aims
* to load the subset that we're saving ourselves. For anything
* else, we fall back to TIFFRGBAImage, which is the same api
* that gdk-pixbuf uses.
*/
/* {{{ IO handling */
typedef struct
{
GBytes **out_bytes;
gchar *data;
gsize size;
gsize position;
} TiffIO;
static void
tiff_io_warning (const char *module,
const char *fmt,
va_list ap) G_GNUC_PRINTF(2, 0);
static void
tiff_io_warning (const char *module,
const char *fmt,
va_list ap)
{
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
}
static void
tiff_io_error (const char *module,
const char *fmt,
va_list ap) G_GNUC_PRINTF(2, 0);
static void
tiff_io_error (const char *module,
const char *fmt,
va_list ap)
{
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
}
static tsize_t
tiff_io_read (thandle_t handle,
tdata_t buffer,
tsize_t size)
{
TiffIO *io = (TiffIO *) handle;
gsize read;
read = MIN (size, io->size - io->position);
memcpy (buffer, io->data + io->position, read);
io->position += read;
return (tsize_t) read;
}
static tsize_t
tiff_io_no_write (thandle_t handle,
tdata_t buffer,
tsize_t size)
{
errno = EINVAL;
return (tsize_t) -1;
}
static tsize_t
tiff_io_write (thandle_t handle,
tdata_t buffer,
tsize_t size)
{
TiffIO *io = (TiffIO *) handle;
if (io->size - io->position < size)
{
io->size = io->position + size;
io->data = g_realloc (io->data, io->size);
}
memcpy (io->data + io->position, buffer, size);
io->position += size;
return (tsize_t) size;
}
static toff_t
tiff_io_seek (thandle_t handle,
toff_t offset,
int whence)
{
TiffIO *io = (TiffIO *) handle;
switch (whence)
{
default:
errno = EINVAL;
return -1;
case SEEK_SET:
break;
case SEEK_CUR:
offset += io->position;
break;
case SEEK_END:
offset += io->size;
break;
}
if (offset < 0)
{
errno = EINVAL;
return -1;
}
if (offset > io->size)
{
/* Linux apparently can do that */
errno = EINVAL;
return -1;
}
io->position = offset;
return offset;
}
static int
tiff_io_close (thandle_t handle)
{
TiffIO *io = (TiffIO *) handle;
if (io->out_bytes)
*io->out_bytes = g_bytes_new_take (io->data, io->size);
g_free (io);
return 0;
}
static toff_t
tiff_io_get_file_size (thandle_t handle)
{
TiffIO *io = (TiffIO *) handle;
return io->size;
}
static TIFF *
tiff_open_read (GBytes *bytes)
{
TiffIO *io;
TIFFSetWarningHandler ((TIFFErrorHandler) tiff_io_warning);
TIFFSetErrorHandler ((TIFFErrorHandler) tiff_io_error);
io = g_new0 (TiffIO, 1);
io->data = (char *) g_bytes_get_data (bytes, &io->size);
return TIFFClientOpen ("GTK-read", "r",
(thandle_t) io,
tiff_io_read,
tiff_io_no_write,
tiff_io_seek,
tiff_io_close,
tiff_io_get_file_size,
NULL, NULL);
}
static TIFF *
tiff_open_write (GBytes **result)
{
TiffIO *io;
TIFFSetWarningHandler ((TIFFErrorHandler) tiff_io_warning);
TIFFSetErrorHandler ((TIFFErrorHandler) tiff_io_error);
io = g_new0 (TiffIO, 1);
io->out_bytes = result;
return TIFFClientOpen ("GTK-write", "w",
(thandle_t) io,
tiff_io_read,
tiff_io_write,
tiff_io_seek,
tiff_io_close,
tiff_io_get_file_size,
NULL, NULL);
}
/* }}} */
/* {{{ Format conversion */
static void
flip_02 (guchar *data,
int width,
int height,
int stride)
{
gsize x, y;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
guchar tmp;
tmp = data[x * 4];
data[x * 4] = data[x * 4 + 2];
data[x * 4 + 2] = tmp;
}
data += stride;
}
}
/* }}} */
/* {{{ Public API */
static struct {
GdkMemoryFormat format;
guint16 bits_per_sample;
guint16 samples_per_pixel;
guint16 sample_format;
} format_data[] = {
{ GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, 8, 4, SAMPLEFORMAT_UINT },
{ GDK_MEMORY_R8G8B8, 8, 3, SAMPLEFORMAT_UINT },
{ GDK_MEMORY_R16G16B16, 16, 3, SAMPLEFORMAT_UINT },
{ GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, 16, 4, SAMPLEFORMAT_UINT },
{ GDK_MEMORY_R16G16B16_FLOAT, 16, 3, SAMPLEFORMAT_IEEEFP },
{ GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, 16, 4, SAMPLEFORMAT_IEEEFP },
{ GDK_MEMORY_R32G32B32_FLOAT, 32, 3, SAMPLEFORMAT_IEEEFP },
{ GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, 32, 4, SAMPLEFORMAT_IEEEFP },
};
GBytes *
gdk_save_tiff (GdkTexture *texture)
{
TIFF *tif;
int width, height, stride;
guint16 bits_per_sample = 0;
guint16 samples_per_pixel = 0;
guint16 sample_format = 0;
const guchar *line;
const guchar *data;
guchar *new_data = NULL;
GBytes *result = NULL;
GdkTexture *memory_texture;
GdkMemoryFormat format;
tif = tiff_open_write (&result);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
memory_texture = gdk_texture_download_texture (texture);
format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (memory_texture));
for (int i = 0; i < G_N_ELEMENTS (format_data); i++)
{
if (format == format_data[i].format)
{
data = gdk_memory_texture_get_data (GDK_MEMORY_TEXTURE (memory_texture));
stride = gdk_memory_texture_get_stride (GDK_MEMORY_TEXTURE (memory_texture));
bits_per_sample = format_data[i].bits_per_sample;
samples_per_pixel = format_data[i].samples_per_pixel;
sample_format = format_data[i].sample_format;
break;
}
}
if (bits_per_sample == 0)
{
/* An 8-bit format we don't have in the table, handle
* it by converting to R8G8B8A8_PREMULTIPLIED
*/
stride = width * 4;
new_data = g_malloc (stride * height);
gdk_texture_download (memory_texture, new_data, stride);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
flip_02 (new_data, width, height, stride);
#endif
data = new_data;
bits_per_sample = 8;
samples_per_pixel = 4;
sample_format = SAMPLEFORMAT_UINT;
}
TIFFSetField (tif, TIFFTAG_SOFTWARE, "GTK");
TIFFSetField (tif, TIFFTAG_IMAGEWIDTH, width);
TIFFSetField (tif, TIFFTAG_IMAGELENGTH, height);
TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, bits_per_sample);
TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, samples_per_pixel);
TIFFSetField (tif, TIFFTAG_SAMPLEFORMAT, sample_format);
TIFFSetField (tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField (tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
// TODO: save gamma / colorspace
if (samples_per_pixel > 3)
{
guint16 extra_samples[] = { EXTRASAMPLE_ASSOCALPHA };
TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples);
}
TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
line = (const guchar *)data;
for (int y = 0; y < height; y++)
{
if (TIFFWriteScanline (tif, (void *)line, y, 0) == -1)
{
TIFFClose (tif);
g_free (new_data);
g_object_unref (memory_texture);
return NULL;
}
line += stride;
}
TIFFFlushData (tif);
TIFFClose (tif);
g_assert (result);
g_free (new_data);
g_object_unref (memory_texture);
return result;
}
static GdkTexture *
load_fallback (TIFF *tif,
GError **error)
{
int width, height;
guchar *data;
GBytes *bytes;
GdkTexture *texture;
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &height);
data = g_malloc (width * height * 4);
if (!TIFFReadRGBAImageOriented (tif, width, height, (uint32 *)data, ORIENTATION_TOPLEFT, 1))
{
g_set_error_literal (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to load RGB data from TIFF file");
g_free (data);
return NULL;
}
bytes = g_bytes_new_take (data, width * height * 4);
texture = gdk_memory_texture_new (width, height,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
bytes,
width * 4);
g_bytes_unref (bytes);
return texture;
}
GdkTexture *
gdk_load_tiff (GBytes *input_bytes,
GError **error)
{
TIFF *tif;
guint16 samples_per_pixel;
guint16 bits_per_sample;
guint16 photometric;
guint16 planarconfig;
guint16 sample_format;
guint16 orientation;
guint32 width, height;
GdkMemoryFormat format;
guchar *data, *line;
gsize stride;
int bpp;
GBytes *bytes;
GdkTexture *texture;
tif = tiff_open_read (input_bytes);
TIFFSetDirectory (tif, 0);
TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel);
TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLEFORMAT, &sample_format);
TIFFGetFieldDefaulted (tif, TIFFTAG_PHOTOMETRIC, &photometric);
TIFFGetFieldDefaulted (tif, TIFFTAG_PLANARCONFIG, &planarconfig);
TIFFGetFieldDefaulted (tif, TIFFTAG_ORIENTATION, &orientation);
TIFFGetFieldDefaulted (tif, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetFieldDefaulted (tif, TIFFTAG_IMAGELENGTH, &height);
if (samples_per_pixel == 4)
{
guint16 extra;
guint16 *extra_types;
if (!TIFFGetField (tif, TIFFTAG_EXTRASAMPLES, &extra, &extra_types))
extra = 0;
if (extra == 0 || extra_types[0] != EXTRASAMPLE_ASSOCALPHA)
{
texture = load_fallback (tif, error);
TIFFClose (tif);
return texture;
}
}
format = 0;
for (int i = 0; i < G_N_ELEMENTS (format_data); i++)
{
if (format_data[i].sample_format == sample_format &&
format_data[i].bits_per_sample == bits_per_sample &&
format_data[i].samples_per_pixel == samples_per_pixel)
{
format = format_data[i].format;
break;
}
}
if (format == 0 ||
photometric != PHOTOMETRIC_RGB ||
planarconfig != PLANARCONFIG_CONTIG ||
TIFFIsTiled (tif) ||
orientation != ORIENTATION_TOPLEFT)
{
texture = load_fallback (tif, error);
TIFFClose (tif);
return texture;
}
stride = width * gdk_memory_format_bytes_per_pixel (format);
g_assert (TIFFScanlineSize (tif) == stride);
data = g_new (guchar, height * stride);
line = data;
for (int y = 0; y < height; y++)
{
if (TIFFReadScanline (tif, line, y, 0) == -1)
{
g_set_error (error,
G_IO_ERROR, G_IO_ERROR_FAILED,
"Reading data failed at row %d", y);
TIFFClose (tif);
g_free (data);
return NULL;
}
line += stride;
}
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);
g_bytes_unref (bytes);
TIFFClose (tif);
return texture;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+32
View File
@@ -0,0 +1,32 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2021 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_TIFF_PRIVATE_H__
#define __GDK_TIFF_PRIVATE_H__
#include "gdktexture.h"
#include <gio/gio.h>
#define TIFF_SIGNATURE1 "MM\x00\x2a"
#define TIFF_SIGNATURE2 "II\x2a\x00"
GdkTexture *gdk_load_tiff (GBytes *bytes,
GError **error);
GBytes * gdk_save_tiff (GdkTexture *texture);
#endif
+7 -2
View File
@@ -27,6 +27,7 @@ gdk_public_sources = files([
'gdkglcontext.c',
'gdkglobals.c',
'gdkgltexture.c',
'gdkhsla.c',
'gdkkeys.c',
'gdkkeyuni.c',
'gdkmemorytexture.c',
@@ -50,6 +51,9 @@ gdk_public_sources = files([
'gdktoplevelsize.c',
'gdktoplevel.c',
'gdkdragsurface.c',
'loaders/gdkpng.c',
'loaders/gdktiff.c',
'loaders/gdkjpeg.c',
])
gdk_public_headers = files([
@@ -107,6 +111,7 @@ gdk_sources = gdk_public_sources
gdk_private_h_sources = files([
'gdkeventsprivate.h',
'gdkdevicetoolprivate.h',
'gdkhslaprivate.h',
'gdkmonitorprivate.h',
'gdkseatdefaultprivate.h',
'gdktoplevelsizeprivate.h',
@@ -254,8 +259,8 @@ endif
libgdk = static_library('gdk',
sources: [gdk_sources, gdk_backends_gen_headers, gdkconfig],
dependencies: gdk_deps + [libgtk_css_dep],
link_with: [libgtk_css, ],
dependencies: gdk_deps + [libgtk_css_dep, png_dep, tiff_dep, jpeg_dep],
link_with: [libgtk_css],
include_directories: [confinc, gdkx11_inc, wlinc],
c_args: libgdk_c_args + common_cflags,
link_whole: gdk_backends,
+12 -17
View File
@@ -4377,15 +4377,6 @@ gsk_text_node_draw (GskRenderNode *node,
cairo_restore (cr);
}
/* We steal one of the bits in PangoGlyphVisAttr */
G_STATIC_ASSERT (sizeof (PangoGlyphVisAttr) == 4);
#define COLOR_GLYPH_BIT 2
#define GLYPH_IS_COLOR(g) (((*(guint32*)&(g)->attr) & COLOR_GLYPH_BIT) != 0)
#define GLYPH_SET_COLOR(g) (*(guint32*)(&(g)->attr) |= COLOR_GLYPH_BIT)
#define GLYPH_CLEAR_COLOR(g) (*(guint32*)(&(g)->attr) &= ~COLOR_GLYPH_BIT)
static void
gsk_text_node_diff (GskRenderNode *node1,
GskRenderNode *node2,
@@ -4411,7 +4402,7 @@ gsk_text_node_diff (GskRenderNode *node1,
info1->geometry.x_offset == info2->geometry.x_offset &&
info1->geometry.y_offset == info2->geometry.y_offset &&
info1->attr.is_cluster_start == info2->attr.is_cluster_start &&
GLYPH_IS_COLOR (info1) == GLYPH_IS_COLOR (info2))
info1->attr.is_color == info2->attr.is_color)
continue;
gsk_render_node_diff_impossible (node1, node2, region);
@@ -5683,7 +5674,7 @@ gsk_render_node_content_serializer_finish (GObject *source,
GOutputStream *stream = G_OUTPUT_STREAM (source);
GError *error = NULL;
if (!g_output_stream_write_bytes_finish (stream, result, &error))
if (g_output_stream_splice_finish (stream, result, &error) < 0)
gdk_content_serializer_return_error (serializer, error);
else
gdk_content_serializer_return_success (serializer);
@@ -5692,6 +5683,7 @@ gsk_render_node_content_serializer_finish (GObject *source,
static void
gsk_render_node_content_serializer (GdkContentSerializer *serializer)
{
GInputStream *input;
const GValue *value;
GskRenderNode *node;
GBytes *bytes;
@@ -5699,13 +5691,16 @@ gsk_render_node_content_serializer (GdkContentSerializer *serializer)
value = gdk_content_serializer_get_value (serializer);
node = gsk_value_get_render_node (value);
bytes = gsk_render_node_serialize (node);
input = g_memory_input_stream_new_from_bytes (bytes);
g_output_stream_write_bytes_async (gdk_content_serializer_get_output_stream (serializer),
bytes,
gdk_content_serializer_get_priority (serializer),
gdk_content_serializer_get_cancellable (serializer),
gsk_render_node_content_serializer_finish,
serializer);
g_output_stream_splice_async (gdk_content_serializer_get_output_stream (serializer),
input,
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
gdk_content_serializer_get_priority (serializer),
gdk_content_serializer_get_cancellable (serializer),
gsk_render_node_content_serializer_finish,
serializer);
g_object_unref (input);
g_bytes_unref (bytes);
}
+6 -16
View File
@@ -94,15 +94,8 @@ parse_texture (GtkCssParser *parser,
bytes = gtk_css_data_url_parse (url, NULL, &error);
if (bytes)
{
stream = g_memory_input_stream_new_from_bytes (bytes);
texture = gdk_texture_new_from_bytes (bytes, &error);
g_bytes_unref (bytes);
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, &error);
g_object_unref (stream);
if (pixbuf != NULL)
{
texture = gdk_texture_new_for_pixbuf (pixbuf);
g_object_unref (pixbuf);
}
}
}
else
@@ -2690,26 +2683,23 @@ render_node_print (Printer *p,
case GSK_TEXTURE_NODE:
{
GdkTexture *texture = gsk_texture_node_get_texture (node);
cairo_surface_t *surface;
GByteArray *array;
GBytes *bytes;
start_node (p, "texture");
append_rect_param (p, "bounds", &node->bounds);
surface = gdk_texture_download_surface (texture);
array = g_byte_array_new ();
cairo_surface_write_to_png_stream (surface, cairo_write_array, array);
bytes = gdk_texture_save_to_png_bytes (texture);
_indent (p);
g_string_append (p->str, "texture: url(\"data:image/png;base64,");
b64 = base64_encode_with_linebreaks (array->data, array->len);
b64 = base64_encode_with_linebreaks (g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
append_escaping_newlines (p->str, b64);
g_free (b64);
g_string_append (p->str, "\");\n");
end_node (p);
g_byte_array_free (array, TRUE);
cairo_surface_destroy (surface);
g_bytes_unref (bytes);
}
break;
+86 -10
View File
@@ -37,7 +37,7 @@ as_float (const guint x)
// IEEE-754 16-bit floating-point format (without infinity): 1-5-10
static inline float
half_to_float (const guint16 x)
half_to_float_one (const guint16 x)
{
const guint e = (x&0x7C00)>>10; // exponent
const guint m = (x&0x03FF)<<13; // mantissa
@@ -46,7 +46,7 @@ half_to_float (const guint16 x)
}
static inline guint16
float_to_half (const float x)
float_to_half_one (const float x)
{
const guint b = as_uint(x)+0x00001000; // round-to-nearest-even
const guint e = (b&0x7F800000)>>23; // exponent
@@ -58,20 +58,38 @@ void
float_to_half4_c (const float f[4],
guint16 h[4])
{
h[0] = float_to_half (f[0]);
h[1] = float_to_half (f[1]);
h[2] = float_to_half (f[2]);
h[3] = float_to_half (f[3]);
h[0] = float_to_half_one (f[0]);
h[1] = float_to_half_one (f[1]);
h[2] = float_to_half_one (f[2]);
h[3] = float_to_half_one (f[3]);
}
void
half_to_float4_c (const guint16 h[4],
float f[4])
{
f[0] = half_to_float (h[0]);
f[1] = half_to_float (h[1]);
f[2] = half_to_float (h[2]);
f[3] = half_to_float (h[3]);
f[0] = half_to_float_one (h[0]);
f[1] = half_to_float_one (h[1]);
f[2] = half_to_float_one (h[2]);
f[3] = half_to_float_one (h[3]);
}
void
float_to_half_c (const float *f,
guint16 *h,
int n)
{
for (int i = 0; i < n; i++)
h[i] = float_to_half_one (f[i]);
}
void
half_to_float_c (const guint16 *h,
float *f,
int n)
{
for (int i = 0; i < n; i++)
f[i] = half_to_float_one (h[i]);
}
#ifdef HAVE_F16C
@@ -122,10 +140,30 @@ half_to_float4 (const guint16 h[4], float f[4])
half_to_float4_c (h, f);
}
void
float_to_half (const float *f, guint16 *h, int n)
{
if (have_f16c_msvc ())
float_to_half_f16c (f, h, n);
else
float_to_half4_c (f, h, n);
}
void
half_to_float (const guint16 *h, float *f, int n)
{
if (have_f16c_msvc ())
half_to_float_f16c (h, f, n);
else
half_to_float_c (h, f, n);
}
#else
void float_to_half4 (const float f[4], guint16 h[4]) __attribute__((ifunc ("resolve_float_to_half4")));
void half_to_float4 (const guint16 h[4], float f[4]) __attribute__((ifunc ("resolve_half_to_float4")));
void float_to_half (const float *f, guint16 *h, int n) __attribute__((ifunc ("resolve_float_to_half")));
void half_to_float (const guint16 *h, float *f, int n) __attribute__((ifunc ("resolve_half_to_float")));
static void *
resolve_float_to_half4 (void)
@@ -147,6 +185,26 @@ resolve_half_to_float4 (void)
return half_to_float4_c;
}
static void *
resolve_float_to_half (void)
{
__builtin_cpu_init ();
if (__builtin_cpu_supports ("f16c"))
return float_to_half_f16c;
else
return float_to_half_c;
}
static void *
resolve_half_to_float (void)
{
__builtin_cpu_init ();
if (__builtin_cpu_supports ("f16c"))
return half_to_float_f16c;
else
return half_to_float_c;
}
#endif
#else /* ! HAVE_F16C */
@@ -168,10 +226,28 @@ half_to_float4 (const guint16 h[4],
half_to_float4_c (h, f);
}
void
float_to_half (const float *f,
guint16 *h,
int n)
{
float_to_half_c (f, h, n);
}
void
half_to_float (const guint16 *h,
float *f,
int n)
{
half_to_float_c (h, f, n);
}
#else
void float_to_half4 (const float f[4], guint16 h[4]) __attribute__((alias ("float_to_half4_c")));
void half_to_float4 (const guint16 h[4], float f[4]) __attribute__((alias ("half_to_float4_c")));
void float_to_half (const float *f, guint16 *h, int n) __attribute__((alias ("float_to_half_c")));
void half_to_float (const guint16 *h, float *f, int n) __attribute__((alias ("half_to_float_c")));
#endif
+70 -1
View File
@@ -30,7 +30,6 @@
#else
#define CAST_M128I_P(a) (__m128i_u const *) a
#endif
void
float_to_half4_f16c (const float f[4],
guint16 h[4])
@@ -50,4 +49,74 @@ half_to_float4_f16c (const guint16 h[4],
_mm_store_ps (f, s);
}
#define ALIGNED(p, n) (GPOINTER_TO_UINT(p) % n == 0)
void
float_to_half_f16c (const float *f,
guint16 *h,
int n)
{
__m128 s;
__m128i i;
int j;
const float *ff = f;
guint16 *hh = h;
for (j = 0; j < n; j++)
{
if (ALIGNED (ff, 16) && ALIGNED (hh, 16))
break;
ff++;
hh++;
}
float_to_half_c (f, h, j);
for (; j + 4 < n; j += 4)
{
s = _mm_loadu_ps (ff);
i = _mm_cvtps_ph (s, 0);
_mm_storel_epi64 ((__m128i*)hh, i);
ff += 4;
hh += 4;
}
if (j < n)
float_to_half_c (ff, hh, n - j);
}
void
half_to_float_f16c (const guint16 *h,
float *f,
int n)
{
__m128i i;
__m128 s;
int j;
const guint16 *hh = h;
float *ff = f;
for (j = 0; j < n; j++)
{
if (ALIGNED (ff, 16) && ALIGNED (hh, 16))
break;
ff++;
hh++;
}
half_to_float_c (h, f, j);
for (; j + 4 < n; j += 4)
{
i = _mm_loadl_epi64 (CAST_M128I_P (hh));
s = _mm_cvtph_ps (i);
_mm_store_ps (ff, s);
hh += 4;
ff += 4;
}
if (j < n)
half_to_float_c (hh, ff, n - j);
}
#endif /* HAVE_F16C */
+24
View File
@@ -35,18 +35,42 @@ void float_to_half4 (const float f[4],
void half_to_float4 (const guint16 h[4],
float f[4]);
void float_to_half (const float *f,
guint16 *h,
int n);
void half_to_float (const guint16 *h,
float *f,
int n);
void float_to_half4_f16c (const float f[4],
guint16 h[4]);
void half_to_float4_f16c (const guint16 h[4],
float f[4]);
void float_to_half_f16c (const float *f,
guint16 *h,
int n);
void half_to_float_f16c (const guint16 *h,
float *f,
int n);
void float_to_half4_c (const float f[4],
guint16 h[4]);
void half_to_float4_c (const guint16 h[4],
float f[4]);
void float_to_half_c (const float *f,
guint16 *h,
int n);
void half_to_float_c (const guint16 *h,
float *f,
int n);
G_END_DECLS
#endif
+8 -19
View File
@@ -735,8 +735,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
int mag_filter)
{
GdkGLContext *context;
GdkTexture *downloaded_texture = NULL;
GdkTexture *source_texture;
GdkTexture *downloaded_texture;
GskNglTexture *t;
guint texture_id;
int height;
@@ -760,21 +759,7 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
}
else
{
cairo_surface_t *surface;
/* In this case, we have to temporarily make the texture's
* context the current one, download its data into our context
* and then create a texture from it. */
if (texture_context != NULL)
gdk_gl_context_make_current (texture_context);
surface = gdk_texture_download_surface (texture);
downloaded_texture = gdk_texture_new_for_surface (surface);
cairo_surface_destroy (surface);
gdk_gl_context_make_current (context);
source_texture = downloaded_texture;
downloaded_texture = gdk_texture_download_texture (texture);
}
}
else
@@ -785,13 +770,17 @@ gsk_ngl_driver_load_texture (GskNglDriver *self,
return t->texture_id;
}
source_texture = texture;
downloaded_texture = gdk_texture_download_texture (texture);
}
/* The download_texture() call may have switched the GL context. Make sure
* the right context is at work again. */
gdk_gl_context_make_current (context);
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
texture_id = gsk_ngl_command_queue_upload_texture (self->command_queue,
source_texture,
downloaded_texture,
0,
0,
width,
+1 -1
View File
@@ -235,7 +235,7 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self,
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data,
width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
GDK_MEMORY_CONVERT_GLES_RGBA,
cairo_image_surface_get_data (surface),
width * 4,
GDK_MEMORY_DEFAULT,
+1 -1
View File
@@ -115,7 +115,7 @@ gsk_ngl_icon_library_add (GskNglIconLibrary *self,
{
pixel_data = free_data = g_malloc (width * height * 4);
gdk_memory_convert (pixel_data, width * 4,
GDK_MEMORY_R8G8B8A8_PREMULTIPLIED,
GDK_MEMORY_CONVERT_GLES_RGBA,
surface_data, cairo_image_surface_get_stride (surface),
GDK_MEMORY_DEFAULT, width, height);
gl_format = GL_RGBA;
+19
View File
@@ -0,0 +1,19 @@
Compose data
============
GTK includes a copy of the X11 Compose file in a compact, precompiled
form (the same format is used for caching custom Compose files in
the users home directory).
The X11 Compose file can be found here:
https://gitlab.freedesktop.org/xorg/lib/libx11/-/raw/master/nls/en_US.UTF-8/Compose.pre
The tool to convert the data is build during the GTK build, from
compose-parse.c in this directory. You run it like this:
cpp -DXCOMM='#' Compose.pre | sed -e 's/^ *#/#/' > Compose
compose-parse Compose sequences-little-endian sequences-big-endian chars gtkcomposedata.h
The GTK build expects the resulting files to be in the source tree,
in the gtk/cmompose directory.
+17 -6
View File
@@ -484,15 +484,26 @@ out:
*
* Parses a string representing an accelerator.
*
* The format looks like <Control>a or <Shift><Alt>F1.
* The format looks like `<Control>a` or `<Shift><Alt>F1`.
*
* The parser is fairly liberal and allows lower or upper case, and also
* abbreviations such as <Ctl> and <Ctrl>. Key names are parsed using
* [func@Gdk.keyval_from_name]. For character keys the name is not the symbol,
* but the lowercase name, e.g. one would use <Ctrl>minus instead of
* <Ctrl>-.
* abbreviations such as `<Ctl>` and `<Ctrl>`.
*
* If the parse fails, @accelerator_key and @accelerator_mods will
* Key names are parsed using [func@Gdk.keyval_from_name]. For character keys
* the name is not the symbol, but the lowercase name, e.g. one would use
* `<Ctrl>minus` instead of `<Ctrl>-`.
*
* Modifiers are enclosed in angular brackets `<>`, and match the
* [enum@Gdk.ModifierType] mask:
*
* - `<Shift>` for `GDK_SHIFT_MASK`
* - `<Ctrl>` for `GDK_CONTROL_MASK`
* - `<Alt>` for `GDK_ALT_MASK`
* - `<Meta>` for `GDK_META_MASK`
* - `<Super>` for `GDK_SUPER_MASK`
* - `<Hyper>` for `GDK_HYPER_MASK`
*
* If the parse operation fails, @accelerator_key and @accelerator_mods will
* be set to 0 (zero).
*/
gboolean
+6 -4
View File
@@ -20,10 +20,10 @@
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkhslaprivate.h"
#include "gtkprivate.h"
#include "gtkstylepropertyprivate.h"
#include "gdk/gdkhslaprivate.h"
#include "gdk/gdkrgbaprivate.h"
typedef enum {
@@ -309,10 +309,10 @@ apply_shade (const GdkRGBA *in,
GdkRGBA *out,
double factor)
{
GtkHSLA hsla;
GdkHSLA hsla;
_gtk_hsla_init_from_rgba (&hsla, in);
_gtk_hsla_shade (&hsla, &hsla, factor);
_gdk_hsla_init_from_rgba (&hsla, in);
_gdk_hsla_shade (&hsla, &hsla, factor);
_gdk_rgba_init_from_hsla (out, &hsla);
}
@@ -699,6 +699,8 @@ gtk_css_color_value_can_parse (GtkCssParser *parser)
|| gtk_css_parser_has_function (parser, "shade")
|| gtk_css_parser_has_function (parser, "alpha")
|| gtk_css_parser_has_function (parser, "mix")
|| gtk_css_parser_has_function (parser, "hsl")
|| gtk_css_parser_has_function (parser, "hsla")
|| gtk_css_parser_has_function (parser, "rgb")
|| gtk_css_parser_has_function (parser, "rgba");
}
+160 -9
View File
@@ -66,8 +66,9 @@
* `GtkMenuButton` has a single CSS node with name `menubutton`
* which contains a `button` node with a `.toggle` style class.
*
* If the button contains only an icon or an arrow, it will have the
* `.image-button` style class, if it contains both, it will have the
* If the button contains an icon, it will have the `.image-button` style class,
* if it contains text, it will have `.text-button` style class. If an arrow is
* visible in addition to an icon, text or a custom child, it will also have
* `.arrow-button` style class.
*
* Inside the toggle button content, there is an `arrow` node for
@@ -87,6 +88,7 @@
#include "config.h"
#include "gtkactionable.h"
#include "gtkbuildable.h"
#include "gtkbuiltiniconprivate.h"
#include "gtkintl.h"
#include "gtkimage.h"
@@ -122,6 +124,7 @@ struct _GtkMenuButton
GtkWidget *label_widget;
GtkWidget *image_widget;
GtkWidget *arrow_widget;
GtkWidget *child;
GtkArrowType arrow_type;
gboolean always_show_arrow;
@@ -147,6 +150,7 @@ enum
PROP_USE_UNDERLINE,
PROP_HAS_FRAME,
PROP_PRIMARY,
PROP_CHILD,
LAST_PROP
};
@@ -158,7 +162,10 @@ enum {
static GParamSpec *menu_button_props[LAST_PROP];
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE (GtkMenuButton, gtk_menu_button, GTK_TYPE_WIDGET)
static void gtk_menu_button_buildable_iface_init (GtkBuildableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkMenuButton, gtk_menu_button, GTK_TYPE_WIDGET,
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_menu_button_buildable_iface_init))
static void gtk_menu_button_dispose (GObject *object);
@@ -199,6 +206,9 @@ gtk_menu_button_set_property (GObject *object,
case PROP_PRIMARY:
gtk_menu_button_set_primary (self, g_value_get_boolean (value));
break;
case PROP_CHILD:
gtk_menu_button_set_child (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -241,6 +251,9 @@ gtk_menu_button_get_property (GObject *object,
case PROP_PRIMARY:
g_value_set_boolean (value, gtk_menu_button_get_primary (GTK_MENU_BUTTON (object)));
break;
case PROP_CHILD:
g_value_set_object (value, gtk_menu_button_get_child (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -444,14 +457,14 @@ gtk_menu_button_class_init (GtkMenuButtonClass *klass)
/**
* GtkMenuButton:always-show-arrow: (attributes org.gtk.Property.get=gtk_menu_button_get_always_show_arrow org.gtk.Property.set=gtk_menu_button_set_always_show_arrow)
*
* Whether to show a dropdown arrow even when using an icon.
* Whether to show a dropdown arrow even when using an icon or a custom child.
*
* Since: 4.4
*/
menu_button_props[PROP_ALWAYS_SHOW_ARROW] =
g_param_spec_boolean ("always-show-arrow",
P_("Always Show Arrow"),
P_("Whether to show a dropdown arrow even when using an icon"),
P_("Whether to show a dropdown arrow even when using an icon or a custom child"),
FALSE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
@@ -507,6 +520,20 @@ gtk_menu_button_class_init (GtkMenuButtonClass *klass)
FALSE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
/**
* GtkMenuButton:child: (attributes org.gtk.Property.get=gtk_menu_button_get_child org.gtk.Property.set=gtk_menu_button_set_child)
*
* The child widget.
*
* Since: 4.6
*/
menu_button_props[PROP_CHILD] =
g_param_spec_object ("child",
P_("Child"),
P_("The child widget"),
GTK_TYPE_WIDGET,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, LAST_PROP, menu_button_props);
/**
@@ -575,13 +602,22 @@ set_arrow_type (GtkWidget *arrow,
static void
update_style_classes (GtkMenuButton *menu_button)
{
if (menu_button->arrow_widget == gtk_button_get_child (GTK_BUTTON (menu_button->button)) ||
(menu_button->image_widget && !menu_button->always_show_arrow))
gboolean has_icon = menu_button->image_widget != NULL;
gboolean has_label = menu_button->label_widget != NULL;
gboolean has_only_arrow = menu_button->arrow_widget == gtk_button_get_child (GTK_BUTTON (menu_button->button));
gboolean has_arrow = gtk_widget_get_visible (menu_button->arrow_widget);
if (has_only_arrow || has_icon)
gtk_widget_add_css_class (menu_button->button, "image-button");
else
gtk_widget_remove_css_class (menu_button->button, "image-button");
if (menu_button->image_widget && menu_button->always_show_arrow)
if (has_label)
gtk_widget_add_css_class (menu_button->button, "text-button");
else
gtk_widget_remove_css_class (menu_button->button, "text-button");
if (has_arrow && !has_only_arrow)
gtk_widget_add_css_class (menu_button->button, "arrow-button");
else
gtk_widget_remove_css_class (menu_button->button, "arrow-button");
@@ -635,6 +671,28 @@ gtk_menu_button_init (GtkMenuButton *self)
gtk_widget_add_css_class (GTK_WIDGET (self), "popup");
}
static GtkBuildableIface *parent_buildable_iface;
static void
gtk_menu_button_buildable_add_child (GtkBuildable *buildable,
GtkBuilder *builder,
GObject *child,
const char *type)
{
if (GTK_IS_WIDGET (child))
gtk_menu_button_set_child (GTK_MENU_BUTTON (buildable), GTK_WIDGET (child));
else
parent_buildable_iface->add_child (buildable, builder, child, type);
}
static void
gtk_menu_button_buildable_iface_init (GtkBuildableIface *iface)
{
parent_buildable_iface = g_type_interface_peek_parent (iface);
iface->add_child = gtk_menu_button_buildable_add_child;
}
/**
* gtk_menu_button_new:
*
@@ -932,6 +990,13 @@ gtk_menu_button_get_popover (GtkMenuButton *menu_button)
* @icon_name: the icon name
*
* Sets the name of an icon to show inside the menu button.
*
* Setting icon name resets [property@Gtk.MenuButton:label] and
* [property@Gtk.MenuButton:child].
*
* If [property@Gtk.MenuButton:always-show-arrow] is set to `TRUE` and
* [property@Gtk.MenuButton:direction] is not `GTK_ARROW_NONE`, a dropdown arrow
* will be shown next to the icon.
*/
void
gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
@@ -946,6 +1011,9 @@ gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
if (gtk_menu_button_get_label (menu_button))
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_LABEL]);
if (gtk_menu_button_get_child (menu_button))
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_CHILD]);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
@@ -963,6 +1031,7 @@ gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
gtk_button_set_child (GTK_BUTTON (menu_button->button), box);
menu_button->label_widget = NULL;
menu_button->child = NULL;
update_arrow (menu_button);
@@ -995,7 +1064,8 @@ gtk_menu_button_get_icon_name (GtkMenuButton *menu_button)
* @menu_button: a `GtkMenuButton`
* @always_show_arrow: hether to show a dropdown arrow even when using an icon
*
* Sets whether to show a dropdown arrow even when using an icon.
* Sets whether to show a dropdown arrow even when using an icon or a custom
* child.
*
* Since: 4.4
*/
@@ -1041,6 +1111,12 @@ gtk_menu_button_get_always_show_arrow (GtkMenuButton *menu_button)
* @label: the label
*
* Sets the label to show inside the menu button.
*
* Setting a label resets [property@Gtk.MenuButton:icon-name] and
* [property@Gtk.MenuButton:child].
*
* If [property@Gtk.MenuButton:direction] is not `GTK_ARROW_NONE`, a dropdown
* arrow will be shown next to the label.
*/
void
gtk_menu_button_set_label (GtkMenuButton *menu_button,
@@ -1056,6 +1132,8 @@ gtk_menu_button_set_label (GtkMenuButton *menu_button,
if (gtk_menu_button_get_icon_name (menu_button))
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_ICON_NAME]);
if (gtk_menu_button_get_child (menu_button))
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_CHILD]);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
label_widget = gtk_label_new (label);
@@ -1072,6 +1150,7 @@ gtk_menu_button_set_label (GtkMenuButton *menu_button,
menu_button->label_widget = label_widget;
menu_button->image_widget = NULL;
menu_button->child = NULL;
update_arrow (menu_button);
@@ -1354,3 +1433,75 @@ gtk_menu_button_get_primary (GtkMenuButton *menu_button)
return menu_button->primary;
}
/**
* gtk_menu_button_set_child: (attributes org.gtk.Method.set_property=child)
* @menu_button: a `GtkMenuButton`
* @child: (nullable): the child widget
*
* Sets the child widget of @menu_button.
*
* Setting a child resets [property@Gtk.MenuButton:label] and
* [property@Gtk.MenuButton:icon-name].
*
* If [property@Gtk.MenuButton:always-show-arrow] is set to `TRUE` and
* [property@Gtk.MenuButton:direction] is not `GTK_ARROW_NONE`, a dropdown arrow
* will be shown next to the child.
*
* Since: 4.6
*/
void
gtk_menu_button_set_child (GtkMenuButton *menu_button,
GtkWidget *child)
{
GtkWidget *box, *arrow;
g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
g_return_if_fail (child == NULL || GTK_IS_WIDGET (child));
g_object_freeze_notify (G_OBJECT (menu_button));
if (gtk_menu_button_get_label (menu_button))
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_LABEL]);
if (gtk_menu_button_get_icon_name (menu_button))
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_ICON_NAME]);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
arrow = gtk_builtin_icon_new ("arrow");
menu_button->arrow_widget = arrow;
gtk_box_append (GTK_BOX (box), child);
gtk_box_append (GTK_BOX (box), arrow);
gtk_button_set_child (GTK_BUTTON (menu_button->button), box);
menu_button->child = child;
menu_button->image_widget = NULL;
menu_button->label_widget = NULL;
update_arrow (menu_button);
g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_CHILD]);
g_object_thaw_notify (G_OBJECT (menu_button));
}
/**
* gtk_menu_button_get_child: (attributes org.gtk.Method.get_property=child)
* @menu_button: a `GtkMenuButton`
*
* Gets the child widget of @menu_button.
*
* Returns: (nullable) (transfer none): the child widget of @menu_button
*
* Since: 4.6
*/
GtkWidget *
gtk_menu_button_get_child (GtkMenuButton *menu_button)
{
g_return_val_if_fail (GTK_IS_MENU_BUTTON (menu_button), NULL);
return menu_button->child;
}
+6
View File
@@ -121,6 +121,12 @@ void gtk_menu_button_set_primary (GtkMenuButton *menu_button,
GDK_AVAILABLE_IN_4_4
gboolean gtk_menu_button_get_primary (GtkMenuButton *menu_button);
GDK_AVAILABLE_IN_4_6
void gtk_menu_button_set_child (GtkMenuButton *menu_button,
GtkWidget *child);
GDK_AVAILABLE_IN_4_6
GtkWidget * gtk_menu_button_get_child (GtkMenuButton *menu_button);
G_END_DECLS
#endif /* __GTK_MENU_BUTTON_H__ */
+4 -4
View File
@@ -33,10 +33,10 @@
#include "gtkcssrepeatvalueprivate.h"
#include "gtkcsscolorvalueprivate.h"
#include "gtkcssstyleprivate.h"
#include "gtkhslaprivate.h"
#include "gtkroundedboxprivate.h"
#include "gtksnapshotprivate.h"
#include "gdk/gdkhslaprivate.h"
#include "gsk/gskroundedrectprivate.h"
typedef struct _GtkBorderImage GtkBorderImage;
@@ -513,10 +513,10 @@ color_shade (const GdkRGBA *color,
double factor,
GdkRGBA *color_return)
{
GtkHSLA hsla;
GdkHSLA hsla;
_gtk_hsla_init_from_rgba (&hsla, color);
_gtk_hsla_shade (&hsla, &hsla, factor);
_gdk_hsla_init_from_rgba (&hsla, color);
_gdk_hsla_shade (&hsla, &hsla, factor);
_gdk_rgba_init_from_hsla (color_return, &hsla);
}
+27 -1
View File
@@ -166,6 +166,7 @@ enum {
PROP_XFT_HINTSTYLE,
PROP_XFT_RGBA,
PROP_XFT_DPI,
PROP_HINT_FONT_METRICS,
PROP_CURSOR_THEME_NAME,
PROP_CURSOR_THEME_SIZE,
PROP_ALTERNATIVE_BUTTON_ORDER,
@@ -556,6 +557,7 @@ gtk_settings_class_init (GtkSettingsClass *class)
g_assert (result == PROP_XFT_RGBA);
/**
* GtkSettings:gtk-xft-dpi:
*
@@ -572,6 +574,25 @@ gtk_settings_class_init (GtkSettingsClass *class)
g_assert (result == PROP_XFT_DPI);
/**
* GtkSettings:gtk-hint-font-metrics:
*
* Whether hinting should be applied to font metrics.
*
* Note that this also turns off subpixel positioning of glyphs,
* since it conflicts with metrics hinting.
*
* Since: 4.6
*/
result = settings_install_property_parser (class,
g_param_spec_boolean ("gtk-hint-font-metrics",
P_("Hint Font Metrics"),
P_("Whether hinting should be applied to font metrics"),
FALSE,
GTK_PARAM_READWRITE));
g_assert (result == PROP_HINT_FONT_METRICS);
/**
* GtkSettings:gtk-cursor-theme-name:
*
@@ -1439,6 +1460,7 @@ gtk_settings_notify (GObject *object,
case PROP_XFT_HINTING:
case PROP_XFT_HINTSTYLE:
case PROP_XFT_RGBA:
case PROP_HINT_FONT_METRICS:
settings_update_font_options (settings);
gtk_system_setting_changed (settings->display, GTK_SYSTEM_SETTING_FONT_CONFIG);
break;
@@ -1678,6 +1700,7 @@ settings_update_font_options (GtkSettings *settings)
cairo_antialias_t antialias_mode;
char *rgba_str;
cairo_subpixel_order_t subpixel_order;
gboolean hint_font_metrics;
if (settings->font_options)
cairo_font_options_destroy (settings->font_options);
@@ -1687,11 +1710,14 @@ settings_update_font_options (GtkSettings *settings)
"gtk-xft-hinting", &hinting,
"gtk-xft-hintstyle", &hint_style_str,
"gtk-xft-rgba", &rgba_str,
"gtk-hint-font-metrics", &hint_font_metrics,
NULL);
settings->font_options = cairo_font_options_create ();
cairo_font_options_set_hint_metrics (settings->font_options, CAIRO_HINT_METRICS_OFF);
cairo_font_options_set_hint_metrics (settings->font_options,
hint_font_metrics ? CAIRO_HINT_METRICS_ON
: CAIRO_HINT_METRICS_OFF);
hint_style = CAIRO_HINT_STYLE_DEFAULT;
if (hinting == 0)
+4 -3
View File
@@ -690,13 +690,14 @@ gtk_stack_dispose (GObject *obj)
GtkStack *stack = GTK_STACK (obj);
GtkStackPrivate *priv = gtk_stack_get_instance_private (stack);
GtkWidget *child;
if (priv->pages)
g_list_model_items_changed (G_LIST_MODEL (priv->pages), 0, g_list_length (priv->children), 0);
guint n_pages = g_list_length (priv->children);
while ((child = gtk_widget_get_first_child (GTK_WIDGET (stack))))
stack_remove (stack, child, TRUE);
if (priv->pages)
g_list_model_items_changed (G_LIST_MODEL (priv->pages), 0, n_pages, 0);
G_OBJECT_CLASS (gtk_stack_parent_class)->dispose (obj);
}
+1 -5
View File
@@ -447,9 +447,6 @@ _gtk_text_attributes_fill_from_tags (GtkTextAttributes *dest,
if (tag->priv->sentence_set)
dest->sentence = vals->sentence;
if (tag->priv->baseline_shift_set)
dest->baseline_shift = vals->baseline_shift;
}
dest->left_margin += left_margin_accumulative;
@@ -480,8 +477,7 @@ _gtk_text_tag_affects_size (GtkTextTag *tag)
priv->invisible_set ||
priv->font_features_set ||
priv->letter_spacing_set ||
priv->text_transform_set ||
priv->baseline_shift_set;
priv->text_transform_set;
}
gboolean
+1 -2
View File
@@ -108,7 +108,7 @@ struct _GtkTextAppearance
* @wrap_mode: `GtkWrapMode` for text.
* @language: `PangoLanguage` for text.
* @invisible: Hide the text.
* @bg_full_height: Background is fit to full line height rather than:
* @bg_full_height: Background is fit to full line height rather than
* baseline +/- ascent/descent (font height).
* @editable: Can edit this text.
* @no_fallback: Whether to disable font fallback.
@@ -162,7 +162,6 @@ struct _GtkTextAttributes
guint text_transform : 3; /* PangoTextTransform */
guint word : 1;
guint sentence : 1;
guint baseline_shift : 2; /* PangoFontScale / PangoBaselineShift */
};
GtkTextAttributes* gtk_text_attributes_new (void);
+3 -4
View File
@@ -4740,11 +4740,10 @@ insert_tags_for_attributes (GtkTextBuffer *buffer,
INT_ATTR (baseline_shift);
break;
/* Ignore font scale, since we treat baseline-shift as indicating
* both. And in practice, they will basically always occur together
* (from a <sup> or <sub>)
*/
case PANGO_ATTR_FONT_SCALE:
INT_ATTR (font_scale);
break;
case PANGO_ATTR_SHAPE:
case PANGO_ATTR_ABSOLUTE_SIZE:
case PANGO_ATTR_GRAVITY:
-15
View File
@@ -1710,21 +1710,6 @@ add_text_attrs (GtkTextLayout *layout,
attr->start_index = start;
attr->end_index = start + byte_count;
pango_attr_list_insert (attrs, attr);
}
if (style->baseline_shift)
{
attr = pango_attr_baseline_shift_new (style->baseline_shift);
attr->start_index = start;
attr->end_index = start + byte_count;
pango_attr_list_insert (attrs, attr);
attr = pango_attr_font_scale_new (style->baseline_shift);
attr->start_index = start;
attr->end_index = start + byte_count;
pango_attr_list_insert (attrs, attr);
}
}
-41
View File
@@ -137,7 +137,6 @@ enum {
PROP_TEXT_TRANSFORM,
PROP_WORD,
PROP_SENTENCE,
PROP_BASELINE_SHIFT,
/* Behavior args */
PROP_ACCUMULATIVE_MARGIN,
@@ -183,7 +182,6 @@ enum {
PROP_TEXT_TRANSFORM_SET,
PROP_WORD_SET,
PROP_SENTENCE_SET,
PROP_BASELINE_SHIFT_SET,
LAST_ARG
};
@@ -914,23 +912,6 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
FALSE,
GTK_PARAM_READWRITE));
/**
* GtkTextTag:baseline-shift:
*
* Whether the tag contents should be shifted to superscript or subscript position,
* relative to the previous content. This also changes the font to a smaller size.
*
* Since: 4.6
*/
g_object_class_install_property (object_class,
PROP_BASELINE_SHIFT,
g_param_spec_enum ("baseline-shift",
P_("Baseline Shift"),
P_("Whether to shift the baseline."),
PANGO_TYPE_BASELINE_SHIFT,
PANGO_BASELINE_SHIFT_NONE,
GTK_PARAM_READWRITE));
/**
* GtkTextTag:accumulative-margin:
*
@@ -1121,10 +1102,6 @@ gtk_text_tag_class_init (GtkTextTagClass *klass)
ADD_SET_PROP ("sentence-set", PROP_WORD_SET,
P_("Sentence set"),
P_("Whether this tag represents a single sentence"));
ADD_SET_PROP ("baseline-shift-set", PROP_BASELINE_SHIFT_SET,
P_("Baseline Shift set"),
P_("Whether this tag represents a baseline shift"));
}
static void
@@ -1892,12 +1869,6 @@ gtk_text_tag_set_property (GObject *object,
g_object_notify (object, "sentence-set");
break;
case PROP_BASELINE_SHIFT:
priv->baseline_shift_set = TRUE;
priv->values->baseline_shift = g_value_get_enum (value);
g_object_notify (object, "baseline-shift-set");
break;
case PROP_ACCUMULATIVE_MARGIN:
priv->accumulative_margin = g_value_get_boolean (value);
g_object_notify (object, "accumulative-margin");
@@ -2074,10 +2045,6 @@ gtk_text_tag_set_property (GObject *object,
priv->sentence_set = g_value_get_boolean (value);
break;
case PROP_BASELINE_SHIFT_SET:
priv->baseline_shift_set = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2302,10 +2269,6 @@ gtk_text_tag_get_property (GObject *object,
g_value_set_boolean (value, priv->values->sentence);
break;
case PROP_BASELINE_SHIFT:
g_value_set_boolean (value, priv->values->baseline_shift);
break;
case PROP_ACCUMULATIVE_MARGIN:
g_value_set_boolean (value, priv->accumulative_margin);
break;
@@ -2460,10 +2423,6 @@ gtk_text_tag_get_property (GObject *object,
g_value_set_boolean (value, priv->sentence_set);
break;
case PROP_BASELINE_SHIFT_SET:
g_value_set_boolean (value, priv->baseline_shift_set);
break;
case PROP_BACKGROUND:
case PROP_FOREGROUND:
case PROP_PARAGRAPH_BACKGROUND:
-1
View File
@@ -90,7 +90,6 @@ struct _GtkTextTagPrivate
guint text_transform_set : 1;
guint word_set : 1;
guint sentence_set : 1;
guint baseline_shift_set : 1;
/* Whether these margins accumulate or override */
guint accumulative_margin : 1;
+50 -14
View File
@@ -397,6 +397,8 @@ static void gtk_text_view_css_changed (GtkWidget *widget,
GtkCssStyleChange *change);
static void gtk_text_view_direction_changed (GtkWidget *widget,
GtkTextDirection previous_direction);
static void gtk_text_view_system_setting_changed (GtkWidget *widget,
GtkSystemSetting setting);
static void gtk_text_view_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state);
@@ -573,6 +575,7 @@ static void gtk_text_view_update_im_spot_location (GtkTextView *text_view);
static void gtk_text_view_insert_emoji (GtkTextView *text_view);
static void update_node_ordering (GtkWidget *widget);
static void gtk_text_view_update_pango_contexts (GtkTextView *text_view);
/* GtkTextHandle handlers */
static void gtk_text_view_handle_drag_started (GtkTextHandle *handle,
@@ -819,6 +822,7 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
widget_class->map = gtk_text_view_map;
widget_class->css_changed = gtk_text_view_css_changed;
widget_class->direction_changed = gtk_text_view_direction_changed;
widget_class->system_setting_changed = gtk_text_view_system_setting_changed;
widget_class->state_flags_changed = gtk_text_view_state_flags_changed;
widget_class->measure = gtk_text_view_measure;
widget_class->size_allocate = gtk_text_view_size_allocate;
@@ -4984,7 +4988,6 @@ gtk_text_view_css_changed (GtkWidget *widget,
{
GtkTextView *text_view;
GtkTextViewPrivate *priv;
PangoContext *ltr_context, *rtl_context;
text_view = GTK_TEXT_VIEW (widget);
priv = text_view->priv;
@@ -5001,16 +5004,13 @@ gtk_text_view_css_changed (GtkWidget *widget,
gtk_text_view_set_attributes_from_style (text_view,
priv->layout->default_style);
gtk_text_layout_default_style_changed (priv->layout);
}
ltr_context = gtk_widget_create_pango_context (widget);
pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
rtl_context = gtk_widget_create_pango_context (widget);
pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
gtk_text_layout_set_contexts (priv->layout, ltr_context, rtl_context);
g_object_unref (ltr_context);
g_object_unref (rtl_context);
if ((change == NULL ||
gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_TEXT)) &&
priv->layout)
{
gtk_text_view_update_pango_contexts (text_view);
}
}
@@ -5028,6 +5028,42 @@ gtk_text_view_direction_changed (GtkWidget *widget,
}
}
static void
gtk_text_view_update_pango_contexts (GtkTextView *text_view)
{
GtkWidget *widget = GTK_WIDGET (text_view);
GtkTextViewPrivate *priv = text_view->priv;
gboolean update_ltr, update_rtl;
if (!priv->layout)
return;
update_ltr = gtk_widget_update_pango_context (widget, priv->layout->ltr_context, GTK_TEXT_DIR_LTR);
update_rtl = gtk_widget_update_pango_context (widget, priv->layout->rtl_context, GTK_TEXT_DIR_RTL);
if (update_ltr || update_rtl)
{
GtkTextIter start, end;
gtk_text_buffer_get_bounds (get_buffer (text_view), &start, &end);
gtk_text_layout_invalidate (priv->layout, &start, &end);
gtk_widget_queue_draw (widget);
}
}
static void
gtk_text_view_system_setting_changed (GtkWidget *widget,
GtkSystemSetting setting)
{
if (setting == GTK_SYSTEM_SETTING_DPI ||
setting == GTK_SYSTEM_SETTING_FONT_NAME ||
setting == GTK_SYSTEM_SETTING_FONT_CONFIG)
{
gtk_text_view_update_pango_contexts (GTK_TEXT_VIEW (widget));
}
}
static void
gtk_text_view_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state)
@@ -7809,8 +7845,8 @@ gtk_text_view_ensure_layout (GtkTextView *text_view)
if (priv->layout == NULL)
{
GtkTextAttributes *style;
PangoContext *ltr_context, *rtl_context;
const GList *iter;
PangoContext *ltr_context, *rtl_context;
DV(g_print(G_STRLOC"\n"));
@@ -7843,15 +7879,15 @@ gtk_text_view_ensure_layout (GtkTextView *text_view)
priv->overwrite_mode && priv->editable);
ltr_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
rtl_context = gtk_widget_create_pango_context (GTK_WIDGET (text_view));
pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
gtk_text_layout_set_contexts (priv->layout, ltr_context, rtl_context);
g_object_unref (ltr_context);
g_object_unref (rtl_context);
gtk_text_view_update_pango_contexts (text_view);
gtk_text_view_check_keymap_direction (text_view);
style = gtk_text_attributes_new ();
+38 -21
View File
@@ -572,7 +572,7 @@ static void gtk_widget_pop_verify_invariants (GtkWidget
#define gtk_widget_pop_verify_invariants(widget)
#endif
static PangoContext* gtk_widget_peek_pango_context (GtkWidget *widget);
static void gtk_widget_update_pango_context (GtkWidget *widget);
static void gtk_widget_update_default_pango_context (GtkWidget *widget);
static void gtk_widget_propagate_state (GtkWidget *widget,
const GtkStateData *data);
static gboolean gtk_widget_real_mnemonic_activate (GtkWidget *widget,
@@ -4957,7 +4957,7 @@ gtk_widget_real_css_changed (GtkWidget *widget,
const gboolean has_text = gtk_widget_peek_pango_context (widget) != NULL;
if (has_text && gtk_css_style_change_affects (change, GTK_CSS_AFFECTS_TEXT))
gtk_widget_update_pango_context (widget);
gtk_widget_update_default_pango_context (widget);
if (priv->root)
{
@@ -4980,7 +4980,7 @@ gtk_widget_real_css_changed (GtkWidget *widget,
}
else
{
gtk_widget_update_pango_context (widget);
gtk_widget_update_default_pango_context (widget);
if (priv->root)
gtk_widget_queue_resize (widget);
@@ -4997,7 +4997,7 @@ gtk_widget_real_system_setting_changed (GtkWidget *widget,
setting == GTK_SYSTEM_SETTING_FONT_NAME ||
setting == GTK_SYSTEM_SETTING_FONT_CONFIG)
{
gtk_widget_update_pango_context (widget);
gtk_widget_update_default_pango_context (widget);
if (gtk_widget_peek_pango_context (widget))
gtk_widget_queue_resize (widget);
}
@@ -6427,30 +6427,42 @@ gtk_widget_get_effective_font_map (GtkWidget *widget)
return pango_cairo_font_map_get_default ();
}
static void
update_pango_context (GtkWidget *widget,
PangoContext *context)
gboolean
gtk_widget_update_pango_context (GtkWidget *widget,
PangoContext *context,
GtkTextDirection direction)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GtkCssStyle *style = gtk_css_node_get_style (priv->cssnode);
PangoFontDescription *font_desc;
GtkSettings *settings;
cairo_font_options_t *font_options;
guint old_serial;
old_serial = pango_context_get_serial (context);
font_desc = gtk_css_style_get_pango_font (style);
pango_context_set_font_description (context, font_desc);
pango_font_description_free (font_desc);
if (cairo_version () >= CAIRO_VERSION_ENCODE (1, 17, 4))
pango_context_set_round_glyph_positions (context, FALSE);
settings = gtk_widget_get_settings (widget);
pango_context_set_base_dir (context,
_gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ?
PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL);
if (settings &&
cairo_version () >= CAIRO_VERSION_ENCODE (1, 17, 4))
{
gboolean hint_font_metrics;
g_object_get (settings, "gtk-hint-font-metrics", &hint_font_metrics, NULL);
pango_context_set_round_glyph_positions (context, hint_font_metrics);
}
if (direction != GTK_TEXT_DIR_NONE)
pango_context_set_base_dir (context, direction == GTK_TEXT_DIR_LTR
? PANGO_DIRECTION_LTR
: PANGO_DIRECTION_RTL);
pango_cairo_context_set_resolution (context, _gtk_css_number_value_get (style->core->dpi, 100));
settings = gtk_widget_get_settings (widget);
font_options = (cairo_font_options_t*)g_object_get_qdata (G_OBJECT (widget), quark_font_options);
if (settings && font_options)
{
@@ -6468,15 +6480,20 @@ update_pango_context (GtkWidget *widget,
}
pango_context_set_font_map (context, gtk_widget_get_effective_font_map (widget));
return old_serial != pango_context_get_serial (context);
}
static void
gtk_widget_update_pango_context (GtkWidget *widget)
gtk_widget_update_default_pango_context (GtkWidget *widget)
{
PangoContext *context = gtk_widget_peek_pango_context (widget);
if (context)
update_pango_context (widget, context);
if (!context)
return;
if (gtk_widget_update_pango_context (widget, context, _gtk_widget_get_direction (widget)))
gtk_widget_queue_draw (widget);
}
/**
@@ -6507,7 +6524,7 @@ gtk_widget_set_font_options (GtkWidget *widget,
options ? cairo_font_options_copy (options) : NULL,
(GDestroyNotify)cairo_font_options_destroy);
gtk_widget_update_pango_context (widget);
gtk_widget_update_default_pango_context (widget);
}
}
@@ -6536,7 +6553,7 @@ gtk_widget_set_font_map_recurse (GtkWidget *widget, gpointer user_data)
if (g_object_get_qdata (G_OBJECT (widget), quark_font_map))
return;
gtk_widget_update_pango_context (widget);
gtk_widget_update_default_pango_context (widget);
gtk_widget_forall (widget, gtk_widget_set_font_map_recurse, user_data);
}
@@ -6573,7 +6590,7 @@ gtk_widget_set_font_map (GtkWidget *widget,
g_object_ref (font_map),
g_object_unref);
gtk_widget_update_pango_context (widget);
gtk_widget_update_default_pango_context (widget);
gtk_widget_forall (widget, gtk_widget_set_font_map_recurse, NULL);
}
@@ -6616,7 +6633,7 @@ gtk_widget_create_pango_context (GtkWidget *widget)
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
update_pango_context (widget, context);
gtk_widget_update_pango_context (widget, context, _gtk_widget_get_direction (widget));
pango_context_set_language (context, gtk_get_default_language ());
return context;
@@ -7201,7 +7218,7 @@ gtk_widget_emit_direction_changed (GtkWidget *widget,
GtkTextDirection direction;
GtkStateFlags state;
gtk_widget_update_pango_context (widget);
gtk_widget_update_default_pango_context (widget);
direction = _gtk_widget_get_direction (widget);
+4
View File
@@ -370,6 +370,10 @@ void gtk_widget_update_orientation (GtkWidget *widget,
void gtk_widget_realize_at_context (GtkWidget *widget);
void gtk_widget_unrealize_at_context (GtkWidget *widget);
gboolean gtk_widget_update_pango_context (GtkWidget *widget,
PangoContext *context,
GtkTextDirection direction);
/* inline getters */
static inline GtkWidget *
+40 -28
View File
@@ -1,29 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface domain="gtk40">
<object class="GtkAdjustment" id="scale_adjustment">
<property name="lower">1</property>
<property name="upper">3</property>
<property name="step-increment">1</property>
<property name="page-increment">1</property>
</object>
<object class="GtkAdjustment" id="font_scale_adjustment">
<property name="lower">0.5</property>
<property name="upper">2</property>
<property name="step-increment">0.01</property>
<property name="page-increment">0.01</property>
</object>
<object class="GtkAdjustment" id="slowdown_adjustment">
<property name="lower">-3</property>
<property name="upper">3</property>
<property name="step-increment">1</property>
<property name="page-increment">1</property>
</object>
<object class="GtkAdjustment" id="cursor_size_adjustment">
<property name="lower">16</property>
<property name="upper">128</property>
<property name="step-increment">8</property>
<property name="page-increment">8</property>
</object>
<template class="GtkInspectorVisual" parent="GtkWidget">
<child>
<object class="GtkScrolledWindow" id="swin">
@@ -142,7 +118,14 @@
<property name="valign">baseline</property>
<property name="max-width-chars">2</property>
<property name="width-chars">2</property>
<property name="adjustment">cursor_size_adjustment</property>
<property name="adjustment">
<object class="GtkAdjustment" id="cursor_size_adjustment">
<property name="lower">16</property>
<property name="upper">128</property>
<property name="step-increment">8</property>
<property name="page-increment">8</property>
</object>
</property>
<property name="snap-to-ticks">1</property>
<property name="hexpand">1</property>
</object>
@@ -218,7 +201,14 @@
<child>
<object class="GtkScale" id="font_scale_scale">
<property name="valign">baseline</property>
<property name="adjustment">font_scale_adjustment</property>
<property name="adjustment">
<object class="GtkAdjustment" id="font_scale_adjustment">
<property name="lower">0.5</property>
<property name="upper">2</property>
<property name="step-increment">0.01</property>
<property name="page-increment">0.01</property>
</object>
</property>
<property name="draw-value">0</property>
<property name="hexpand">1</property>
<marks>
@@ -231,6 +221,7 @@
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="width-chars">4</property>
<property name="max-width-chars">4</property>
<property name="input-purpose">number</property>
</object>
</child>
@@ -290,7 +281,14 @@
<object class="GtkSpinButton" id="hidpi_spin">
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="adjustment">scale_adjustment</property>
<property name="adjustment">
<object class="GtkAdjustment" id="scale_adjustment">
<property name="lower">1</property>
<property name="upper">3</property>
<property name="step-increment">1</property>
<property name="page-increment">1</property>
</object>
</property>
<property name="snap-to-ticks">1</property>
<property name="hexpand">1</property>
</object>
@@ -339,7 +337,14 @@
</child>
<child>
<object class="GtkScale" id="slowdown_scale">
<property name="adjustment">slowdown_adjustment</property>
<property name="adjustment">
<object class="GtkAdjustment" id="slowdown_adjustment">
<property name="lower">-3</property>
<property name="upper">3</property>
<property name="step-increment">1</property>
<property name="page-increment">1</property>
</object>
</property>
<property name="valign">baseline</property>
<property name="draw-value">0</property>
<property name="hexpand">1</property>
@@ -353,6 +358,7 @@
<property name="halign">end</property>
<property name="valign">baseline</property>
<property name="width-chars">4</property>
<property name="max-width-chars">4</property>
<property name="input-purpose">number</property>
</object>
</child>
@@ -718,6 +724,12 @@
<widget name="software_gl_label"/>
</widgets>
</object>
<object class="GtkSizeGroup">
<widgets>
<widget name="font_scale_label"/>
<widget name="slowdown_label"/>
</widgets>
</object>
<object class="GtkSizeGroup">
<widgets>
<widget name="theme_combo"/>
-1
View File
@@ -111,7 +111,6 @@ gtk_private_sources = files([
'gtkfilechooserutils.c',
'gtkfilesystemmodel.c',
'gtkgizmo.c',
'gtkhsla.c',
'gtkiconcache.c',
'gtkiconcachevalidator.c',
'gtkiconhelper.c',
+9
View File
@@ -566,6 +566,15 @@ button {
}
}
&.arrow-button {
padding-left: 10px;
padding-right: 10px;
> box {
border-spacing: 4px;
}
}
@at-root %button_basic_drop_active,
&:drop(active) {
color: $drop_target_color;
+23 -8
View File
@@ -11,7 +11,7 @@ project('gtk', 'c',
license: 'LGPL-2.1-or-later')
glib_req = '>= 2.66.0'
pango_req = '>= 1.49.0' # keep this in sync with .gitlab-ci/test-msys.sh
pango_req = '>= 1.49.1' # keep this in sync with .gitlab-ci/test-msys.sh
fribidi_req = '>= 0.19.7'
cairo_req = '>= 1.14.0'
gdk_pixbuf_req = '>= 2.30.0'
@@ -150,11 +150,6 @@ cdata.set_quoted('GTK_DATADIR', gtk_datadir)
cdata.set_quoted('GTK_LIBDIR', gtk_libdir)
cdata.set_quoted('GTK_SYSCONFDIR', gtk_sysconfdir)
cdata.set_quoted('GETTEXT_PACKAGE', 'gtk40')
cdata.set('GTK_MAJOR_VERSION', gtk_major_version)
cdata.set('GTK_MINOR_VERSION', gtk_minor_version)
cdata.set('GTK_MICRO_VERSION', gtk_micro_version)
cdata.set('GTK_BINARY_AGE', gtk_binary_age)
cdata.set('GTK_INTERFACE_AGE', gtk_interface_age)
check_headers = [
'crt/externs.h',
@@ -212,6 +207,17 @@ foreach func : check_functions
endif
endforeach
# We use links() because sigsetjmp() is often a macro hidden behind other macros
cdata.set('HAVE_SIGSETJMP',
cc.links('''#define _POSIX_SOURCE
#include <setjmp.h>
int main (void) {
sigjmp_buf env;
sigsetjmp (env, 0);
return 0;
}''', name: 'sigsetjmp'),
)
# Check for __uint128_t (gcc) by checking for 128-bit division
uint128_t_src = '''int main() {
static __uint128_t v1 = 100;
@@ -394,6 +400,16 @@ pangocairo_dep = dependency('pangocairo', version: pango_req,
pixbuf_dep = dependency('gdk-pixbuf-2.0', version: gdk_pixbuf_req,
fallback : ['gdk-pixbuf', 'gdkpixbuf_dep'],
default_options: ['png=enabled', 'jpeg=enabled', 'builtin_loaders=png,jpeg', 'man=false'])
png_dep = dependency('libpng',
fallback: ['libpng', 'libpng_dep'],
required: true)
tiff_dep = dependency('libtiff-4',
fallback: ['libtiff', 'libtiff4_dep'],
required: true)
jpeg_dep = dependency('libjpeg',
fallback: ['libjpeg-turbo', 'jpeg_dep'],
required: true)
epoxy_dep = dependency('epoxy', version: epoxy_req,
fallback: ['libepoxy', 'libepoxy_dep'])
harfbuzz_dep = dependency('harfbuzz', version: '>= 2.1.0', required: false,
@@ -747,8 +763,7 @@ if get_option('build-examples')
endif
# config.h
configure_file(input: 'config.h.meson',
output: 'config.h',
configure_file(output: 'config.h',
configuration: cdata)
# Requires
+3 -11
View File
@@ -49,17 +49,9 @@ gstgl_dep = dependency('gstreamer-gl-1.0', version: '>= 1.12.3',
if gstplayer_dep.found() and gstgl_dep.found()
extra_win_cflags = []
if host_machine.system() == 'windows'
new_gst_gl_display_code = \
'''#include <gst/gl/gstgldisplay.h>
int main (int a, char ** g) {
GstGLDisplay *d = gst_gl_display_new_with_type (GST_GL_DISPLAY_TYPE_WIN32);
return 0;
}'''
if cc.links(new_gst_gl_display_code, dependencies : gstgl_dep)
message('libgstgl has gst_gl_display_new_with_type()')
extra_win_cflags += '-DHAVE_GST_GL_DISPLAY_NEW_WITH_TYPE'
endif
if host_machine.system() == 'windows' and gstgl_dep.version().version_compare('>=1.19.1')
message('libgstgl has gst_gl_display_new_with_type()')
extra_win_cflags += '-DHAVE_GST_GL_DISPLAY_NEW_WITH_TYPE'
endif
media_backends += 'gstreamer'
+1748 -1710
View File
File diff suppressed because it is too large Load Diff
+1777 -1742
View File
File diff suppressed because it is too large Load Diff
+908 -804
View File
File diff suppressed because it is too large Load Diff
+1382 -1360
View File
File diff suppressed because it is too large Load Diff
+1033 -927
View File
File diff suppressed because it is too large Load Diff
+1740 -1734
View File
File diff suppressed because it is too large Load Diff
+1806 -1759
View File
File diff suppressed because it is too large Load Diff
+549 -537
View File
File diff suppressed because it is too large Load Diff
+1778 -1746
View File
File diff suppressed because it is too large Load Diff
+3156 -3679
View File
File diff suppressed because it is too large Load Diff
+1012 -974
View File
File diff suppressed because it is too large Load Diff
+1136 -1049
View File
File diff suppressed because it is too large Load Diff
+1111 -1063
View File
File diff suppressed because it is too large Load Diff
+1096 -1018
View File
File diff suppressed because it is too large Load Diff
+357 -345
View File
File diff suppressed because it is too large Load Diff
+865 -1545
View File
File diff suppressed because it is too large Load Diff
+4033 -3303
View File
File diff suppressed because it is too large Load Diff
+1158 -1278
View File
File diff suppressed because it is too large Load Diff
+514 -468
View File
File diff suppressed because it is too large Load Diff
+605 -543
View File
File diff suppressed because it is too large Load Diff
+375 -320
View File
File diff suppressed because it is too large Load Diff
+2173 -1412
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
[wrap-file]
directory = libpng-1.6.37
source_url = https://github.com/glennrp/libpng/archive/v1.6.37.tar.gz
source_filename = libpng-1.6.37.tar.gz
source_hash = ca74a0dace179a8422187671aee97dd3892b53e168627145271cad5b5ac81307
patch_url = https://wrapdb.mesonbuild.com/v2/libpng_1.6.37-3/get_patch
patch_filename = libpng-1.6.37-3-wrap.zip
patch_hash = 6c9f32fd9150b3a96ab89be52af664e32207e10aa9f5fb9aa015989ee2dd7100
[provide]
libpng = libpng_dep
+12
View File
@@ -0,0 +1,12 @@
[wrap-file]
directory = tiff-4.1.0
source_url = http://download.osgeo.org/libtiff/tiff-4.1.0.zip
source_filename = tiff-4.1.0.zip
source_hash = 6f3dbed9d2ecfed33c7192b5c01884078970657fa21b4ad28e3cdf3438eb2419
patch_filename = libtiff_4.1.0-4_patch.zip
patch_url = https://wrapdb.mesonbuild.com/v2/libtiff_4.1.0-4/get_patch
patch_hash = c0fe078d06e5a7f2480a96c3897a7b3b9fa9a42c08fb76ae5f1dd59e0519a14e
[provide]
libtiff-4 = libtiff4_dep
+1 -1
View File
@@ -3,7 +3,7 @@
static const char *format_name[] = {
"BGRAp", "ARGBp", "RGBAp",
"BGRA", "ARGB", "RGBA", "ABGR",
"RGB", "BGR",
"RGB", "BGR", NULL
};
static const char *
+23
View File
@@ -0,0 +1,23 @@
a {
color: hsl(0, 0%, 0%);
}
b {
color: hsl(120, 100%, 50%);
}
c {
color: hsl(360, 100%, 50%);
}
d {
color: hsl(-314.159, 50%, 50%);
}
e {
color: hsl(0, 0%, 0%, 0.5);
}
f {
color: hsl(1, 2, 3);
}
+1
View File
@@ -0,0 +1 @@
hsl.css:22:17-18: error: GTK_CSS_PARSER_ERROR_SYNTAX
+19
View File
@@ -0,0 +1,19 @@
a {
color: rgb(0,0,0);
}
b {
color: rgb(0,255,0);
}
c {
color: rgb(255,0,0);
}
d {
color: rgb(191,161,64);
}
e {
color: rgba(0,0,0,0.5);
}
+3
View File
@@ -358,6 +358,9 @@ test_data = [
'freed-string-in-error-messages.css',
'freed-string-in-error-messages.errors',
'freed-string-in-error-messages.ref.css',
'hsl.css',
'hsl.errors',
'hsl.ref.css',
'import-cyclic-1.css',
'import-cyclic-1.errors',
'import-cyclic-1.ref.css',
+70 -1
View File
@@ -30,6 +30,49 @@ compare_rgba_values (GValue *v1, GValue *v2)
(GdkRGBA *)g_value_get_boxed (v2));
}
static gboolean
textures_equal (GdkTexture *t1, GdkTexture *t2)
{
guchar *d1, *d2;
int width, height;
gboolean ret;
width = gdk_texture_get_width (t1);
height = gdk_texture_get_height (t1);
if (width != gdk_texture_get_width (t2))
return FALSE;
if (height != gdk_texture_get_height (t2))
return FALSE;
d1 = g_malloc (width * height * 4);
d2 = g_malloc (width * height * 4);
gdk_texture_download (t1, d1, width * 4);
gdk_texture_download (t2, d2, width * 4);
ret = memcmp (d1, d2, width * height * 4) == 0;
if (!ret)
{
gdk_texture_save_to_png (t1, "texture1.png");
gdk_texture_save_to_png (t2, "texture2.png");
}
g_free (d1);
g_free (d2);
return ret;
}
static gboolean
compare_texture_values (GValue *v1, GValue *v2)
{
return G_VALUE_TYPE (v1) == GDK_TYPE_TEXTURE &&
G_VALUE_TYPE (v2) == GDK_TYPE_TEXTURE &&
textures_equal ((GdkTexture *)g_value_get_object (v1),
(GdkTexture *)g_value_get_object (v2));
}
static gboolean
compare_file_values (GValue *v1, GValue *v2)
{
@@ -125,7 +168,7 @@ test_content_roundtrip (const GValue *value,
TestData data = { 0, };
data.ostream = g_memory_output_stream_new_resizable ();
data.mime_type = g_strdup (mime_type);
data.mime_type = mime_type;
g_value_init (&data.value, G_VALUE_TYPE (value));
g_value_copy (value, &data.value);
data.compare = compare;
@@ -182,6 +225,30 @@ test_content_color (void)
g_value_unset (&value);
}
static void
test_content_texture (gconstpointer data)
{
const char *mimetype = data;
GValue value = G_VALUE_INIT;
char *path;
GFile *file;
GdkTexture *texture;
GError *error = NULL;
path = g_test_build_filename (G_TEST_DIST, "image-data", "image.png", NULL);
file = g_file_new_for_path (path);
texture = gdk_texture_new_from_file (file, &error);
g_assert_no_error (error);
g_object_unref (file);
g_free (path);
g_value_init (&value, GDK_TYPE_TEXTURE);
g_value_set_object (&value, texture);
test_content_roundtrip (&value, mimetype, compare_texture_values);
g_value_unset (&value);
g_object_unref (texture);
}
static void
test_content_file (void)
{
@@ -406,6 +473,8 @@ main (int argc, char *argv[])
g_test_add_func ("/content/text_plain_utf8", test_content_text_plain_utf8);
g_test_add_func ("/content/text_plain", test_content_text_plain);
g_test_add_func ("/content/color", test_content_color);
g_test_add_data_func ("/content/texture/png", "image/png", test_content_texture);
g_test_add_data_func ("/content/texture/tiff", "image/tiff", test_content_texture);
g_test_add_func ("/content/file", test_content_file);
g_test_add_func ("/content/files", test_content_files);
g_test_add_func ("/content/custom", test_custom_format);
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.
+129
View File
@@ -0,0 +1,129 @@
#include <gtk/gtk.h>
#include "gdk/loaders/gdkpngprivate.h"
#include "gdk/loaders/gdktiffprivate.h"
#include "gdk/loaders/gdkjpegprivate.h"
static void
assert_texture_equal (GdkTexture *t1,
GdkTexture *t2)
{
int width;
int height;
int stride;
guchar *d1;
guchar *d2;
width = gdk_texture_get_width (t1);
height = gdk_texture_get_height (t1);
stride = 4 * width;
g_assert_cmpint (width, ==, gdk_texture_get_width (t2));
g_assert_cmpint (height, ==, gdk_texture_get_height (t2));
d1 = g_malloc (stride * height);
d2 = g_malloc (stride * height);
gdk_texture_download (t1, d1, stride);
gdk_texture_download (t2, d2, stride);
g_assert_cmpmem (d1, stride * height, d2, stride * height);
g_free (d1);
g_free (d2);
}
static void
test_load_image (gconstpointer data)
{
const char *filename = data;
GdkTexture *texture;
char *path;
GFile *file;
GBytes *bytes;
GError *error = NULL;
path = g_test_build_filename (G_TEST_DIST, "image-data", filename, NULL);
file = g_file_new_for_path (path);
bytes = g_file_load_bytes (file, NULL, NULL, &error);
g_assert_no_error (error);
if (g_str_has_suffix (filename, ".png"))
texture = gdk_load_png (bytes, &error);
else if (g_str_has_suffix (filename, ".tiff"))
texture = gdk_load_tiff (bytes, &error);
else if (g_str_has_suffix (filename, ".jpeg"))
texture = gdk_load_jpeg (bytes, &error);
else
g_assert_not_reached ();
g_assert_no_error (error);
g_assert_true (GDK_IS_TEXTURE (texture));
g_assert_cmpint (gdk_texture_get_width (texture), ==, 32);
g_assert_cmpint (gdk_texture_get_height (texture), ==, 32);
g_object_unref (texture);
g_bytes_unref (bytes);
g_object_unref (file);
g_free (path);
}
static void
test_save_image (gconstpointer test_data)
{
const char *filename = test_data;
char *path;
GFile *file;
GdkTexture *texture;
GFile *file2;
GdkTexture *texture2;
GError *error = NULL;
GBytes *bytes = NULL;
GIOStream *stream;
path = g_test_build_filename (G_TEST_DIST, "image-data", filename, NULL);
file = g_file_new_for_path (path);
texture = gdk_texture_new_from_file (file, &error);
g_assert_no_error (error);
if (g_str_has_suffix (filename, ".png"))
bytes = gdk_save_png (texture);
else if (g_str_has_suffix (filename, ".tiff"))
bytes = gdk_save_tiff (texture);
else
g_assert_not_reached ();
file2 = g_file_new_tmp ("imageXXXXXX", (GFileIOStream **)&stream, NULL);
g_object_unref (stream);
g_file_replace_contents (file2,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes),
NULL, FALSE, 0,
NULL, NULL, &error);
g_assert_no_error (error);
texture2 = gdk_texture_new_from_file (file2, &error);
g_assert_no_error (error);
assert_texture_equal (texture, texture2);
g_bytes_unref (bytes);
g_object_unref (texture2);
g_object_unref (file2);
g_object_unref (texture);
g_object_unref (file);
g_free (path);
}
int
main (int argc, char *argv[])
{
(g_test_init) (&argc, &argv, NULL);
g_test_add_data_func ("/image/load/png", "image.png", test_load_image);
g_test_add_data_func ("/image/load/tiff", "image.tiff", test_load_image);
g_test_add_data_func ("/image/load/jpeg", "image.jpeg", test_load_image);
g_test_add_data_func ("/image/save/png", "image.png", test_save_image);
g_test_add_data_func ("/image/save/tiff", "image.tiff", test_save_image);
return g_test_run ();
}
+567 -144
View File
@@ -1,57 +1,330 @@
#include <locale.h>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
/* maximum bytes per pixel */
#define MAX_BPP 4
#include "gsk/ngl/gsknglrenderer.h"
#define N 20
static GskRenderer *gl_renderer = NULL;
typedef struct _TextureBuilder TextureBuilder;
typedef enum {
BLUE,
GREEN,
RED,
TRANSPARENT,
ALMOST_OPAQUE_REBECCAPURPLE,
N_COLORS
} Color;
TEXTURE_METHOD_LOCAL,
TEXTURE_METHOD_GL,
TEXTURE_METHOD_GL_RELEASED,
TEXTURE_METHOD_PNG,
TEXTURE_METHOD_TIFF,
const char * color_names[N_COLORS] = {
"blue",
"green",
"red",
"transparent",
"almost_opaque_rebeccapurple"
};
N_TEXTURE_METHODS
} TextureMethod;
typedef struct _MemoryData {
gsize bytes_per_pixel;
guint opaque : 1;
guchar data[N_COLORS][MAX_BPP];
} MemoryData;
typedef struct _TestData {
struct _TextureBuilder
{
GdkMemoryFormat format;
Color color;
} TestData;
int width;
int height;
#define RGBA(a, b, c, d) { 0x ## a, 0x ## b, 0x ## c, 0x ## d }
static MemoryData tests[GDK_MEMORY_N_FORMATS] = {
{ 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(66,22,44,AA) } },
{ 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,44,22,66) } },
{ 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(44,22,66,AA) } },
{ 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(99,33,66,AA) } },
{ 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,66,33,99) } },
{ 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(66,33,99,AA) } },
{ 4, FALSE, { RGBA(FF,FF,00,00), RGBA(FF,00,FF,00), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(AA,99,33,66) } },
{ 3, TRUE, { RGBA(00,00,FF,00), RGBA(00,FF,00,00), RGBA(FF,00,00,00), RGBA(00,00,00,00), RGBA(44,22,66,00) } },
{ 3, TRUE, { RGBA(FF,00,00,00), RGBA(00,FF,00,00), RGBA(00,00,FF,00), RGBA(00,00,00,00), RGBA(66,22,44,00) } },
guchar *pixels;
gsize stride;
gsize offset;
};
static gsize
gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
return 3;
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
return 4;
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16_FLOAT:
return 6;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
return 8;
case GDK_MEMORY_R32G32B32_FLOAT:
return 12;
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
return 16;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
return 4;
}
}
static gboolean
gdk_memory_format_has_alpha (GdkMemoryFormat format)
{
switch (format)
{
case GDK_MEMORY_R8G8B8:
case GDK_MEMORY_B8G8R8:
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16_FLOAT:
case GDK_MEMORY_R32G32B32_FLOAT:
return FALSE;
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
case GDK_MEMORY_B8G8R8A8:
case GDK_MEMORY_A8R8G8B8:
case GDK_MEMORY_R8G8B8A8:
case GDK_MEMORY_A8B8G8R8:
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
return TRUE;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
return TRUE;
}
}
static gpointer
encode (GdkMemoryFormat format,
TextureMethod method)
{
return GSIZE_TO_POINTER (method * GDK_MEMORY_N_FORMATS + format);
}
static void
decode (gconstpointer data,
GdkMemoryFormat *format,
TextureMethod *method)
{
gsize value = GPOINTER_TO_SIZE (data);
*format = value % GDK_MEMORY_N_FORMATS;
value /= GDK_MEMORY_N_FORMATS;
*method = value;
}
static void
texture_builder_init (TextureBuilder *builder,
GdkMemoryFormat format,
int width,
int height)
{
gsize extra_stride;
builder->format = format;
builder->width = width;
builder->height = height;
extra_stride = g_test_rand_bit() ? g_test_rand_int_range (0, 16) : 0;
builder->offset = g_test_rand_bit() ? g_test_rand_int_range (0, 128) : 0;
builder->stride = width * gdk_memory_format_bytes_per_pixel (format) + extra_stride;
builder->pixels = g_malloc0 (builder->offset + builder->stride * height);
}
static GdkTexture *
texture_builder_finish (TextureBuilder *builder)
{
GBytes *bytes;
GdkTexture *texture;
bytes = g_bytes_new_with_free_func (builder->pixels + builder->offset,
builder->height * builder->stride,
g_free,
builder->pixels);
texture = gdk_memory_texture_new (builder->width,
builder->height,
builder->format,
bytes,
builder->stride);
g_bytes_unref (bytes);
return texture;
}
static inline void
set_pixel_u8 (guchar *data,
int r,
int g,
int b,
int a,
gboolean premultiply,
const GdkRGBA *color)
{
if (a >= 0)
data[a] = CLAMP (color->alpha * 256.f, 0.f, 255.f);
if (premultiply)
{
data[r] = CLAMP (color->red * color->alpha * 256.f, 0.f, 255.f);
data[g] = CLAMP (color->green * color->alpha * 256.f, 0.f, 255.f);
data[b] = CLAMP (color->blue * color->alpha * 256.f, 0.f, 255.f);
}
else
{
data[r] = CLAMP (color->red * 256.f, 0.f, 255.f);
data[g] = CLAMP (color->green * 256.f, 0.f, 255.f);
data[b] = CLAMP (color->blue * 256.f, 0.f, 255.f);
}
}
static inline guint16
float_to_half (const float x)
{
const guint b = *(guint*)&x+0x00001000; // round-to-nearest-even
const guint e = (b&0x7F800000)>>23; // exponent
const guint m = b&0x007FFFFF; // mantissa
return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : saturate
}
static void
texture_builder_set_pixel (TextureBuilder *builder,
int x,
int y,
const GdkRGBA *color)
{
guchar *data;
g_assert_cmpint (x, >=, 0);
g_assert_cmpint (x, <, builder->width);
g_assert_cmpint (y, >=, 0);
g_assert_cmpint (y, <, builder->height);
data = builder->pixels
+ builder->offset
+ y * builder->stride
+ x * gdk_memory_format_bytes_per_pixel (builder->format);
switch (builder->format)
{
case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
set_pixel_u8 (data, 2, 1, 0, 3, TRUE, color);
break;
case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
set_pixel_u8 (data, 1, 2, 3, 0, TRUE, color);
break;
case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
set_pixel_u8 (data, 0, 1, 2, 3, TRUE, color);
break;
case GDK_MEMORY_B8G8R8A8:
set_pixel_u8 (data, 2, 1, 0, 3, FALSE, color);
break;
case GDK_MEMORY_A8R8G8B8:
set_pixel_u8 (data, 1, 2, 3, 0, FALSE, color);
break;
case GDK_MEMORY_R8G8B8A8:
set_pixel_u8 (data, 0, 1, 2, 3, FALSE, color);
break;
case GDK_MEMORY_A8B8G8R8:
set_pixel_u8 (data, 3, 2, 1, 0, FALSE, color);
break;
case GDK_MEMORY_R8G8B8:
set_pixel_u8 (data, 0, 1, 2, -1, TRUE, color);
break;
case GDK_MEMORY_B8G8R8:
set_pixel_u8 (data, 2, 1, 0, -1, TRUE, color);
break;
case GDK_MEMORY_R16G16B16:
{
guint16 pixels[3] = {
CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f),
CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f),
CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f),
};
memcpy (data, pixels, 3 * sizeof (guint16));
}
break;
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
{
guint16 pixels[4] = {
CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f),
CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f),
CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f),
CLAMP (color->alpha * 65536.f, 0, 65535.f),
};
memcpy (data, pixels, 4 * sizeof (guint16));
}
break;
case GDK_MEMORY_R16G16B16_FLOAT:
{
guint16 pixels[3] = {
float_to_half (color->red * color->alpha),
float_to_half (color->green * color->alpha),
float_to_half (color->blue * color->alpha)
};
memcpy (data, pixels, 3 * sizeof (guint16));
}
break;
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
{
guint16 pixels[4] = {
float_to_half (color->red * color->alpha),
float_to_half (color->green * color->alpha),
float_to_half (color->blue * color->alpha),
float_to_half (color->alpha)
};
memcpy (data, pixels, 4 * sizeof (guint16));
}
break;
case GDK_MEMORY_R32G32B32_FLOAT:
{
float pixels[3] = {
color->red * color->alpha,
color->green * color->alpha,
color->blue * color->alpha
};
memcpy (data, pixels, 3 * sizeof (float));
}
break;
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
{
float pixels[4] = {
color->red * color->alpha,
color->green * color->alpha,
color->blue * color->alpha,
color->alpha
};
memcpy (data, pixels, 4 * sizeof (float));
}
break;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
break;
}
}
static void
texture_builder_fill (TextureBuilder *builder,
const GdkRGBA *color)
{
int x, y;
for (y = 0; y < builder->height; y++)
for (x = 0; x < builder->width; x++)
texture_builder_set_pixel (builder, x, y, color);
}
static void
compare_textures (GdkTexture *expected,
GdkTexture *test,
gboolean ignore_alpha)
gboolean has_alpha)
{
guchar *expected_data, *test_data;
guint32 *expected_data, *test_data;
int width, height;
int x, y;
@@ -61,20 +334,64 @@ compare_textures (GdkTexture *expected,
width = gdk_texture_get_width (expected);
height = gdk_texture_get_height (expected);
expected_data = g_malloc (width * height * 4);
gdk_texture_download (expected, expected_data, width * 4);
expected_data = g_new (guint32, width * height);
gdk_texture_download (expected, (guchar *) expected_data, width * 4);
test_data = g_malloc (width * height * 4);
gdk_texture_download (test, test_data, width * 4);
test_data = g_new (guint32, width * height);
gdk_texture_download (test, (guchar *) test_data, width * 4);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
if (ignore_alpha)
g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4] & 0xFFFFFF, ==, *(guint32 *) &test_data[y * width + x * 4] & 0xFFFFFF);
if (has_alpha)
g_assert_cmphex (expected_data[y * width + x], ==, test_data[y * width + x]);
else
g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4], ==, *(guint32 *) &test_data[y * width + x * 4]);
g_assert_cmphex (expected_data[y * width + x] | 0xFF000000, ==, test_data[y * width + x]);
}
}
g_free (expected_data);
g_free (test_data);
}
static void
compare_textures_float (GdkTexture *expected,
GdkTexture *test,
float eps,
gboolean has_alpha)
{
static int R = 0;
static int G = 1;
static int B = 2;
static int A = 3;
float *expected_data, *test_data;
int width, height;
int x, y;
g_assert_cmpint (gdk_texture_get_width (expected), ==, gdk_texture_get_width (test));
g_assert_cmpint (gdk_texture_get_height (expected), ==, gdk_texture_get_height (test));
width = gdk_texture_get_width (expected);
height = gdk_texture_get_height (expected);
expected_data = g_new (float, width * height * 4);
gdk_texture_download_float (expected, expected_data, width * 4);
test_data = g_new (float, width * height * 4);
gdk_texture_download_float (test, test_data, width * 4);
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + R], test_data[y * width + 4 * x + R], eps);
g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + G], test_data[y * width + 4 * x + G], eps);
g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + B], test_data[y * width + 4 * x + B], eps);
if (has_alpha)
g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + A], test_data[y * width + 4 * x + A], eps);
else
g_assert_cmpfloat (1.0, ==, test_data[y * width + 4 * x + A]);
}
}
@@ -82,149 +399,255 @@ compare_textures (GdkTexture *expected,
g_free (test_data);
}
static GdkTexture *
upload_to_gl (GdkTexture *texture)
{
GskRenderNode *node;
GdkTexture *result;
if (gl_renderer == NULL)
return texture;
node = gsk_texture_node_new (texture,
&GRAPHENE_RECT_INIT(
0, 0,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture)
));
result = gsk_renderer_render_texture (gl_renderer, node, NULL);
gsk_render_node_unref (node);
g_object_unref (texture);
return result;
}
static GdkTexture *
create_texture (GdkMemoryFormat format,
Color color,
TextureMethod method,
int width,
int height,
gsize stride)
const GdkRGBA *color)
{
TextureBuilder builder;
GdkTexture *texture;
GBytes *bytes;
guchar *data;
int x, y;
data = g_malloc (height * MAX (stride, tests[format].bytes_per_pixel));
for (y = 0; y < height; y++)
for (x = 0; x < width; x++)
texture_builder_init (&builder, format, width, height);
texture_builder_fill (&builder, color);
texture = texture_builder_finish (&builder);
switch (method)
{
case TEXTURE_METHOD_LOCAL:
break;
case TEXTURE_METHOD_GL:
texture = upload_to_gl (texture);
break;
case TEXTURE_METHOD_GL_RELEASED:
texture = upload_to_gl (texture);
gdk_gl_texture_release (GDK_GL_TEXTURE (texture));
break;
case TEXTURE_METHOD_PNG:
{
memcpy (&data[y * stride + x * tests[format].bytes_per_pixel],
&tests[format].data[color],
tests[format].bytes_per_pixel);
GBytes *bytes = gdk_texture_save_to_png_bytes (texture);
g_assert (bytes);
g_object_unref (texture);
texture = gdk_texture_new_from_bytes (bytes, NULL);
g_assert (texture);
g_bytes_unref (bytes);
}
break;
bytes = g_bytes_new_take (data, height * MAX (stride, tests[format].bytes_per_pixel));
texture = gdk_memory_texture_new (width, height,
format,
bytes,
stride);
g_bytes_unref (bytes);
case TEXTURE_METHOD_TIFF:
{
GBytes *bytes = gdk_texture_save_to_tiff_bytes (texture);
g_assert (bytes);
g_object_unref (texture);
texture = gdk_texture_new_from_bytes (bytes, NULL);
g_assert (texture);
g_bytes_unref (bytes);
}
break;
case N_TEXTURE_METHODS:
default:
g_assert_not_reached ();
break;
}
return texture;
}
static void
test_download_1x1 (gconstpointer data)
create_random_color (GdkRGBA *color)
{
const TestData *test_data = data;
GdkTexture *expected, *test;
expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, tests[test_data->format].bytes_per_pixel);
test = create_texture (test_data->format, test_data->color, 1, 1, tests[test_data->format].bytes_per_pixel);
compare_textures (expected, test, tests[test_data->format].opaque);
g_object_unref (expected);
g_object_unref (test);
/* Generate colors so that premultiplying will result in values in steps of 1/15th */
color->red = g_test_rand_int_range (0, 6) / 5.f;
color->green = g_test_rand_int_range (0, 6) / 5.f;
color->blue = g_test_rand_int_range (0, 6) / 5.f;
color->alpha = g_test_rand_int_range (0, 4) / 3.f;
}
static void
test_download_1x1_with_stride (gconstpointer data)
test_download_1x1 (gconstpointer data)
{
const TestData *test_data = data;
GdkMemoryFormat format;
TextureMethod method;
GdkTexture *expected, *test;
gsize i;
expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, 4);
test = create_texture (test_data->format, test_data->color, 1, 1, 2 * MAX_BPP);
decode (data, &format, &method);
compare_textures (expected, test, tests[test_data->format].opaque);
for (i = 0; i < N; i++)
{
GdkRGBA color;
g_object_unref (expected);
g_object_unref (test);
create_random_color (&color);
expected = create_texture (GDK_MEMORY_DEFAULT, TEXTURE_METHOD_LOCAL, 1, 1, &color);
test = create_texture (format, method, 1, 1, &color);
compare_textures (expected, test, gdk_memory_format_has_alpha (format));
g_object_unref (expected);
g_object_unref (test);
}
}
static void
test_download_4x4 (gconstpointer data)
{
const TestData *test_data = data;
GdkMemoryFormat format;
TextureMethod method;
GdkTexture *expected, *test;
gsize i;
expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16);
test = create_texture (test_data->format, test_data->color, 4, 4, 4 * tests[test_data->format].bytes_per_pixel);
decode (data, &format, &method);
compare_textures (expected, test, tests[test_data->format].opaque);
for (i = 0; i < N; i++)
{
GdkRGBA color;
g_object_unref (expected);
g_object_unref (test);
create_random_color (&color);
expected = create_texture (GDK_MEMORY_DEFAULT, TEXTURE_METHOD_LOCAL, 4, 4, &color);
test = create_texture (format, method, 4, 4, &color);
compare_textures (expected, test, gdk_memory_format_has_alpha (format));
g_object_unref (expected);
g_object_unref (test);
}
}
static void
test_download_4x4_with_stride (gconstpointer data)
{
const TestData *test_data = data;
GdkTexture *expected, *test;
expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16);
test = create_texture (test_data->format, test_data->color, 4, 4, 4 * MAX_BPP);
compare_textures (expected, test, tests[test_data->format].opaque);
g_object_unref (expected);
g_object_unref (test);
}
int
main (int argc, char *argv[])
test_download_float_1x1 (gconstpointer data)
{
GdkMemoryFormat format;
Color color;
GEnumClass *enum_class;
TextureMethod method;
GdkTexture *expected, *test;
gsize i;
(g_test_init) (&argc, &argv, NULL);
decode (data, &format, &method);
for (i = 0; i < N; i++)
{
GdkRGBA color;
create_random_color (&color);
expected = create_texture (GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, TEXTURE_METHOD_LOCAL, 1, 1, &color);
test = create_texture (format, method, 1, 1, &color);
compare_textures_float (expected, test,
G_MINFLOAT,
gdk_memory_format_has_alpha (format));
g_object_unref (expected);
g_object_unref (test);
}
}
static void
test_download_float_4x4 (gconstpointer data)
{
GdkMemoryFormat format;
TextureMethod method;
GdkTexture *expected, *test;
gsize i;
decode (data, &format, &method);
for (i = 0; i < N; i++)
{
GdkRGBA color;
create_random_color (&color);
expected = create_texture (GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, TEXTURE_METHOD_LOCAL, 4, 4, &color);
test = create_texture (format, method, 4, 4, &color);
compare_textures_float (expected, test, G_MINFLOAT, gdk_memory_format_has_alpha (format));
g_object_unref (expected);
g_object_unref (test);
}
}
static void
add_test (const char *name,
GTestDataFunc func)
{
GdkMemoryFormat format;
TextureMethod method;
GEnumClass *enum_class;
enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT);
for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
{
for (color = 0; color < N_COLORS; color++)
for (method = 0; method < N_TEXTURE_METHODS; method++)
{
TestData *test_data = g_new (TestData, 1);
char *test_name = g_strdup_printf ("/memorytexture/download_1x1/%s/%s",
const char *method_names[N_TEXTURE_METHODS] = { "local", "gl", "gl-released", "png", "tiff" };
char *test_name = g_strdup_printf ("%s/%s/%s",
name,
g_enum_get_value (enum_class, format)->value_nick,
color_names[color]);
test_data->format = format;
test_data->color = color;
g_test_add_data_func_full (test_name, test_data, test_download_1x1, g_free);
g_free (test_name);
test_data = g_new (TestData, 1);
test_name = g_strdup_printf ("/memorytexture/download_1x1_with_stride/%s/%s",
g_enum_get_value (enum_class, format)->value_nick,
color_names[color]);
test_data->format = format;
test_data->color = color;
g_test_add_data_func_full (test_name, test_data, test_download_1x1_with_stride, g_free);
g_free (test_name);
test_data = g_new (TestData, 1);
test_name = g_strdup_printf ("/memorytexture/download_4x4/%s/%s",
g_enum_get_value (enum_class, format)->value_nick,
color_names[color]);
test_data->format = format;
test_data->color = color;
g_test_add_data_func_full (test_name, test_data, test_download_4x4, g_free);
g_free (test_name);
test_data = g_new (TestData, 1);
test_name = g_strdup_printf ("/memorytexture/download_4x4_with_stride/%s/%s",
g_enum_get_value (enum_class, format)->value_nick,
color_names[color]);
test_data->format = format;
test_data->color = color;
g_test_add_data_func_full (test_name, test_data, test_download_4x4_with_stride, g_free);
method_names[method]);
g_test_add_data_func_full (test_name, encode (format, method), test_download_1x1, NULL);
g_free (test_name);
}
}
return g_test_run ();
}
int
main (int argc, char *argv[])
{
GdkSurface *surface;
int result;
gtk_test_init (&argc, &argv, NULL);
add_test ("/memorytexture/download_1x1", test_download_1x1);
add_test ("/memorytexture/download_4x4", test_download_4x4);
add_test ("/memorytexture/download_float_1x1", test_download_float_1x1);
add_test ("/memorytexture/download_float_4x4", test_download_float_4x4);
surface = gdk_surface_new_toplevel (gdk_display_get_default());
gl_renderer = gsk_ngl_renderer_new ();
if (!gsk_renderer_realize (gl_renderer, surface, NULL))
{
g_clear_object (&gl_renderer);
g_clear_object (&surface);
}
result = g_test_run ();
if (gl_renderer)
{
gsk_renderer_unrealize (gl_renderer);
g_clear_object (&gl_renderer);
}
g_clear_object (&surface);
return result;
}
+27
View File
@@ -26,6 +26,7 @@ tests = [
'rgba',
'seat',
'texture',
'texture-threads',
]
foreach t : tests
@@ -48,6 +49,31 @@ foreach t : tests
)
endforeach
internal_tests = [
'image'
]
foreach t : internal_tests
test_exe = executable(t, '@0@.c'.format(t),
c_args: common_cflags,
dependencies: libgtk_static_dep,
install: get_option('install-tests'),
install_dir: testexecdir,
)
test(t, test_exe,
args: [ '--tap', '-k' ],
protocol: 'tap',
env: [
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
'DBUS_SESSION_BUS_ADDRESS=',
],
suite: 'gdk',
)
endforeach
if get_option('install-tests')
foreach t : tests
test_cdata = configuration_data()
@@ -62,4 +88,5 @@ if get_option('install-tests')
endforeach
install_subdir('clipboard-data', install_dir: testexecdir)
install_subdir('image-data', install_dir: testexecdir)
endif
+24
View File
@@ -65,6 +65,30 @@ test_color_parse (void)
res = gdk_rgba_parse (&color, "#0080ff88");
g_assert_true (res);
g_assert_true (gdk_rgba_equal (&color, &expected));
expected.red = 1.0;
expected.green = 0.0;
expected.blue = 0.0;
expected.alpha = 1.0;
res = gdk_rgba_parse (&color, "hsl (0, 100%, 50%)");
g_assert_true (res);
g_assert_true (gdk_rgba_equal (&color, &expected));
expected.red = 0.0;
expected.green = 1.0;
expected.blue = 0.0;
expected.alpha = 0.1;
res = gdk_rgba_parse (&color, "hsla (120, 255, 50%, 0.1)");
g_assert_true (res);
g_assert_true (gdk_rgba_equal (&color, &expected));
expected.red = 0.0;
expected.green = 0.5;
expected.blue = 0.5;
expected.alpha = 1.0;
res = gdk_rgba_parse (&color, "hsl(180, 100%, 25%)");
g_assert_true (res);
g_assert_true (gdk_rgba_equal (&color, &expected));
}
static void
+103
View File
@@ -0,0 +1,103 @@
#include <gtk/gtk.h>
#include "gsk/ngl/gsknglrenderer.h"
/* This function will be called from a thread and/or the main loop.
* Textures are threadsafe after all. */
static void
ensure_texture_access (GdkTexture *texture)
{
/* Make sure to initialize the pixel to anything but red */
guint32 pixel = 0;
float float_pixel[4] = { INFINITY, INFINITY, INFINITY, INFINITY };
/* Just to be sure */
g_assert_cmpint (gdk_texture_get_width (texture), ==, 1);
g_assert_cmpint (gdk_texture_get_height (texture), ==, 1);
/* download the pixel */
gdk_texture_download (texture, (guchar *) &pixel, 4);
gdk_texture_download_float (texture, float_pixel, 4);
/* check the pixel is now red */
g_assert_cmphex (pixel, ==, 0xFFFF0000);
g_assert_cmpfloat (float_pixel[0], ==, 1.0);
g_assert_cmpfloat (float_pixel[1], ==, 0.0);
g_assert_cmpfloat (float_pixel[2], ==, 0.0);
g_assert_cmpfloat (float_pixel[3], ==, 1.0);
}
static void
texture_download_done (GObject *texture,
GAsyncResult *res,
gpointer loop)
{
ensure_texture_access (GDK_TEXTURE (texture));
g_main_loop_quit (loop);
}
static void
texture_download_thread (GTask *task,
gpointer texture,
gpointer unused,
GCancellable *cancellable)
{
ensure_texture_access (GDK_TEXTURE (texture));
g_task_return_boolean (task, TRUE);
}
static void
texture_threads (void)
{
GdkSurface *surface;
GskRenderer *gl_renderer;
GskRenderNode *node;
GMainLoop *loop;
GdkTexture *texture;
GTask *task;
/* 1. Get a GL renderer */
surface = gdk_surface_new_toplevel (gdk_display_get_default());
gl_renderer = gsk_ngl_renderer_new ();
g_assert_true (gsk_renderer_realize (gl_renderer, surface, NULL));
/* 2. Get a GL texture */
node = gsk_color_node_new (&(GdkRGBA) { 1, 0, 0, 1 }, &GRAPHENE_RECT_INIT(0, 0, 1, 1));
texture = gsk_renderer_render_texture (gl_renderer, node, &GRAPHENE_RECT_INIT(0, 0, 1, 1));
gsk_render_node_unref (node);
/* 3. This is a bit fishy, but we want to make sure that
* the texture's GL context is current in the main thread.
*
* If we had access to the context, we'd make_current() here.
*/
ensure_texture_access (texture);
g_assert_nonnull (gdk_gl_context_get_current ());
/* 4. Run a thread trying to download the texture */
loop = g_main_loop_new (NULL, TRUE);
task = g_task_new (texture, NULL, texture_download_done, loop);
g_task_run_in_thread (task, texture_download_thread);
g_clear_object (&task);
/* 5. Run the main loop waiting for the thread to return */
g_main_loop_run (loop);
/* 6. All good */
gsk_renderer_unrealize (gl_renderer);
g_clear_pointer (&loop, g_main_loop_unref);
g_clear_object (&gl_renderer);
g_clear_object (&surface);
}
int
main (int argc, char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/texture-threads", texture_threads);
return g_test_run ();
}
+45 -9
View File
@@ -32,6 +32,23 @@ test_constants (void)
}
}
static float
random_representable_float (void)
{
guint16 h[4];
float f[4];
do
{
/* generate a random float thats representable as fp16 */
memset (h, 0, sizeof (h));
h[0] = g_random_int_range (G_MININT16, G_MAXINT16);
half_to_float4 (h, f);
}
while (!isnormal (f[0])); /* skip nans and infs since they don't compare well */
return f[0];
}
static void
test_roundtrip (void)
{
@@ -41,15 +58,7 @@ test_roundtrip (void)
float f2[4];
guint16 h[4];
do
{
/* generate a random float thats representable as fp16 */
memset (h, 0, sizeof (h));
h[0] = g_random_int_range (G_MININT16, G_MAXINT16);
half_to_float4 (h, f2);
}
while (!isnormal (f2[0])); /* skip nans and infs since they don't compare well */
f2[0] = random_representable_float ();
memset (f, 0, sizeof (f));
f[0] = f2[0];
@@ -60,6 +69,32 @@ test_roundtrip (void)
}
}
/* Test that the array version work as expected,
* in particular with unaligned boundaries.
*/
static void
test_many (void)
{
for (int i = 0; i < 100; i++)
{
int size = g_random_int_range (100, 200);
int offset = g_random_int_range (0, 20);
guint16 *h = g_new0 (guint16, size);
float *f = g_new0 (float, size);
float *f2 = g_new0 (float, size);
for (int j = offset; j < size; j++)
f[j] = random_representable_float ();
float_to_half (f + offset, h + offset, size - offset);
half_to_float (h + offset, f2 + offset, size - offset);
for (int j = offset; j < size; j++)
g_assert_cmpfloat (f[j], ==, f2[j]);
}
}
int
main (int argc, char *argv[])
{
@@ -67,6 +102,7 @@ main (int argc, char *argv[])
g_test_add_func ("/half-float/constants", test_constants);
g_test_add_func ("/half-float/roundtrip", test_roundtrip);
g_test_add_func ("/half-float/many", test_many);
return g_test_run ();
}
@@ -1,7 +1,6 @@
texture {
bounds: 0 0 50 50;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABmJLR0QA/wD/AP+gvaeTAAAAKUlE\
QVQYlWP8z3DmPwMaYGQwYUQXY0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5C\
YII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAClJREFUGJVj\
/M9w5j8DGmBkMGFEF2NCF8AFBlAhhqMZGBgYsHlwKHgGAM+OBd3t1NcVAAAAAElFTkSuQmCC\
");
}
+259 -259
View File
@@ -39,129 +39,129 @@ transform {
offset: 0.180392 0.203922 0.211765 0;
child: texture {
bounds: 1068.6 0 256 256;
texture: url("data:image/png;base64,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\
texture: url("data:image/png;base64,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\
YRiGYRiGIfw/xkuszVpN0tYAAAAASUVORK5CYII=\
");
}
}
@@ -277,8 +277,8 @@ GIZhGIZhGIZhGIYh/D/GS6zNWk3S1gAAAABJRU5ErkJggg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 4 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAH0lE\
QVQ4jWNgGPKAEY3/n1R9TNRzy0CB0TAYDQOqAADB/QMKPEUKLAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAB9JREFUOI1j\
YBjygBGN/59UfUzUc8tAgdEwGA0DqgAAwf0DCjxFCiwAAAAASUVORK5CYII=\
");
}
}
@@ -294,10 +294,10 @@ QVQ4jWNgGPKAEY3/n1R9TNRzy0CB0TAYDQOqAADB/QMKPEUKLAAAAABJRU5ErkJggg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAfUlE\
QVQ4je3RMQoCMRBG4Q+voEIKC/H+d7Cwd1GULSzEUyg2azOyQ1gxB9gHgcnknxdCmJliwAHr1Fti\
H2d/uUTwHJIVuuj1LYINbklyivqObYuglgx4YDcVXPwQvPFM+1esJgquxjf3qS4tgmM1UJKkaxF8\
g/m2YvyJmYoPk2IlW2Wofj0AAAAASUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAH1JREFUOI3t\
0TEKAjEQRuEPr6BCCgvx/newsHdRlC0sxFMoNmszskNYMQfYB4HJ5J8XQpiZYsAB69RbYh9nf7lE\
8BySFbro9S2CDW5Jcor6jm2LoJYMeGA3FVz8ELzxTPtXrCYKrsY396kuLYJjNVCSpGsRfIP5tmL8\
iZmKD5NiJVtlqH49AAAAAElFTkSuQmCC\
");
}
}
@@ -373,9 +373,9 @@ transform {
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAOklE\
QVQ4jWNgGAWDD5QzMDD8J4DrKTGEoGZ8hhCtGZshODUz4zHgKAMDAyMDA8NBBgaGRlJtHwUkAACH\
ZRnQomjWaAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOI1j\
YBgFgw+UMzAw/CeA6ykxhKBmfIYQrRmbITg1M+Mx4CgDAwMjAwPDQQYGhkZSbR8FJAAAh2UZ0KJo\
1mgAAAAASUVORK5CYII=\
");
}
}
@@ -430,9 +430,9 @@ ZRnQomjWaAAAAABJRU5ErkJggg==\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAOklE\
QVQ4jWNgGAWDD5QzMDD8J4DrKTGEoGZ8hhCtGZshODUz4zHgKAMDAyMDA8NBBgaGRlJtHwUkAACH\
ZRnQomjWaAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOI1j\
YBgFgw+UMzAw/CeA6ykxhKBmfIYQrRmbITg1M+Mx4CgDAwMjAwPDQQYGhkZSbR8FJAAAh2UZ0KJo\
1mgAAAAASUVORK5CYII=\
");
}
}
@@ -473,11 +473,11 @@ ZRnQomjWaAAAAABJRU5ErkJggg==\
offset: 0.654902 0.666667 0.666667 0;
child: texture {
bounds: 0 8 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAyklE\
QVQ4jc3S3UpCURAF4K8w8ypQA1EfpkcI8SmEEh9STYzQQNCE3sELiQiiLhy1I/ucbl0wDHt+Fmv2\
DOeGCh4xxic2eIrYVdSM8JNqbmMeyZS9oPnnnUEZr5FY4h63aKCDdeSe8wgGEXxDNaGujvcTRRns\
mTuJ5v3Mp5bBRwQbCYK8PwGl8N/hvxIEF4nYAZfhF+HvioqL8BCyVqgl8jVM5ewfrjGLgjW6uAnr\
Oq5xWqSi5XgLeYfU+m+UMvqYYGt3ykP0QuUZ4hei9keg1mtPrwAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAMpJREFUOI3N\
0t1KQlEQBeCvMPMqUANRH6ZHCPEphBIfUk2M0EDQhN7BC4kIoi4ctSP7nG5dMAx7fhZr9gznhgoe\
McYnNniK2FXUjPCTam5jHsmUvaD5551BGa+RWOIet2igg3XknvMIBhF8QzWhro73E0UZ7Jk7ieb9\
zKeWwUcEGwmCvD8BpfDf4b8SBBeJ2AGX4Rfh74qKi/AQslaoJfI1TOXsH64xi4I1urgJ6zqucVqk\
ouV4C3mH1PpvlDL6mGBrd8pD9ELlGeIXovZHoNZrT68AAAAASUVORK5CYII=\
");
}
}
@@ -557,10 +557,10 @@ Oq5xWqSi5XgLeYfU+m+UMvqYYGt3ykP0QuUZ4hei9keg1mtPrwAAAABJRU5ErkJggg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 4 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAfUlE\
QVQ4je3RMQoCMRBG4Q+voEIKC/H+d7Cwd1GULSzEUyg2azOyQ1gxB9gHgcnknxdCmJliwAHr1Fti\
H2d/uUTwHJIVuuj1LYINbklyivqObYuglgx4YDcVXPwQvPFM+1esJgquxjf3qS4tgmM1UJKkaxF8\
g/m2YvyJmYoPk2IlW2Wofj0AAAAASUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAH1JREFUOI3t\
0TEKAjEQRuEPr6BCCgvx/newsHdRlC0sxFMoNmszskNYMQfYB4HJ5J8XQpiZYsAB69RbYh9nf7lE\
8BySFbro9S2CDW5Jcor6jm2LoJYMeGA3FVz8ELzxTPtXrCYKrsY396kuLYJjNVCSpGsRfIP5tmL8\
iZmKD5NiJVtlqH49AAAAAElFTkSuQmCC\
");
}
}
@@ -600,9 +600,9 @@ g/m2YvyJmYoPk2IlW2Wofj0AAAAASUVORK5CYII=\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAOklE\
QVQ4jWNgGAWDD5QzMDD8J4DrKTGEoGZ8hhCtGZshODUz4zHgKAMDAyMDA8NBBgaGRlJtHwUkAACH\
ZRnQomjWaAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOI1j\
YBgFgw+UMzAw/CeA6ykxhKBmfIYQrRmbITg1M+Mx4CgDAwMjAwPDQQYGhkZSbR8FJAAAh2UZ0KJo\
1mgAAAAASUVORK5CYII=\
");
}
}
@@ -638,9 +638,9 @@ ZRnQomjWaAAAAABJRU5ErkJggg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAOklE\
QVQ4jWNgGAWDD5QzMDD8J4DrKTGEoGZ8hhCtGZshODUz4zHgKAMDAyMDA8NBBgaGRlJtHwUkAACH\
ZRnQomjWaAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOI1j\
YBgFgw+UMzAw/CeA6ykxhKBmfIYQrRmbITg1M+Mx4CgDAwMjAwPDQQYGhkZSbR8FJAAAh2UZ0KJo\
1mgAAAAASUVORK5CYII=\
");
}
}
@@ -679,9 +679,9 @@ ZRnQomjWaAAAAABJRU5ErkJggg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAOklE\
QVQ4jWNgGAWDD5QzMDD8J4DrKTGEoGZ8hhCtGZshODUz4zHgKAMDAyMDA8NBBgaGRlJtHwUkAACH\
ZRnQomjWaAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOI1j\
YBgFgw+UMzAw/CeA6ykxhKBmfIYQrRmbITg1M+Mx4CgDAwMjAwPDQQYGhkZSbR8FJAAAh2UZ0KJo\
1mgAAAAASUVORK5CYII=\
");
}
}
@@ -747,8 +747,8 @@ ZRnQomjWaAAAAABJRU5ErkJggg==\
offset: 0.615686 0.623529 0.623529 0;
child: texture {
bounds: 4 8 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAHElE\
QVQ4jWNgGAXDADCi8f+Tqo+Jem4ZBUMYAABDXwEEvj+CVwAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAABxJREFUOI1j\
YBgFwwAwovH/k6qPiXpuGQVDGAAAQ18BBL4/glcAAAAASUVORK5CYII=\
");
}
}
@@ -767,9 +767,8 @@ QVQ4jWNgGAXDADCi8f+Tqo+Jem4ZBUMYAABDXwEEvj+CVwAAAABJRU5ErkJggg==\
offset: 0.615686 0.623529 0.623529 0;
child: texture {
bounds: 4 8 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAKElE\
QVQ4jWNgGPbgPxTjBEyU2jDwBjCi8fH6F5s+il1ACIyEWBgGAADypgUMy1PhdwAAAABJRU5ErkJg\
gg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAChJREFUOI1j\
YBj24D8U4wRMlNow8AYwovHx+hebPopdQAiMhFgYBgAA8qYFDMtT4XcAAAAASUVORK5CYII=\
");
}
}
@@ -819,8 +818,8 @@ gg==\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 4 8 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAHElE\
QVQ4jWNgGAXDADCi8f+Tqo+Jem4ZBUMYAABDXwEEvj+CVwAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAABxJREFUOI1j\
YBgFwwAwovH/k6qPiXpuGQVDGAAAQ18BBL4/glcAAAAASUVORK5CYII=\
");
}
}
@@ -846,9 +845,8 @@ QVQ4jWNgGAXDADCi8f+Tqo+Jem4ZBUMYAABDXwEEvj+CVwAAAABJRU5ErkJggg==\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 4 8 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAKElE\
QVQ4jWNgGPbgPxTjBEyU2jDwBjCi8fH6F5s+il1ACIyEWBgGAADypgUMy1PhdwAAAABJRU5ErkJg\
gg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAChJREFUOI1j\
YBj24D8U4wRMlNow8AYwovHx+hebPopdQAiMhFgYBgAA8qYFDMtT4XcAAAAASUVORK5CYII=\
");
}
}
@@ -881,10 +879,10 @@ gg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 0 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAeElE\
QVQokb3QXwpAQBDH8e9uzscRXEXyJFE8KFoXcxheVm1j0Cp+tQ87M5/2D/yc8g2qgC0GGKDzSIUp\
YBXUB+gEC19cAmyAQaAmRJloOiABJlGv5WnWD4dDq9i32tuOa41i+FiT719Gw/MT0rDj/Mu3sUAe\
i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAHhJREFUKJG9\
0F8KQEAQx/Hvbs7HEVxF8iRRPChaF3MYXlZtY9AqfrUPOzOf9g/8nPINqoAtBhig80iFKWAV1Afo\
BAtfXAJsgEGgJkSZaDogASZRr+Vp1g+HQ6vYt9rbjmuNYvhYk+9fRsPzE9Kw4/zLt7FAHou+yw6e\
9iu4wGcfbQAAAABJRU5ErkJggg==\
");
}
}
@@ -947,9 +945,9 @@ i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 0 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAOUlE\
QVQokWNgGAVEAW8GBoYnDAwM/3HgxwwMDF7YND7GowmGH8EUM1HDqV4EbH3EwMDgSQ2Lhj0AABu4\
GmjkhFgCAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAADlJREFUKJFj\
YBgFRAFvBgaGJwwMDP9x4McMDAxe2DQ+xqMJhh/BFDNRw6leBGx9xMDA4EkNi4Y9AAAbuBpo5IRY\
AgAAAABJRU5ErkJggg==\
");
}
}
@@ -985,10 +983,10 @@ GmjkhFgCAAAAAElFTkSuQmCC\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 0 0 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAeElE\
QVQokb3QXwpAQBDH8e9uzscRXEXyJFE8KFoXcxheVm1j0Cp+tQ87M5/2D/yc8g2qgC0GGKDzSIUp\
YBXUB+gEC19cAmyAQaAmRJloOiABJlGv5WnWD4dDq9i32tuOa41i+FiT719Gw/MT0rDj/Mu3sUAe\
i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAHhJREFUKJG9\
0F8KQEAQx/Hvbs7HEVxF8iRRPChaF3MYXlZtY9AqfrUPOzOf9g/8nPINqoAtBhig80iFKWAV1Afo\
BAtfXAJsgEGgJkSZaDogASZRr+Vp1g+HQ6vYt9rbjmuNYvhYk+9fRsPzE9Kw4/zLt7FAHou+yw6e\
9iu4wGcfbQAAAABJRU5ErkJggg==\
");
}
}
@@ -1051,9 +1049,9 @@ i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 0 0 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAOUlE\
QVQokWNgGAVEAW8GBoYnDAwM/3HgxwwMDF7YND7GowmGH8EUM1HDqV4EbH3EwMDgSQ2Lhj0AABu4\
GmjkhFgCAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAADlJREFUKJFj\
YBgFRAFvBgaGJwwMDP9x4McMDAxe2DQ+xqMJhh/BFDNRw6leBGx9xMDA4EkNi4Y9AAAbuBpo5IRY\
AgAAAABJRU5ErkJggg==\
");
}
}
@@ -1152,9 +1150,9 @@ GmjkhFgCAAAAAElFTkSuQmCC\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 0 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAOUlE\
QVQokWNgGAVEAW8GBoYnDAwM/3HgxwwMDF7YND7GowmGH8EUM1HDqV4EbH3EwMDgSQ2Lhj0AABu4\
GmjkhFgCAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAADlJREFUKJFj\
YBgFRAFvBgaGJwwMDP9x4McMDAxe2DQ+xqMJhh/BFDNRw6leBGx9xMDA4EkNi4Y9AAAbuBpo5IRY\
AgAAAABJRU5ErkJggg==\
");
}
}
@@ -1193,9 +1191,9 @@ GmjkhFgCAAAAAElFTkSuQmCC\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 0 0 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAASklE\
QVQokWNgGJmAjYGBoZWBgeERFLcwMDCwEqOxlYGB4T8abiZG42MsGh+iK2LCovE/MWLYNC4iUgwD\
sDJA/PQQihsZiAyc4QYASeYTs7b/ALUAAAAASUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAEpJREFUKJFj\
YBiZgI2BgaGVgYHhERS3MDAwsBKjsZWBgeE/Gm4mRuNjLBofoitiwqLxPzFi2DQuIlIMA7AyQPz0\
EIobGYgMnOEGAEnmE7O2/wC1AAAAAElFTkSuQmCC\
");
}
}
@@ -1264,9 +1262,9 @@ sDJA/PQQihsZiAyc4QYASeYTs7b/ALUAAAAASUVORK5CYII=\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 0 0 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAOUlE\
QVQokWNgGAVEAW8GBoYnDAwM/3HgxwwMDF7YND7GowmGH8EUM1HDqV4EbH3EwMDgSQ2Lhj0AABu4\
GmjkhFgCAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAADlJREFUKJFj\
YBgFRAFvBgaGJwwMDP9x4McMDAxe2DQ+xqMJhh/BFDNRw6leBGx9xMDA4EkNi4Y9AAAbuBpo5IRY\
AgAAAABJRU5ErkJggg==\
");
}
}
@@ -1292,13 +1290,13 @@ GmjkhFgCAAAAAElFTkSuQmCC\
transform: translate(8, 11.5) rotate(12.2788) translate(-8, -11.5);
child: texture {
bounds: 0 3.5 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABE0lE\
QVQ4jbXSPy9DURjH8U9bSqhEmog/A6PFJGGRCInRZrQZTN6B1XsysJgMRklJDRYGtVBtWkRr6HOb\
G2muRuJJbnJynvP9nt9zc/iHKuEIZ3jEFeaHhbfwgO6P73AYeAftAfANFn+Dp1FLQffYx8yw0Y9T\
8B3mMs6OoYh8evMSnRDsZcCFkJf1fraRaCygFevzDEE3JBMYRSMR1CPaVwYsYk/Fup1swC2e0MBG\
hqAcgtlI0hecxjgNHKRuSVcRKyHJi5EL0axiNxodrEWiFsaxhE1MBvOOCjq51A3rOMFrSNp4RhMv\
+AhhHRfR6yeg9+4rWE0J8sjhLQTNgGsJlE6QVAnbWI65mzFOFdf4HMD8vb4BZVRHF0lPimAAAAAA\
SUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAARNJREFUOI21\
0j8vQ1EYx/FPW0qoRJqIPwOjxSRhkQiJ0Wa0GUzegdV7MrCYDEZJSQ0WBrVQbVpEa+hzmxtprkbi\
SW5ycp7z/Z7fc3P4hyrhCGd4xBXmh4W38IDuj+9wGHgH7QHwDRZ/g6dRS0H32MfMsNGPU/Ad5jLO\
jqGIfHrzEp0Q7GXAhZCX9X62kWgsoBXr8wxBNyQTGEUjEdQj2lcGLGJPxbqdbMAtntDARoagHILZ\
SNIXnMY4DRykbklXESshyYuRC9GsYjcaHaxFohbGsYRNTAbzjgo6udQN6zjBa0jaeEYTL/gIYR0X\
0esnoPfuK1hNCfLI4S0EzYBrCZROkFQJ21iOuZsxThXX+BzA/L2+AWVURxdJT4pgAAAAAElFTkSu\
QmCC\
");
}
}
@@ -1315,13 +1313,13 @@ SUVORK5CYII=\
transform: translate(8, 11.5) rotate(12.2788) translate(-8, -11.5);
child: texture {
bounds: 0 3.5 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABE0lE\
QVQ4jbXSPy9DURjH8U9bSqhEmog/A6PFJGGRCInRZrQZTN6B1XsysJgMRklJDRYGtVBtWkRr6HOb\
G2muRuJJbnJynvP9nt9zc/iHKuEIZ3jEFeaHhbfwgO6P73AYeAftAfANFn+Dp1FLQffYx8yw0Y9T\
8B3mMs6OoYh8evMSnRDsZcCFkJf1fraRaCygFevzDEE3JBMYRSMR1CPaVwYsYk/Fup1swC2e0MBG\
hqAcgtlI0hecxjgNHKRuSVcRKyHJi5EL0axiNxodrEWiFsaxhE1MBvOOCjq51A3rOMFrSNp4RhMv\
+AhhHRfR6yeg9+4rWE0J8sjhLQTNgGsJlE6QVAnbWI65mzFOFdf4HMD8vb4BZVRHF0lPimAAAAAA\
SUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAARNJREFUOI21\
0j8vQ1EYx/FPW0qoRJqIPwOjxSRhkQiJ0Wa0GUzegdV7MrCYDEZJSQ0WBrVQbVpEa+hzmxtprkbi\
SW5ycp7z/Z7fc3P4hyrhCGd4xBXmh4W38IDuj+9wGHgH7QHwDRZ/g6dRS0H32MfMsNGPU/Ad5jLO\
jqGIfHrzEp0Q7GXAhZCX9X62kWgsoBXr8wxBNyQTGEUjEdQj2lcGLGJPxbqdbMAtntDARoagHILZ\
SNIXnMY4DRykbklXESshyYuRC9GsYjcaHaxFohbGsYRNTAbzjgo6udQN6zjBa0jaeEYTL/gIYR0X\
0esnoPfuK1hNCfLI4S0EzYBrCZROkFQJ21iOuZsxThXX+BzA/L2+AWVURxdJT4pgAAAAAElFTkSu\
QmCC\
");
}
}
@@ -1459,9 +1457,9 @@ SUVORK5CYII=\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAOklE\
QVQ4jWNgGAWDD5QzMDD8J4DrKTGEoGZ8hhCtGZshODUz4zHgKAMDAyMDA8NBBgaGRlJtHwUkAACH\
ZRnQomjWaAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOI1j\
YBgFgw+UMzAw/CeA6ykxhKBmfIYQrRmbITg1M+Mx4CgDAwMjAwPDQQYGhkZSbR8FJAAAh2UZ0KJo\
1mgAAAAASUVORK5CYII=\
");
}
}
@@ -1500,9 +1498,9 @@ ZRnQomjWaAAAAABJRU5ErkJggg==\
offset: 0.831373 0.811765 0.792157 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAOklE\
QVQ4jWNgGAWDD5QzMDD8J4DrKTGEoGZ8hhCtGZshODUz4zHgKAMDAyMDA8NBBgaGRlJtHwUkAACH\
ZRnQomjWaAAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOI1j\
YBgFgw+UMzAw/CeA6ykxhKBmfIYQrRmbITg1M+Mx4CgDAwMjAwPDQQYGhkZSbR8FJAAAh2UZ0KJo\
1mgAAAAASUVORK5CYII=\
");
}
}
@@ -1615,10 +1613,10 @@ ZRnQomjWaAAAAABJRU5ErkJggg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 0 4 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAeUlE\
QVQ4jcWTQQqAIBBFn9HV6i4uOmaL7hF1hVbZRkF0tMmCPnwYdeahH4RcM+AEH4AV+jNJw8EnMGkB\
pf0MsiRDd4AAsdKBFhAywSTN8doIkBgGYLpKk0qvAVB+s0q9AHuk/zP4BLD7uiXIFWD0Re0TSd6A\
of3uXhd1yT8mvMGiQgAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAHlJREFUOI3F\
k0EKgCAQRZ/R1eouLjpmi+4RdYVW2UZBdLTJgj58GHXmoR+EXDPgBB+AFfozScPBJzBpAaX9DLIk\
Q3eAALHSgRYQMsEkzfHaCJAYBmC6SpNKrwFQfrNKvQB7pP8z+ASw+7olyBVg9EXtE0negKH97l4X\
dck/JrzBokIAAAAASUVORK5CYII=\
");
}
}
@@ -2087,19 +2085,21 @@ of3uXhd1yT8mvMGiQgAAAABJRU5ErkJggg==\
transform: translate(225, -10);
child: texture {
bounds: 1 1 20 25;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAZCAYAAAAxFw7TAAAABmJLR0QA/wD/AP+gvaeTAAAChklE\
QVQ4jbXVTWsTQRgH8P88u2myu4ZEKVJqEj9Ar0V6kIQtPRWs1EpAPfegiFD8Av0C4sVbz1qt2IMe\
fUmTXhTzKbKbEhRslrCzsyYz46Ev1jRNX4L/47Dz22eGmXkYBqReryc6nfaSaZoPtMYNpdRlADAM\
7CrFvgHypeNkN6enp7v9c1n/QKVSuUuEF6lUys5mM2nLcpBImACAbrcLzjmCIOjEsQgB/bhYnH03\
ENR6lba33WdEbHly8ppj2/ag4g8TRRzNph9KqdaKxepTxlbVP2C1WnmeTCaXC4WCQ2QMxQ6ilESj\
0QjjOF4rldwVACAAqNW+LBkGnQsDACID+XzBMQxa3tr6vAgArF6vJzjvNHK5wsRpyzwpnIfwfX9H\
Sn2dwrB9J5lMnrpnw2LbDsbGxtKMqUVizLyfyWTTF9b2k8lk04Zh3CPG1Mwo1R3EcRxojRnSGlnT\
TIwMmqYJpeQVUgqMHTveFwtjDEREu91ub2Ss1+uBiLUJYN+jiI8Mcs6hNX0lrbvrQRB0RgWDoN1R\
qveGxsd/vRVCRKNUyXmEOBaC83iTpqbKv7VWK81mM1RKnhuTUmJnxwsB+WR+fj4mACiVZl8pJdd9\
3+eAPgen0Wz6XCn5qlicew3sPw57f8JDIcSW53nh2VANz2tEcSyqUrJHB6OHoOu6vVbrx0IU8U+N\
RoNrPQzV8H2PCxFVLevSbdd1D88dHf2sXC7LVuvnkhDRR887Cd3DOOfblpVe6G8DA+/IxsaGMTFx\
dTOVSs3l8wX771XS8DwviiJes+30rTP1lH7UslJzuVzBBgDfH44NBYG97sd554NtOze11iSEqFmW\
cyJ2KngEfQ8Atn18z/57/gBelEdqMNUvpgAAAABJRU5ErkJggg==\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAZCAYAAAAxFw7TAAAAAXNSR0IArs4c6QAAAvFJREFUOI2t\
1c9r02AYB/DnTd60Td7Mdk06Z0FFrJhsdnhwoujamwqi4qZ40OsmsoF4U3ccKlLdEPwT/MHQ7WiR\
Wl2jh3TbYSJjk2VOelgug1prUl1/vB5GpZ2tutXvKQTeDw8vD98XQY1gjLlQqKvn+PFjFxVFOUgI\
aQYAsO1v6dnZuWQsFnusae/GC4VCfv1ZtP5HOBw+d+3a1Ydut1vw+7c18TwBjsMAAJDP58G2bTBN\
M5vJfLFGRh4MJBLaWOV5tvzBMIgZGBgY7uvrHVIUtdnv9ztdLh5YlgWEECCEgGUxuFw8+Hw+pyRJ\
YjC47+SWLW7f9PR0jFKgVWB/f/9wT093r6qqxOFw1rqJqnAcB7IsO1paWoKiKMqTk1Mvf4HhcKjn\
8uXeIVVVCcOwf5Yq7wsx4PV6HbLsDS4tfZ5LpVLzCGPMPX8+muro2N8qCMI/Y5WxbQtmZmaWz5+/\
sJMJhY52u91uslkMAEAQCHg8nqaurqNn2b6+3tudnQc7XC5+0yAAAMacc3X1B2ba29VDjUxXDiEE\
2traDjGEiB6MuYZBjDGIIvEylAJCv6335oIQAsayrHQ+X2gYKxQKYFnWF2Z+/uNULmc3DNq2DbOz\
czrz6lXsqWma2UZB01zOxuPxUWZiIvEsk8nkGpnStnOQzX79rmlvx9lSqVRcWVlZbm9vOyHLsgMh\
ZkNYsViEhYV56969+1cMY/E9CwDw6dPSh9bWrbtkWVYkSeJqtFqdUDCMBfvFi+iTR4+e3AGoaBtd\
T0YVZe9hnuf9kiQ5/o5SMIyFnK4nE0NDty5RSktVIKW0FI+/Hg0EdncSQnZ4vRJXf0HXJtN1Xbtx\
Y/BMsVj8tXdVXUUppW/eTDwLBHYfEMV6aBlLvr1+ffD0+mfgt/Iro3v2BDoJIdurUQqGYeTWsJun\
ar0pNdu0EhXFNRQAYHHRyOm6rtXD6oJlNJHQxlRVOSII/LZ0Ol1MJpN/xP4pGGMuErkbjUTuRvH/\
qKWN5ichVT1RK2aa7gAAAABJRU5ErkJggg==\
");
}
}
@@ -2442,10 +2442,10 @@ cyJ2KngEfQ8Atn18z/57/gBelEdqMNUvpgAAAABJRU5ErkJggg==\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 14 29 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAeElE\
QVQokb3QXwpAQBDH8e9uzscRXEXyJFE8KFoXcxheVm1j0Cp+tQ87M5/2D/yc8g2qgC0GGKDzSIUp\
YBXUB+gEC19cAmyAQaAmRJloOiABJlGv5WnWD4dDq9i32tuOa41i+FiT719Gw/MT0rDj/Mu3sUAe\
i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAHhJREFUKJG9\
0F8KQEAQx/Hvbs7HEVxF8iRRPChaF3MYXlZtY9AqfrUPOzOf9g/8nPINqoAtBhig80iFKWAV1Afo\
BAtfXAJsgEGgJkSZaDogASZRr+Vp1g+HQ6vYt9rbjmuNYvhYk+9fRsPzE9Kw4/zLt7FAHou+yw6e\
9iu4wGcfbQAAAABJRU5ErkJggg==\
");
}
}
@@ -2459,12 +2459,12 @@ i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
offset: 0.196078 0.196078 0.196078 0;
child: texture {
bounds: 54 28 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAA8klE\
QVQ4jbXSwSrEURTH8Y/YsZiUhfIGnkFJUrKSlIeQJ5AaUlPWdrKUJ9DMwhMQyZKVhSxEg7Lwz1i4\
f925c/9jSk7dbuee8/3dczqHf7BxbOEcL3jFFeqY/A1exBM6FecZq1XwPD76wOUpMJvCY3gYAO7g\
CCOpwMaA8CGGc+W3Msmnib+PoYjpErpNkhvhfTf4ewlcw0kscBPBx0l1S4k/hWvf4/2xZiRQYC3X\
J6ZxF/Iu48B60kJOZEb3jmzHwVHc9xFZxnsUa2MiLW9O7yIVOAh3+faJlYoWLeBR70jjnyvh0mrY\
xFkA3nCBnVzZf7Yvt2xyJ4TFGjYAAAAASUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAPJJREFUOI21\
0sEqxFEUx/GP2LGYlIXyBp5BSVKykpSHkCeQGlJT1naylCfQzMITEMmSlYUsRIOy8M9YuH/duXP/\
Y0pO3W7nnvP93XM6h3+wcWzhHC94xRXqmPwNXsQTOhXnGatV8Dw++sDlKTCbwmN4GADu4AgjqcDG\
gPAhhnPltzLJp4m/j6GI6RK6TZIb4X03+HsJXMNJLHATwcdJdUuJP4Vr3+P9sWYkUGAt1yemcRfy\
LuPAetJCTmRG945sx8FR3PcRWcZ7FGtjIi1vTu8iFTgId/n2iZWKFi3gUe9I458r4dJq2MRZAN5w\
gZ1c2X+2L7dscieExRo2AAAAAElFTkSuQmCC\
");
}
}
@@ -2520,11 +2520,11 @@ xFkA3nCBnVzZf7Yvt2xyJ4TFGjYAAAAASUVORK5CYII=\
offset: 0.196078 0.196078 0.196078 0;
child: texture {
bounds: 54 51 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAAz0lE\
QVQ4jbXSTU4CQRAF4A/iFlbKOVywMoRDGLyAe70D4o3kBqz9uQAXICxwcM2wmAY6Y3djjL6kku7q\
qtevfvgHDPCMd3wFe8MsvBVxhwp1xipMSsm7VsIYw5ZvlyIZZH4+oO3/xBV0Q8Ajeufqi9DHQ+z4\
SPxSUlBrGnvE9hcEVVxCHPxT1HARLktcJ4JG6GQIljHBPEOwKCh4iS+5Md4EFW3/BpecerDCve+9\
6CZKqEPsOiVrolmS3CpvcFsoC82GPeFVM95tOE8Psv8Ue0ISW4s5Tmr/AAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAM9JREFUOI21\
0k1OAkEQBeAP4hZWyjlcsDKEQxi8gHu9A+KN5Aas/bkAFyAscHDNsJgGOmN3Y4y+pJLu6qrXr374\
BwzwjHd8BXvDLLwVcYcKdcYqTErJu1bCGMOWb5ciGWR+PqDt/8QVdEPAI3rn6ovQx0Ps+Ej8UlJQ\
axp7xPYXBFVcQhz8U9RwES5LXCeCRuhkCJYxwTxDsCgoeIkvuTHeBBVt/waXnHqwwr3vvegmSqhD\
7Dola6JZktwqb3BbKAvNhj3hVTPebThPD7L/FHtCEluLOU5q/wAAAABJRU5ErkJggg==\
");
}
}
@@ -2575,10 +2575,10 @@ SPxSUlBrGnvE9hcEVVxCHPxT1HARLktcJ4JG6GQIljHBPEOwKCh4iS+5Md4EFW3/BpecerDCve+9\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 14 75 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAAeElE\
QVQokb3QXwpAQBDH8e9uzscRXEXyJFE8KFoXcxheVm1j0Cp+tQ87M5/2D/yc8g2qgC0GGKDzSIUp\
YBXUB+gEC19cAmyAQaAmRJloOiABJlGv5WnWD4dDq9i32tuOa41i+FiT719Gw/MT0rDj/Mu3sUAe\
i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAHhJREFUKJG9\
0F8KQEAQx/Hvbs7HEVxF8iRRPChaF3MYXlZtY9AqfrUPOzOf9g/8nPINqoAtBhig80iFKWAV1Afo\
BAtfXAJsgEGgJkSZaDogASZRr+Vp1g+HQ6vYt9rbjmuNYvhYk+9fRsPzE9Kw4/zLt7FAHou+yw6e\
9iu4wGcfbQAAAABJRU5ErkJggg==\
");
}
}
@@ -2592,12 +2592,12 @@ i77LDp72K7jAZx9tAAAAAElFTkSuQmCC\
offset: 0.196078 0.196078 0.196078 0;
child: texture {
bounds: 54 74 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAA/klE\
QVQ4jaXTzypFURTH8Q9CN2FyXYmRjqmpiZkykoF0n+J6Bxl4CQ/gASTlAZjwApIRMhDiSkd0Dc6W\
3bHPPcmv1mCv/Vvf/W9t/qmBRG4aHYzhNORecIML5LF5qFTcxjFWcYQnDKKBFjI8hyBMxsX7mAzj\
u8TuhrGMuTJgBnsl4FsCQHHsJYzGgC1MJIxVGsFCDFhLmMrAsmZjQJYwzNcAxmPAZ8KwXgPoxYCr\
hCHDYh9ANwYcVJg6aFbMXfNz0y1cCucq6QG7uI1yOQ6Rf3fiq6JNN/1+vgZW8BFWfccJHlPb2lC0\
b68i7hVN1FdN7OBc8Ym6OMM2puqK/6wvIccweWvwsr0AAAAASUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAP5JREFUOI2l\
088qRVEUx/EPQjdhcl2JkY6pqYmZMpKBdJ/iegcZeAkP4AEk5QGY8AKSETIQ4kpHdA3Olt2xzz3J\
r9Zgr/1b3/1vbf6pgURuGh2M4TTkXnCDC+SxeahU3MYxVnGEJwyigRYyPIcgTMbF+5gM47vE7oax\
jLkyYAZ7JeBbAkBx7CWMxoAtTCSMVRrBQgxYS5jKwLJmY0CWMMzXAMZjwGfCsF4D6MWAq4Qhw2If\
QDcGHFSYOmhWzF3zc9MtXArnKukBu7iNcjkOkX934quiTTf9fr4GVvARVn3HCR5T29pQtG+vIu4V\
TdRXTezgXPGJujjDNqbqiv+sLyHHMHlr8LK9AAAAAElFTkSuQmCC\
");
}
}
@@ -2659,9 +2659,9 @@ b68i7hVN1FdN7OBc8Ym6OMM2puqK/6wvIccweWvwsr0AAAAASUVORK5CYII=\
offset: 0.572549 0.584314 0.584314 0;
child: texture {
bounds: 14 98 14 14;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAABmJLR0QA/wD/AP+gvaeTAAAASklE\
QVQokWNgGJmAjYGBoZWBgeERFLcwMDCwEqOxlYGB4T8abiZG42MsGh+iK2LCovE/MWLYNC4iUgwD\
sDJA/PQQihsZiAyc4QYASeYTs7b/ALUAAAAASUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAAXNSR0IArs4c6QAAAEpJREFUKJFj\
YBiZgI2BgaGVgYHhERS3MDAwsBKjsZWBgeE/Gm4mRuNjLBofoitiwqLxPzFi2DQuIlIMA7AyQPz0\
EIobGYgMnOEGAEnmE7O2/wC1AAAAAElFTkSuQmCC\
");
}
}
@@ -2675,14 +2675,14 @@ sDJA/PQQihsZiAyc4QYASeYTs7b/ALUAAAAASUVORK5CYII=\
offset: 0.196078 0.196078 0.196078 0;
child: texture {
bounds: 54 97 16 16;
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAABT0lE\
QVQ4jZXTv0vXcRDH8cdXzQQTEZFCUVAU1xZ/LCIYrrVkoTi6NLTpX+DoGrTnkoMgqOjk8hXBhqbA\
MALTSB1EpDQp/DF874Nvv4hfPTg4uHu+7n13n0+52+01/mAYu/hdov6atWIBS+i4D1iHSXzBRfgn\
vMWDUnAnfiZgsa+h+iawEhX4fAuc+TuUBwNe4BgHSdEpevG/KL7ACX4E8xw20Y+xRGAzxL8XxVn+\
FbqwAUeowkBS8Bft+FcUZ/mnMcZuDrPIxUzdmMMytvAL52hAE/owGq86REUOtZjAXixxCD1oxuMQ\
2MdOXOFj7KQRU9ki67F4hwtkPoMaia1EYv0O8CrOYnRlCl9Xfwh9xXgInSYNjpHHG3wLbjB9wXzS\
IY8RtMVodWhR+LHySd2HVOARpmNhpUY4w3s8pHC+1JrxEs+i65MQ3cO2qytsZcAlA5qEWoLbkBcA\
AAAASUVORK5CYII=\
texture: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAU9JREFUOI2V\
079L13EQx/HHV80EExGRQlFQFNcWfywiGK61ZKE4ujS06V/g6Bq055KDIKjo5PIVwYamwDAC00gd\
RKQ0KfwxfO+Db7+IXz04OLh7vu59d59PudvtNf5gGLv4XaL+mrViAUvouA9Yh0l8wUX4J7zFg1Jw\
J34mYLGvofomsBIV+HwLnPk7lAcDXuAYB0nRKXrxvyi+wAl+BPMcNtGPsURgM8S/F8VZ/hW6sAFH\
qMJAUvAX7fhXFGf5pzHGbg6zyMVM3ZjDMrbwC+doQBP6MBqvOkRFDrWYwF4scQg9aMbjENjHTlzh\
Y+ykEVPZIuuxeIcLZD6DGomtRGL9DvAqzmJ0ZQpfV38IfcV4CJ0mDY6Rxxt8C24wfcF80iGPEbTF\
aHVoUfix8kndh1TgEaZjYaVGOMN7PKRwvtSa8RLPouuTEN3DtqsrbGXAJQOahFqC25AXAAAAAElF\
TkSuQmCC\
");
}
}
+6 -1
View File
@@ -104,7 +104,12 @@ buffer_diff_core (const guchar *buf_a,
/* check if the pixels are the same */
if (row_a[x] == row_b[x])
continue;
/* even if they're not literally the same, fully-transparent
* pixels are effectively the same regardless of colour */
if ((row_a[x] & 0xff000000) == 0 && (row_b[x] & 0xff000000) == 0)
continue;
if (diff == NULL)
{
diff = cairo_image_surface_create (CAIRO_FORMAT_RGB24,

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