Compare commits

...

243 Commits

Author SHA1 Message Date
Matthias Clasen 7b68ef7669 widget-factory: Precompile the ui file
It doesn't make a huge amount of difference, unfortunately.
2021-09-19 20:19:34 -04:00
Matthias Clasen 11b9b1759a buildertool: Add a compile command
This converts the ui file into our internal, precompiled,
format. The widget-factory.ui file shrinks from 200k to 45k.
But sadly, the loading time only shrinks from 240ms to 235.
2021-09-19 20:19:34 -04:00
Emin Tufan Çetin 6474c7af35 Update Turkish translation 2021-09-19 17:22:22 +00:00
Emin Tufan Çetin 145a16ff81 Update Turkish translation 2021-09-19 17:18:57 +00:00
Matthias Clasen f079d75d1f Merge branch 'resource-cleanup' into 'master'
Clean up gesture icons

See merge request GNOME/gtk!3978
2021-09-19 12:53:59 +00:00
Matthias Clasen e1facc548a resources: Treat svgs as xml
They can have their whitespace removed just the same.
2021-09-19 08:27:08 -04:00
Matthias Clasen 87e4a542eb Clean up gesture icons
These had duplicate drawing in them, and were
saved with all the extra Inkscape data.
2021-09-19 08:27:08 -04:00
Matthias Clasen 56e6a51ac0 Merge branch 'delayed-loading' into 'master'
gtk-demo: Cosmetics

See merge request GNOME/gtk!3975
2021-09-18 23:02:00 +00:00
Matthias Clasen da115ad075 Use GtkLoader for image loading
This avoids blocking on image loading while
we have better things to do.
2021-09-18 17:35:00 -04:00
Matthias Clasen 4a89cfe2c9 Add delayed loading for textures
Add a private GdkPaintable implementation that
loads a texture in a thread, and does not show
anything until the texture is loaded. This avoid
blocking on image loading in the main thread.
2021-09-18 17:35:00 -04:00
Matthias Clasen c9135546b6 loaders: Add profiler marks
These are potentially expensive calls, we
should make sure they show up in profiles.
2021-09-18 17:35:00 -04:00
Jordi Mas a94e438a29 Update Catalan translation 2021-09-18 21:15:31 +02:00
Matthias Clasen 164443a99a builder: Cosmetics 2021-09-18 14:14:55 -04:00
Matthias Clasen d88c4d122d gtk-demo: Cosmetics
Tweak the color of the outlines in the font rendering
demo.
2021-09-18 11:08:15 -04:00
Matthias Clasen d66bc501a4 Merge branch 'wip/baedert/for-master' into 'master'
label: Remove redundant store

Closes #4196

See merge request GNOME/gtk!3891
2021-09-18 15:04:09 +00:00
Timm Bäder 1c2c356ed4 widget factory: Scale down jpeg images 2021-09-18 16:48:48 +02:00
Piotr Drąg 1fae91d123 Update POTFILES.in 2021-09-18 13:12:42 +02:00
Timm Bäder 24415a6ffb cssimageurl: Explicitly check for local_error != NULL
This should always be the case since gdk_texture_new_from_file should
always set the error when it returns NULL, but make it explicit anyway.
2021-09-18 13:08:46 +02:00
Timm Bäder ae08aa3622 constraintsolver: Remove a dead assignment 2021-09-18 12:53:41 +02:00
Timm Bäder c24b7877a0 gdktiff: Use guint32 instead of int32
The latter seems to be deprecated.
2021-09-18 09:00:16 +02:00
Matthias Clasen 7b22e37371 Merge branch 'transform-work' into 'master'
transform: Add sections

See merge request GNOME/gtk!3974
2021-09-18 06:35:08 +00:00
Timm Bäder c2ab1f172d window: Fix mnemonics-visible getter+setter annotations 2021-09-18 08:29:18 +02:00
Timm Bäder 136a3f6e5a stackswitcher: Expand child buttons
Fixes #4196
2021-09-18 08:29:18 +02:00
Timm Bäder 2bc82da34d inspector: Cache if we have ever constructed a window
Silly optimization to get rid of

gtk_main_do_event
  gtk_inspector_handle_event
    gtk_inspector_window_get_for_display
      g_object_get_data

showing up in profiles even though it's useless since we've never even
created any inspector window in the first place.
2021-09-18 08:29:18 +02:00
Matthias Clasen 41b810da7f Add gsk_transform_to_2d_components
This function decomposes a general 2D transform
into skew, scale, rotation and translation.

Tests included.
2021-09-18 02:06:51 -04:00
Matthias Clasen 155e0f3dfb Merge branch 'gbsneto/fix-filechooserwidget-choices' into 'master'
File chooser choice fixes

See merge request GNOME/gtk!3973
2021-09-18 03:59:52 +00:00
Georges Basile Stavracas Neto 02bb23486f filechooserwidget: Return an id in get_choice()
gtk_file_chooser_widget_get_choice() is supposed to return the option
id of the choice, but it currently is returning the option label.

Return the option id instead.
2021-09-18 00:22:05 -03:00
Georges Basile Stavracas Neto bc0d9488ee filechooserwidget: Match choice id from "options"
When choices are added to the file chooser widget, the options of
that choice are stored object data under the "options" key. However,
gtk_file_chooser_widget_set_choice() was checking for "choices".

Retrieve the options from the "options" key stored data object data.
2021-09-18 00:20:42 -03:00
Matthias Clasen 5742483422 Add more transform tests
Test gsk_transform_to_2d.
2021-09-17 22:37:08 -04:00
Matthias Clasen 7f2cb1138a Merge branch 'static-analysis-fixes' into 'master'
label: Remove a dead assignment

See merge request GNOME/gtk!3972
2021-09-18 02:22:21 +00:00
Matthias Clasen 1289e68931 gsk: Add skew transforms
Add gsk_transform_skew() to make our transform
api more complete wrt to what you would expect
for a graphics api.
2021-09-17 22:07:26 -04:00
Matthias Clasen 9e6adaa913 transform: Add sections
This makes the code easier to navigate (for me).
2021-09-17 22:07:26 -04:00
Matthias Clasen 9cfce67d0f textview: Remove a dead store
Pointed out by clang.
2021-09-17 22:06:21 -04:00
Matthias Clasen 295d406207 listitemmanager: Add a few assertions
This might help poor static analyzers.
2021-09-17 22:06:21 -04:00
Matthias Clasen ece5fd7db5 Merge branch 'more-glyph-drawing-fixes' into 'master'
ngl: Use exact device scales for glyphs

See merge request GNOME/gtk!3971
2021-09-18 00:26:14 +00:00
Matthias Clasen c4e558da46 imcontextsimple: Rewrite a function slightly
This hopefully avoids upsetting static analyis.
2021-09-17 20:02:12 -04:00
Matthias Clasen be1a60d5d0 label: Remove a dead assignment
It may have quieted gcc at some point, but
it upsets clang nowadays. Remove it.
2021-09-17 19:54:16 -04:00
Matthias Clasen a1adaac69b Merge branch 'glyph-clipping-fixes' into 'master'
gtk-demo: Improve ink extents rendering

See merge request GNOME/gtk!3969
2021-09-17 23:31:41 +00:00
Matthias Clasen 7e4b2b971f Revert "gsk: Stop enlarging text bounding boxes"
This reverts commit 87af45403a.

I've found that this change is needed to ensure that the
bounding boxes of text nodes encompass all the glyphd drawing.
Without it, we overdraw the widget boundaries and cut off
glyphs.
2021-09-17 19:11:06 -04:00
Matthias Clasen c6cacd2b2d ngl: Use exact device scales for glyphs
We are rendering the glyphs on a larger surface,
and we should avoid introducing unnecessary
rounding errors here. Also, I've found that
we always need to enlarge the surface by one
pixels in each direction to avoid cutting off
the tops of large glyphs.
2021-09-17 19:07:55 -04:00
Matthias Clasen 2c8e55605b gtk-demo: Improve ink extents rendering
Show the pixel-aligned ink rectangle, so we can
see that it includes all the pixels that are inked.
2021-09-17 16:29:30 -04:00
Matthias Clasen 06db477847 gtk-demo: Fix non-circular buttons 2021-09-17 15:24:26 -04:00
Matthias Clasen e9cf8c6cc7 Merge branch 'glyph-clipping-fixes' into 'master'
gsk: Stop enlarging text bounding boxes

See merge request GNOME/gtk!3968
2021-09-17 18:35:41 +00:00
Matthias Clasen aad6b2d279 Merge branch 'wip/otte/for-master' into 'master'
icontheme: Fix variable mixup leading to crashes

Closes #4269

See merge request GNOME/gtk!3967
2021-09-17 18:06:30 +00:00
Benjamin Otte cf3830704b icontheme: Fix variable mixup leading to crashes
Note: Don't have 2 variables named "icon" and "gicon", you will screw
them up.

reftests included.

Fixes #4269
2021-09-17 17:41:13 +00:00
Matthias Clasen d962360fa0 Fix glyph cache entry sizing
The subpixel-positioned glyph extends on both sides.
2021-09-17 13:38:29 -04:00
Matthias Clasen 76d31ff04b Merge branch 'menu_button_a11y_improvements' into 'master'
Set correct accessible relations for GtkMenuButton

Closes #4254

See merge request GNOME/gtk!3950
2021-09-17 16:51:52 +00:00
Matthias Clasen 87af45403a gsk: Stop enlarging text bounding boxes
This should not be necessary and only serves
to make the actual bugs harder to find.
2021-09-17 12:37:36 -04:00
Emmanuele Bassi 15ffd49efb Apply 4 suggestion(s) to 1 file(s) 2021-09-17 16:26:00 +00:00
Matthias Clasen 37a54eb9fc Merge branch 'matthiasc/for-master' into 'master'
gsk: Add a test for transform_bounds

See merge request GNOME/gtk!3966
2021-09-17 16:22:04 +00:00
Matthias Clasen 63647cace0 testsuite: Run the clipboard test in isolation
We can't have other test pop up windows, and possibly
stealing focus and preventing us from getting data
offers. So, run the clipboard test in isolation.
2021-09-17 11:38:28 -04:00
Matthias Clasen bef54a382d transform: Improve docs
Add an example for reconstructing transforms.
2021-09-17 10:28:49 -04:00
Matthias Clasen 6a60214e8c gsk: Handle 2D transforms better
For 2D transforms, we can read the scale
factors more directly off the matrix.

This should eventually be moved out into a
function to decompose a 2D transform into
scale + rotation + skew + translation.
2021-09-17 10:28:49 -04:00
Matthias Clasen 27d662f1aa node editor: Preserve aspect ratio
We don't want to distort our rendering.
Tell the paintable to keep the aspect
ratio.
2021-09-17 10:28:49 -04:00
Matthias Clasen 52a8492887 rendernodepaintable: Provide accurate aspect ratio
Since we report width and height as integers, the
default implementation of this introduces rounding
errors. This shows up in the node-editor, as having
uneven scale factors like sx=1.0 and sy=1.0035.
Text nodes don't handle uneven scales like that well
and overdraw.
2021-09-17 10:28:49 -04:00
Lukáš Tyrychtr ba5d010e39 Delete unneccessary comment and make other more descriptive 2021-09-17 15:11:26 +02:00
Matthias Clasen 8c34dd58c0 gsk: Add a test for transform_bounds 2021-09-17 07:43:07 -04:00
Matthias Clasen 0cce92ab19 Merge branch 'fix-typo' into 'master'
gtkcolorbutton: Fix documentation

See merge request GNOME/gtk!3965
2021-09-17 10:52:59 +00:00
James Westman f95c21b67c gtkcolorbutton: Fix documentation 2021-09-16 23:53:42 -05:00
Benjamin Otte 1d41dc716e Merge branch 'image-loading' into 'master'
Image loaders

See merge request GNOME/gtk!3939
2021-09-17 03:13:38 +00:00
Benjamin Otte 3914ecbd0f gtk-demo: Use textures in listbox example 2021-09-17 04:31:46 +02:00
Benjamin Otte 0428d8ccd6 examples: Use textures over pixbufs 2021-09-17 04:31:46 +02:00
Benjamin Otte 37a7c6780a icontheme: Implement gtk_icon_theme_lookup_by_gicon() for textures
More feature parity.

Before this, it would have worked just as well - just going via a PNG
bytes step inbetween.
2021-09-17 04:31:46 +02:00
Benjamin Otte 1b85b5597b texture: Implement GIcon and GLoadableIcon
This is mainly for feature parity with GdkPixbuf. And it doesn't hurt
anyone (I hope).
2021-09-17 04:31:46 +02:00
Benjamin Otte fae32846c7 texture: Refactor gdk_texture_new_from_bytes()
1. Split into a real loader and a fake one

2. Only try the fake one if the real one doesn't support the file.
2021-09-17 04:31:46 +02:00
Benjamin Otte b271a94f92 texture: Rework error enum
1. Change INSUFFICIENT_MEMORY to TOO_LARGE
   GTK crashes on insufficient memory, we don't emit GErrors.

2. Split UNSUPPORTED into UNSUPPORTED_CONTENT and UNSUPPORTED_FORMAT
   So we know if you need to find an RPM with a loader or curse and
   the weird file.

3. Translate error messages, they are meant for end users.
2021-09-17 03:25:35 +02:00
Benjamin Otte e58f70d7bb pixbufutils: Don't hardcode formats
Just let the loaders figure out the file format themselves.
2021-09-17 02:34:15 +02:00
Benjamin Otte 4fcf54757f icontheme: Insist that people provide proper values
Seriously...
2021-09-17 02:29:59 +02:00
Benjamin Otte b5da07f0e1 icontheme: Use textures more
We were going via GLoadablieIcon/GInputStream for everything previously
and we have no API for that with GdkTexture.

With this commit, gdk-pixbuf isn't used anymore when starting
widget-factory for anything but SVG.
2021-09-17 02:12:07 +02:00
Benjamin Otte a85f4ec6c2 icontheme: Load textures directly when possible
This doesn't fix the codepaths for SVG (both for recoloring and
resizing) and doesn't handle streams yet.
2021-09-17 02:02:51 +02:00
Matthias Clasen b226478e8b Support 16bit formats in the png loader
When loading, convert all >8-bit data to
GDK_MEMORY_R16G16B16A16_PREMULTIPLIED.

When saving, save all 8-bit formats as 8-bit RGBA,
and save all >8-bt formats as 16-bit RGBA.
2021-09-17 02:02:51 +02:00
Matthias Clasen 14280b5f5b contentdeserializer: Use our on jpeg loader 2021-09-17 02:02:51 +02:00
Matthias Clasen e720f9d35d Add code to save jpegs 2021-09-17 02:02:51 +02:00
Matthias Clasen fecb31b706 builder: Stop using pixbufutils
We can just use gdk_pixbuf_new_from_resource here.
2021-09-17 02:02:51 +02:00
Matthias Clasen 729ad8e64a cssimageurl: Just create a texture directly
We don't need to use the pixbufutils api here.
2021-09-17 02:02:51 +02:00
Matthias Clasen dcd873a6d8 builder: create textures without pixbufs
Load textures using the GdkTexture apis, without
going through a pixbuf first.
2021-09-17 02:02:51 +02:00
Benjamin Otte 679c93e843 texture: Add private can_load() function
... and use it to load textures in gtk_picture_set_from_file().
2021-09-17 00:25:22 +02:00
Benjamin Otte 2d3de8608c texture: Split out type detection
This way, the code using it becomes clearer and we can use it in
multiple places without accidentally doing it wrong (hint: see next
commit).
2021-09-17 00:25:22 +02:00
Benjamin Otte 100b0bf7d9 texture: Remove declaration for nonexisting function 2021-09-17 00:25:22 +02:00
Matthias Clasen f2ca9ebbd7 texture: Avoid pixbufs when loading resources
We can just use our own loaders here now.
2021-09-17 00:25:22 +02:00
Benjamin Otte 577bf104c0 testsuite: Add png and tiff methods
We encode the texture to a PNG or TIFF and then decode
it again, in various ways.
2021-09-17 00:25:22 +02:00
Benjamin Otte b1bb7c3258 texture: Add gdk_texture_save_to_tiff_bytes() 2021-09-17 00:25:22 +02:00
Matthias Clasen c77b5c46a3 rendernodeparser: Avoid gdk_texture_new_for_pixbuf
We can just use gdk_texture_new_from_bytes here now.

Update affected test output.
2021-09-17 00:25:22 +02:00
Matthias Clasen 5b82cf1145 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-17 00:25:22 +02:00
Matthias Clasen 95a0c93839 Add contentserializer tests for textures 2021-09-17 00:25:22 +02:00
Matthias Clasen d27bc74481 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-17 00:25:22 +02:00
Matthias Clasen e30b4c61cb Add tests for the jpeg loader 2021-09-17 00:25:22 +02:00
Matthias Clasen daf29e174f Load jpegs without gdk-pixbuf
Use our own loader for jpeg files.
2021-09-17 00:25:22 +02:00
Matthias Clasen 729ba8111a 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-17 00:25:22 +02:00
Matthias Clasen d30a029689 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-17 00:25:22 +02:00
Matthias Clasen 945c2531ac Add tests for the tiff loader 2021-09-17 00:25:22 +02:00
Matthias Clasen f925e12e1d Load tiffs without gdk-pixbuf
This will let us load floating point data, in
the future.
2021-09-17 00:25:22 +02:00
Matthias Clasen a03594df52 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-17 00:25:22 +02:00
Matthias Clasen d7c8f92733 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-17 00:25:22 +02:00
Matthias Clasen d6ce65f81c Add tests for the png loader 2021-09-17 00:25:22 +02:00
Matthias Clasen 7949aaabb7 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-17 00:25:22 +02:00
Matthias Clasen a71877bf99 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-17 00:25:22 +02:00
Matthias Clasen f51f7f85eb 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-17 00:25:22 +02:00
Matthias Clasen 66031fd00b texture: Add error enum 2021-09-17 00:25:22 +02:00
Benjamin Otte 698b3542a1 Merge branch 'modern-testsuite' into 'master'
testsuite: modernize image handling

Closes #4261

See merge request GNOME/gtk!3955
2021-09-16 22:22:56 +00:00
Benjamin Otte 83ea623775 reftests: Use the default (aka NGL) renderer
All tests pass with the renderer now, so we can remove useof the
fallback.
2021-09-16 23:59:37 +02:00
Benjamin Otte 345faa7250 reftests: XFAIL border-half-pixel test
the GL renderer can't deal with non-integers
2021-09-16 23:59:37 +02:00
Benjamin Otte 08df891070 reftests: Use colors without rounding errors
Color values must be divisible by 15 to be convertible into U8 and U16
values with the same result. 0x80 is not one of these values, so switch
it to 0x99.
2021-09-16 23:59:37 +02:00
Benjamin Otte 56b31c3923 rendernodeparser: Handle is_color attribute for glyphs 2021-09-16 23:59:37 +02:00
Matthias Clasen 93323be22a ngl: Avoid offscreens in more cases
We avoid an offscreen if we know the child node
can 'handle' the transform. Shadow nodes can if their
child node does - either the child node is a text node
in which case the shortcuts we take for shadow nodes
will work fine with the transform (we just render the
text node offset), or the child is not a text node,
in which case we render the shadow to an offscreen
anyway.

This change makes the label-shadows reftest pass with
the GL renderer, not by fixing the issue but by avoiding
it.
2021-09-16 23:59:37 +02:00
Matthias Clasen 9e14de2534 ngl: Improve shortcuts for shadow nodes
For shadow nodes, we try pretty hard to avoid
rendering shadows, and and we have a shortcut
that just renders text offset, but we can try
harder to do nothing - if the text is offset
by zero, we don't need to draw it at all.
2021-09-16 23:59:37 +02:00
Benjamin Otte 62954a0338 ngl Fix bottom-right border render failure
The wrong index was used for offsetting the bottom border rect.

Test included.
2021-09-16 23:59:37 +02:00
Benjamin Otte 7cf5e5546b testsuite: Switch color from khaki to yellow
llvmpipe doesn't loike compositing semitransparent khaki onto solid
khaki without rounding errors.
2021-09-16 23:59:37 +02:00
Benjamin Otte 58f66ebd07 reftests: Make image-compare use textures
All image comparisons are done on textures now.
2021-09-16 23:59:37 +02:00
Benjamin Otte 47330598fb reftests: Use 0.6 instead of 0.5 for alpha
See previous commit about rounding
2021-09-16 23:59:37 +02:00
Benjamin Otte 90ed7b92b2 reftests: Use 0.6 alpha, not 0.5
0.5 leads to some GL renderers computing 0.5 * 0xFF as 0x7F and
others 0x80, while 0.6 * 0xFF (255 is divisible by 5) is always 0x99.
2021-09-16 23:59:37 +02:00
Benjamin Otte 625b5ce91a testsuite: Port compare_render() to use textures 2021-09-16 23:59:37 +02:00
Benjamin Otte c84d5b1f7f tests: Update rendernode test to use textures 2021-09-16 23:59:37 +02:00
Benjamin Otte 46bb160923 testuite: Add opacity-overdraw test
Tests that overdrawing of content inside an opacity node happens before
the opacity is applied.

This is broken in the GL renderer and causes the opacity.ui reftest to
fail.
2021-09-16 23:59:37 +02:00
Matthias Clasen 390a0b2f2a ngl: Fix opacity handling
We need to use an offscreen whenever there is overlapping
children somewhere in the tree below, just checking the
direct child of the opacity node is not enough.

Fixes: #4261
2021-09-16 23:59:37 +02:00
Benjamin Otte 0dfab46c15 reftests: Use GdkTexture instead of cairo_surface_t
This also switches the rendering code from using gsk_render_node_draw()
to gsk_renderer_render_texture().

Some tests are broken with the GL renderer, so this patch forces the
Cairo renderer until they get fixed.
2021-09-16 23:59:37 +02:00
Benjamin Otte 3a8ec683d3 reftests: Make diff pixels always opaque
We had pixels that did not differ in alpha and we then set 0 alpha
difference hich made the pixel invisible. Oops.
2021-09-16 23:59:37 +02:00
Benjamin Otte de53b0c7a3 testsuite: remove box-order test
The test used to test that GtkBox ordered it's children left-to-right in
CSS, no matter the text direction or pack-type.

But there is neither a pack-type anymore nor does GTK4 do that.

So that test has been broken for yers, it just didn't render anything
wrong.
2021-09-16 23:59:37 +02:00
Benjamin Otte 75dfb4d63b API: Add gdk_texture_new_from_filename()
There are quite a few places where we can make use of it, in particular
in the testsuite and icontheme.
2021-09-16 23:59:37 +02:00
Benjamin Otte 64acaf99fb testsuite: Fix race in texture-threads test
Threads are evil, yo.
2021-09-16 23:59:37 +02:00
Benjamin Otte 551f76ea69 gltexture: Fallback in download_float()
GLES only allows downloading float if the texture matches specific
criteria and I'm too lazy to determine them, so always fall back.

And the custom stride fallback code isn't necessary, because falling
back does exactly that step already.
2021-09-16 23:59:37 +02:00
Benjamin Otte a4f3fbbda1 gltexture: Fix download() for GLES
GLES can't do glGetTexImage(), so implement a version that does
glReadPixels() on GLES.
2021-09-16 23:59:37 +02:00
Benjamin Otte b6d3561f4a testsuite: Be more verbose in texture-threads test
The test randomly fails on CI, so try to be more helpful in debugging
them.
2021-09-16 23:59:37 +02:00
Matthias Clasen 01944d57b7 Merge branch 'master' into 'master'
Do not require wayland-protocols as dependency in the .pc files

See merge request GNOME/gtk!3960
2021-09-16 18:32:23 +00:00
muradm c9aec9b5a2 Do not require wayland-protocols as dependency in the .pc file
Basically, I was building some packages on Guix. I figured out that
wayland-protocols was listed among propagated-inputs for gtk+ package
(gtk-3-24). propagated-inputs holds a list of runtime dependencies,
that should be available to any other package that depends on gtk+.
While discussing we clarified that wayland-protocols is not runtime
dependency. So I moved it to native-inputs of gtk+ package, which
means that, this dependency will be available only to gtk+ package and
only at build time. Once moved, building of other applications that
depening on gtk+ started to fail.

Investigation showed that, all .pc (pkg-config) files prepared by gtk+
package, was including:

Requires.private: ... wayland-protocols ...

Since it becomes requirement, other applications was failing with
missing dependency wayland-protocols of dependency gtk+, for instance:

-- Checking for module 'gtk+-3.0'
--   Package 'wayland-protocols', required by 'gdk-3.0', not found

While actually wayland-protocols is not even a build time dependency
of application that depends on gtk+. Advertisement of such
requirement, is a bit misleading, because one does not need it at
runtime, especially applications based on gtk.
2021-09-16 20:31:30 +03:00
Matthias Clasen 025759e614 Merge branch 'wip/jimmac/make-toolbar-togglebuttons-visible' into 'master'
theme: make toggled tbuttons in toolbars visible

Closes #4264

See merge request GNOME/gtk!3959
2021-09-16 11:35:35 +00:00
Jakub Steiner ed679703b8 theme: make toggled tbuttons in toolbars visible
- do what Alex does in libadwaita

Fixes https://gitlab.gnome.org/GNOME/gtk/-/issues/4264
2021-09-16 12:47:26 +02:00
Matthias Clasen fe46da1bf4 Merge branch 'misc-texture-things' into 'master'
Add gdk_texture_new_from_bytes

See merge request GNOME/gtk!3958
2021-09-16 03:14:12 +00:00
Benjamin Otte 7fd8899092 pixbufutils: Simplify function 2021-09-15 22:00:41 -04:00
Matthias Clasen 9f8d6ff29c texture: Mention download_float in the docs 2021-09-15 22:00:16 -04:00
Matthias Clasen 1230bce133 Add gdk_texture_new_from_bytes
Add this new api, and make gdk_texture_new_from_file
a wrapper around it.
2021-09-15 22:00:09 -04:00
Matthias Clasen 7c2be93a56 Merge branch 'matthiasc/for-master' into 'master'
Fix memorytexture float conversion

See merge request GNOME/gtk!3957
2021-09-16 01:56:39 +00:00
Matthias Clasen eb23e23b03 ngl: Avoid cairo_to_png in debug output
Just use a GL texture and gdk_texture_save_to_png,
it was made for this.
2021-09-15 21:18:34 -04:00
Matthias Clasen 75b45aeabf Fix memorytexture float conversion
This was silently dropping the alpha in one case.
2021-09-15 21:14:59 -04:00
Matthias Clasen 23ffd6923d Merge branch 'update-readme' into 'master'
Update the README

See merge request GNOME/gtk!3956
2021-09-15 23:25:57 +00:00
Matthias Clasen d2eb0288d9 Apply 1 suggestion(s) to 1 file(s) 2021-09-15 21:50:36 +00:00
Matthias Clasen a4b976f7a2 Update the README
Remove the mention of GNU (since that has not been case
for a long time, effectively), state that GTK is hosted
by the GNOME project, and point to GNOME as a place
for donations.
2021-09-15 15:44:57 -04:00
Boyuan Yang 4930faa984 Update Chinese (China) translation 2021-09-15 18:41:06 +00:00
Dz Chen 84fdda4f56 Update Chinese (China) translation 2021-09-15 15:28:39 +00:00
Matthias Clasen ec6228b3a4 Merge branch 'function-annotations' into 'master'
Annotate gsk_rounded_rect_is_circular as pure

See merge request GNOME/gtk!3952
2021-09-14 21:39:48 +00:00
Matthias Clasen 8b85e7f35a Annotate gtk_get_default_language as const 2021-09-14 16:38:08 -04:00
Matthias Clasen d7909dccdc Annotate gtk_editable_get_chars as malloc 2021-09-14 16:38:08 -04:00
Matthias Clasen 7773ae4538 csstypes: Add annotations and inlines
Inline _gtk_css_change_for_sibling and
_gtk_css_change_for_child, and mark a few
other functions as const or malloc.
2021-09-14 16:38:08 -04:00
Matthias Clasen bec44acdeb Annotate some builder apis as malloc 2021-09-14 16:38:08 -04:00
Matthias Clasen 5bfac597f6 Annotate gtk_accelerator_get_default_mod_mask as const 2021-09-14 16:38:08 -04:00
Matthias Clasen 423a4d4c3e Annotate gsk_cairo_blur_compute_pixels as const 2021-09-14 16:38:08 -04:00
Matthias Clasen 38fce67a9b Annotate gdk_rgba_to_string as malloc 2021-09-14 16:38:08 -04:00
Matthias Clasen 04ef7055cd Annotate gdk_drag_action_is_unique as const 2021-09-14 16:38:08 -04:00
Matthias Clasen 44a031c3c1 Annotate gtk_css_tokenizer_get_location as const 2021-09-14 16:38:08 -04:00
Matthias Clasen be885c888f cssparser: Mark some functions as pure and malloc 2021-09-14 16:38:08 -04:00
Matthias Clasen 6faef4416f Annotate gsk_ngl_uniform_state_align as pure 2021-09-14 16:38:08 -04:00
Matthias Clasen 5f452a5e6c Annotate gsk_rounded_rect_is_circular as pure
And also mark gsk_rounded_rect_to_string as malloc.
2021-09-14 16:38:08 -04:00
Matthias Clasen 060f2d5f65 Annotate pango_glyph_string_num_glyphs as pure 2021-09-14 16:38:08 -04:00
Matthias Clasen ebca260f2d Annotate gdk_unichar_direction as const 2021-09-14 16:38:08 -04:00
Matthias Clasen d4b1f85e14 Merge branch 'gsk-tests-gl' into 'master'
testsuite: Call g_test_init in test binaries

See merge request GNOME/gtk!3953
2021-09-14 20:37:16 +00:00
Matthias Clasen 4439ff0c12 testsuite: Stop running tests for the gl renderer
It does not exist anymore.
2021-09-14 16:12:55 -04:00
Matthias Clasen ffab67ac70 testsuite: Call g_test_init in test binaries
Without it, we mess out on G_DEBUG=fatal-warnings,
so our ci does not alert us that we run a bunch of
tests which spit out warnings.
2021-09-14 16:12:55 -04:00
Lukáš Tyrychtr 0120ff3518 Merge branch 'master' into menu_button_a11y_improvements 2021-09-14 15:34:14 +02:00
Matthias Clasen 2e63b53b1e Merge branch 'fix_accessible_described_by' into 'master'
Fix generation of accessible description in presence of described by relations

See merge request GNOME/gtk!3948
2021-09-14 13:29:28 +00:00
Matthias Clasen 878c9da736 Merge branch 'test-leak-fixes' into 'master'
testsuite: Fix a few memory leaks

See merge request GNOME/gtk!3947
2021-09-14 13:14:10 +00:00
Lukáš Tyrychtr 955d50a080 Fix generation of accessible description in presence of described by relations
The loop going through the relation list should have stopped on the NULL sentinel value, however it never accesed the next list element.
2021-09-14 14:33:30 +02:00
Matthias Clasen 2b4f798e34 testsuite: Fix a few memory leaks
These are keeping the asan build in ci from passing.
2021-09-14 08:29:45 -04:00
Matthias Clasen cda5d2dadd Merge branch 'tiff-ci' into 'master'
ci: Add libtiff-devel to the image

See merge request GNOME/gtk!3946
2021-09-14 12:27:39 +00:00
Lukáš Tyrychtr b664b2d1fd Set correct accessible relations for GtkMenuButton
Up until now, as the focus was moved to the inner button, it was not possible for
assistive technologies to determine the correct labels and descriptions
because developers could set them only for the parent widget.
Now, the proper relations are added so the labels should be picked up properly.

Fixes #4254
2021-09-14 14:26:18 +02:00
Matthias Clasen c70fdd6331 ci: Use the v4 image 2021-09-14 08:06:09 -04:00
Matthias Clasen ddec3dedd0 ci: Add libtiff-devel to the image
We want to require libtiff in our build.
2021-09-14 08:06:09 -04:00
Matthias Clasen b1a5c3ff55 Merge branch 'wip/exalm/papercuts' into 'master'
Fix 2 papercuts

See merge request GNOME/gtk!3945
2021-09-14 11:36:25 +00:00
Alexander Mikhaylenko 8f9a5175f0 media-controls: Make play button flat
Match the volume button.
2021-09-14 12:23:03 +05:00
Alexander Mikhaylenko 099c923679 searchbar: Vertically center the close button 2021-09-14 12:22:45 +05:00
Matthias Clasen 2a12a3e6d9 Merge branch 'fix_#4255' into 'master'
stack: Dispose children before emitting items-changed

Closes #4255

See merge request GNOME/gtk!3943
2021-09-13 16:10:37 +00:00
Julian Sparber cdc1fa166d 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-13 17:19:05 +02: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
192 changed files with 35071 additions and 30698 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ variables:
BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled"
MESON_TEST_TIMEOUT_MULTIPLIER: 3
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v33"
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/gtk/fedora:v34"
FLATPAK_IMAGE: "registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master"
.only-default:
+1
View File
@@ -53,6 +53,7 @@ RUN dnf -y install \
libpng-devel \
librsvg2 \
libselinux-devel \
libtiff-devel \
libubsan \
libXcomposite-devel \
libXcursor-devel \
+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
+9 -4
View File
@@ -10,10 +10,12 @@ GTK is a multi-platform toolkit for creating graphical user interfaces.
Offering a complete set of widgets, GTK is suitable for projects ranging
from small one-off projects to complete application suites.
GTK is free software and part of the GNU Project. However, the
licensing terms for GTK, the GNU LGPL, allow it to be used by all
developers, including those developing proprietary software, without any
license fees or royalties.
GTK is a free and open-source software project. The licensing terms
for GTK, the GNU LGPL, allow it to be used by all developers, including those
developing proprietary software, without any license fees or royalties.
GTK is hosted by the GNOME project (thanks!) and used by a wide variety
of applications and projects.
The official download location
@@ -151,6 +153,9 @@ Contributing to GTK
Please, follow the [contribution guide](./CONTRIBUTING.md) to know how to
start contributing to GTK.
If you want to support GTK financially, please consider donating to
the GNOME project, which runs the infrastructure hosting GTK.
Release notes
-------------
-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
+157 -19
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>
@@ -17,10 +22,14 @@ 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)
@@ -28,7 +37,7 @@ update_image (void)
const char *text;
PangoFontDescription *desc;
PangoLayout *layout;
PangoRectangle ink, pink, logical;
PangoRectangle ink, logical;
int baseline;
cairo_surface_t *surface;
cairo_t *cr;
@@ -39,6 +48,7 @@ update_image (void)
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);
@@ -84,7 +94,6 @@ update_image (void)
pango_layout_set_font_description (layout, desc);
pango_layout_set_text (layout, text, -1);
pango_layout_get_extents (layout, &ink, &logical);
pink = ink;
baseline = pango_layout_get_baseline (layout);
pango_extents_to_pixels (&ink, NULL);
@@ -94,10 +103,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);
@@ -136,7 +149,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,
@@ -149,17 +162,45 @@ 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,
scale * pango_units_to_double (pink.width) - 1,
scale * pango_units_to_double (pink.height) - 1);
scale * (10 + ink.x) - 0.5,
scale * (10 + ink.y) - 0.5,
scale * ink.width + 1,
scale * ink.height + 1);
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, 0, 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
{
@@ -167,10 +208,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);
@@ -185,7 +242,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);
}
@@ -193,7 +250,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);
}
@@ -212,7 +269,6 @@ update_image (void)
cairo_surface_destroy (surface);
}
gtk_picture_set_pixbuf (GTK_PICTURE (image), pixbuf2);
g_object_unref (pixbuf2);
@@ -220,6 +276,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)
{
@@ -227,20 +355,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 *
@@ -266,6 +400,8 @@ do_fontrendering (GtkWidget *do_widget)
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);
@@ -277,6 +413,8 @@ do_fontrendering (GtkWidget *do_widget)
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 ();
+84 -35
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,20 +82,20 @@
</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="GtkCheckButton" id="antialias">
<property name="label">Antialias</property>
<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>
@@ -108,45 +103,73 @@
</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="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="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>
</layout>
</object>
</child>
<child>
<object class="GtkCheckButton" id="hint_metrics">
<property name="label">Hint Metrics</property>
<property name="label">Hint _Metrics</property>
<property name="use-underline">1</property>
<layout>
<property name="column">4</property>
<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="active">1</property>
<property name="label">Show _Extents</property>
<property name="use-underline">1</property>
<layout>
<property name="column">5</property>
<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>
@@ -154,11 +177,24 @@
<child>
<object class="GtkButton" id="up_button">
<property name="icon-name">list-add-symbolic</property>
<property name="halign">center</property>
<property name="valign">center</property>
<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>
@@ -166,11 +202,24 @@
<child>
<object class="GtkButton" id="down_button">
<property name="icon-name">list-remove-symbolic</property>
<property name="halign">center</property>
<property name="valign">center</property>
<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>
@@ -179,7 +228,7 @@
<object class="GtkLabel">
<property name="hexpand">1</property>
<layout>
<property name="column">7</property>
<property name="column">8</property>
</layout>
</object>
</child>
+4 -7
View File
@@ -8,7 +8,7 @@
#include <stdlib.h>
#include <string.h>
static GdkPixbuf *avatar_pixbuf_other;
static GdkTexture *avatar_texture_other;
static GtkWidget *window = NULL;
#define GTK_TYPE_MESSAGE (gtk_message_get_type ())
@@ -196,12 +196,9 @@ gtk_message_row_update (GtkMessageRow *row)
gtk_button_set_label (GTK_BUTTON (priv->resent_by_button), priv->message->resent_by);
if (strcmp (priv->message->sender_nick, "@GTKtoolkit") == 0)
{
gtk_image_set_from_icon_name (priv->avatar_image, "org.gtk.Demo4");
gtk_image_set_icon_size (priv->avatar_image, GTK_ICON_SIZE_LARGE);
}
gtk_image_set_from_icon_name (priv->avatar_image, "org.gtk.Demo4");
else
gtk_image_set_from_pixbuf (priv->avatar_image, avatar_pixbuf_other);
gtk_image_set_from_paintable (priv->avatar_image, GDK_PAINTABLE (avatar_texture_other));
}
@@ -344,7 +341,7 @@ do_listbox (GtkWidget *do_widget)
if (!window)
{
avatar_pixbuf_other = gdk_pixbuf_new_from_resource_at_scale ("/listbox/apple-red.png", 32, 32, FALSE, NULL);
avatar_texture_other = gdk_texture_new_from_resource ("/listbox/apple-red.png");
window = gtk_window_new ();
gtk_window_set_display (GTK_WINDOW (window),
+1
View File
@@ -25,6 +25,7 @@
<property name="margin-start">8</property>
<property name="margin-end">8</property>
<property name="icon-name">image-missing</property>
<property name="icon-size">large</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
+1
View File
@@ -198,6 +198,7 @@
<child>
<object class="GtkPicture" id="picture">
<property name="can-shrink">0</property>
<property name="keep-aspect-ratio">1</property>
<property name="halign">center</property>
<property name="valign">center</property>
<child>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 MiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 59 KiB

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/WidgetFactory4">
<file preprocess="xml-stripblanks">widget-factory.ui</file>
<file alias='widget-factory.ui'>widget-factory.uic</file>
</gresource>
<gresource prefix="/org/gtk/WidgetFactory4">
<file>widget-factory.css</file>
Binary file not shown.
+2 -2
View File
@@ -603,8 +603,8 @@ bloat_pad_startup (GApplication *application)
g_object_unref (icon);
g_bytes_unref (bytes);
icon = G_ICON (gdk_pixbuf_new_from_resource ("/org/gtk/libgtk/icons/16x16/actions/folder-new.png", NULL));
item = g_menu_item_new ("Pixbuf", NULL);
icon = G_ICON (gdk_texture_new_from_resource ("/org/gtk/libgtk/icons/16x16/actions/folder-new.png"));
item = g_menu_item_new ("Texture", NULL);
g_menu_item_set_icon (item, icon);
g_menu_append_item (menu, item);
g_object_unref (item);
+1 -1
View File
@@ -29,7 +29,7 @@ gboolean gdk_should_use_portal (void);
const char * gdk_get_startup_notification_id (void);
PangoDirection gdk_unichar_direction (gunichar ch);
PangoDirection gdk_unichar_direction (gunichar ch) G_GNUC_CONST;
PangoDirection gdk_find_base_dir (const char *text,
int len);
+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,
+92 -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,56 @@ pixbuf_deserializer (GdkContentDeserializer *deserializer)
deserializer);
}
static void
texture_deserializer_finish (GObject *source,
GAsyncResult *result,
gpointer deserializer)
{
GOutputStream *stream = G_OUTPUT_STREAM (source);
GBytes *bytes;
GError *error = NULL;
GdkTexture *texture = NULL;
gssize written;
written = g_output_stream_splice_finish (stream, result, &error);
if (written < 0)
{
gdk_content_deserializer_return_error (deserializer, error);
return;
}
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (stream));
texture = gdk_texture_new_from_bytes (bytes, &error);
g_bytes_unref (bytes);
if (texture == NULL)
{
gdk_content_deserializer_return_error (deserializer, error);
return;
}
g_value_take_object (gdk_content_deserializer_get_value (deserializer), texture);
gdk_content_deserializer_return_success (deserializer);
}
static void
texture_deserializer (GdkContentDeserializer *deserializer)
{
GOutputStream *output;
output = g_memory_output_stream_new_resizable ();
g_output_stream_splice_async (output,
gdk_content_deserializer_get_input_stream (deserializer),
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE
| G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
gdk_content_deserializer_get_priority (deserializer),
gdk_content_deserializer_get_cancellable (deserializer),
texture_deserializer_finish,
deserializer);
g_object_unref (output);
}
static void
string_deserializer_finish (GObject *source,
GAsyncResult *result,
@@ -863,48 +915,71 @@ 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);
gdk_content_register_deserializer ("image/jpeg",
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, jpegs and tiffs into textures is handled above */
if (!g_str_equal (name, "png") &&
!g_str_equal (name, "jpeg") &&
!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);
+115 -18
View File
@@ -26,6 +26,10 @@
#include "filetransferportalprivate.h"
#include "gdktextureprivate.h"
#include "gdkrgba.h"
#include "loaders/gdkpngprivate.h"
#include "loaders/gdktiffprivate.h"
#include "loaders/gdkjpegprivate.h"
#include "gdkmemorytextureprivate.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <string.h>
@@ -606,6 +610,7 @@ gdk_content_serialize_finish (GAsyncResult *result,
/*** SERIALIZERS ***/
static void
pixbuf_serializer_finish (GObject *source,
GAsyncResult *res,
@@ -658,6 +663,77 @@ 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;
GInputStream *input;
gssize spliced;
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 if (strcmp (gdk_content_serializer_get_mime_type (serializer), "image/jpeg") == 0)
bytes = gdk_save_jpeg (texture);
else
g_assert_not_reached ();
input = g_memory_input_stream_new_from_bytes (bytes);
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;
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 +953,72 @@ 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);
gdk_content_register_serializer (GDK_TYPE_TEXTURE,
"image/jpeg",
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, tiffs or jpegs is handled above */
if (!g_str_equal (name, "png") &&
!g_str_equal (name, "tiff") &&
!g_str_equal (name, "jpeg"))
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);
+1 -1
View File
@@ -69,7 +69,7 @@ GDK_AVAILABLE_IN_ALL
GdkDragAction gdk_drag_get_selected_action (GdkDrag *drag);
GDK_AVAILABLE_IN_ALL
gboolean gdk_drag_action_is_unique (GdkDragAction action);
gboolean gdk_drag_action_is_unique (GdkDragAction action) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GdkDrag * gdk_drag_begin (GdkSurface *surface,
+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));
}
+243 -46
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,258 @@ 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);
}
static void
gdk_gl_texture_download (GdkTexture *texture,
const GdkRectangle *area,
guchar *data,
gsize stride)
typedef struct _InvokeData
{
GdkGLTexture *self = GDK_GL_TEXTURE (texture);
cairo_surface_t *surface;
cairo_t *cr;
GdkGLTexture *self;
volatile int spinlock;
GFunc func;
gpointer data;
} InvokeData;
surface = cairo_image_surface_create_for_data (data,
CAIRO_FORMAT_ARGB32,
area->width, area->height,
stride);
static gboolean
gdk_gl_texture_invoke_callback (gpointer data)
{
InvokeData *invoke = data;
GdkGLContext *context;
cr = cairo_create (surface);
context = gdk_display_get_gl_context (gdk_gl_context_get_display (invoke->self->context));
if (self->saved)
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_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 inline void
gdk_gl_texture_get_tex_image (GdkGLTexture *self,
GLenum gl_format,
GLenum gl_type,
GLvoid *data)
{
if (gdk_gl_context_get_use_es (self->context))
{
cairo_set_source_surface (cr, self->saved, 0, 0);
cairo_paint (cr);
GdkTexture *texture = GDK_TEXTURE (self);
GLuint fbo;
glGenFramebuffers (1, &fbo);
glBindFramebuffer (GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->id, 0);
glReadPixels (0, 0,
texture->width, texture->height,
gl_format,
gl_type,
data);
glBindFramebuffer (GL_FRAMEBUFFER, 0);
glDeleteFramebuffers (1, &fbo);
}
else
{
GdkSurface *gl_surface;
glGetTexImage (GL_TEXTURE_2D,
0,
gl_format,
gl_type,
data);
}
}
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;
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);
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);
gdk_gl_texture_get_tex_image (texture_,
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);
GdkTexture *result;
if (self->saved)
return g_object_ref (self->saved);
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)
{
gdk_texture_download (self->saved, data, stride);
return;
}
cairo_destroy (cr);
cairo_surface_finish (surface);
cairo_surface_destroy (surface);
if (gdk_gl_context_get_use_es (self->context) ||
stride != texture->width * 4)
{
GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download (texture, data, stride);
return;
}
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);
if (self->saved)
{
gdk_texture_download_float (self->saved, data, stride);
return;
}
if (gdk_gl_context_get_use_es (self->context) ||
stride != texture->width * 4)
{
GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download_float (texture, data, stride);
return;
}
gdk_gl_texture_run (self, gdk_gl_texture_do_download_float, data);
}
static void
@@ -116,7 +325,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 +361,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] = src[3] / 65535.f;
}
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))
{
+1 -1
View File
@@ -67,7 +67,7 @@ GDK_AVAILABLE_IN_ALL
gboolean gdk_rgba_parse (GdkRGBA *rgba,
const char *spec);
GDK_AVAILABLE_IN_ALL
char * gdk_rgba_to_string (const GdkRGBA *rgba);
char * gdk_rgba_to_string (const GdkRGBA *rgba) G_GNUC_MALLOC;
G_END_DECLS
+438 -59
View File
@@ -28,8 +28,8 @@
* `GdkPixbuf`, or a Cairo surface, or other pixel data.
*
* The ownership of the pixel data is transferred to the `GdkTexture`
* instance; you can only make a copy of it, via
* [method@Gdk.Texture.download].
* instance; you can only make a copy of it, via [method@Gdk.Texture.download]
* or [method@Gdk.Texture.download_float].
*
* `GdkTexture` is an immutable object: That means you cannot change
* anything about it other than increasing the reference count via
@@ -41,11 +41,17 @@
#include "gdktextureprivate.h"
#include "gdkinternals.h"
#include "gdkintl.h"
#include "gdkmemorytextureprivate.h"
#include "gdkpaintable.h"
#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
@@ -108,20 +114,143 @@ gdk_texture_paintable_init (GdkPaintableInterface *iface)
iface->get_intrinsic_height = gdk_texture_paintable_get_intrinsic_height;
}
static GVariant *
gdk_texture_icon_serialize (GIcon *icon)
{
GVariant *result;
GBytes *bytes;
bytes = gdk_texture_save_to_png_bytes (GDK_TEXTURE (icon));
result = g_variant_new_from_bytes (G_VARIANT_TYPE_BYTESTRING, bytes, TRUE);
g_bytes_unref (bytes);
return g_variant_new ("(sv)", "bytes", result);
}
static void
gdk_texture_icon_init (GIconIface *iface)
{
iface->hash = (guint (*) (GIcon *)) g_direct_hash;
iface->equal = (gboolean (*) (GIcon *, GIcon *)) g_direct_equal;
iface->serialize = gdk_texture_icon_serialize;
}
static GInputStream *
gdk_texture_loadable_icon_load (GLoadableIcon *icon,
int size,
char **type,
GCancellable *cancellable,
GError **error)
{
GInputStream *stream;
GBytes *bytes;
bytes = gdk_texture_save_to_png_bytes (GDK_TEXTURE (icon));
stream = g_memory_input_stream_new_from_bytes (bytes);
g_bytes_unref (bytes);
if (type)
*type = NULL;
return stream;
}
static void
gdk_texture_loadable_icon_load_in_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
GInputStream *stream;
GBytes *bytes;
bytes = gdk_texture_save_to_png_bytes (source_object);
stream = g_memory_input_stream_new_from_bytes (bytes);
g_bytes_unref (bytes);
g_task_return_pointer (task, stream, g_object_unref);
}
static void
gdk_texture_loadable_icon_load_async (GLoadableIcon *icon,
int size,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
task = g_task_new (icon, cancellable, callback, user_data);
g_task_run_in_thread (task, gdk_texture_loadable_icon_load_in_thread);
g_object_unref (task);
}
static GInputStream *
gdk_texture_loadable_icon_load_finish (GLoadableIcon *icon,
GAsyncResult *res,
char **type,
GError **error)
{
GInputStream *result;
g_return_val_if_fail (g_task_is_valid (res, icon), NULL);
result = g_task_propagate_pointer (G_TASK (res), error);
if (result == NULL)
return NULL;
if (type)
*type = NULL;
return result;
}
static void
gdk_texture_loadable_icon_init (GLoadableIconIface *iface)
{
iface->load = gdk_texture_loadable_icon_load;
iface->load_async = gdk_texture_loadable_icon_load_async;
iface->load_finish = gdk_texture_loadable_icon_load_finish;
}
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gdk_texture_paintable_init))
gdk_texture_paintable_init)
G_IMPLEMENT_INTERFACE (G_TYPE_ICON,
gdk_texture_icon_init)
G_IMPLEMENT_INTERFACE (G_TYPE_LOADABLE_ICON, gdk_texture_loadable_icon_init))
#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 +316,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 +394,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));
@@ -325,18 +456,23 @@ gdk_texture_new_for_pixbuf (GdkPixbuf *pixbuf)
GdkTexture *
gdk_texture_new_from_resource (const char *resource_path)
{
GError *error = NULL;
GBytes *bytes;
GdkTexture *texture;
GdkPixbuf *pixbuf;
GError *error = NULL;
g_return_val_if_fail (resource_path != NULL, NULL);
pixbuf = gdk_pixbuf_new_from_resource (resource_path, &error);
if (pixbuf == NULL)
g_error ("Resource path %s is not a valid image: %s", resource_path, error->message);
bytes = g_resources_lookup_data (resource_path, 0, &error);
if (bytes != NULL)
{
texture = gdk_texture_new_from_bytes (bytes, &error);
g_bytes_unref (bytes);
}
else
texture = NULL;
texture = gdk_texture_new_for_pixbuf (pixbuf);
g_object_unref (pixbuf);
if (texture == NULL)
g_error ("Resource path %s s not a valid image: %s", resource_path, error->message);
return texture;
}
@@ -359,17 +495,65 @@ 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;
texture = gdk_texture_new_from_bytes (bytes, error);
g_bytes_unref (bytes);
return texture;
}
gboolean
gdk_texture_can_load (GBytes *bytes)
{
return gdk_is_png (bytes) ||
gdk_is_jpeg (bytes) ||
gdk_is_tiff (bytes);
}
static GdkTexture *
gdk_texture_new_from_bytes_internal (GBytes *bytes,
GError **error)
{
if (gdk_is_png (bytes))
{
return gdk_load_png (bytes, error);
}
else if (gdk_is_jpeg (bytes))
{
return gdk_load_jpeg (bytes, error);
}
else if (gdk_is_tiff (bytes))
{
return gdk_load_tiff (bytes, error);
}
else
{
g_set_error_literal (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_FORMAT,
_("Unknown image format."));
return NULL;
}
}
static GdkTexture *
gdk_texture_new_from_bytes_pixbuf (GBytes *bytes,
GError **error)
{
GInputStream *stream;
GdkPixbuf *pixbuf;
GdkTexture *texture;
stream = g_memory_input_stream_new_from_bytes (bytes);
pixbuf = gdk_pixbuf_new_from_stream (stream, NULL, error);
g_object_unref (stream);
if (pixbuf == NULL)
@@ -381,6 +565,82 @@ gdk_texture_new_from_file (GFile *file,
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)
{
GdkTexture *texture;
GError *internal_error = NULL;
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
texture = gdk_texture_new_from_bytes_internal (bytes, &internal_error);
if (texture)
return texture;
if (!g_error_matches (internal_error, GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT) &&
!g_error_matches (internal_error, GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_FORMAT))
{
g_propagate_error (error, internal_error);
return NULL;
}
g_clear_error (&internal_error);
return gdk_texture_new_from_bytes_pixbuf (bytes, error);
}
/**
* gdk_texture_new_from_filename:
* @path: (type filename): the filename to load
* @error: Return location for an error
*
* Creates a new texture by loading an image from a file.
*
* 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`
*/
GdkTexture *
gdk_texture_new_from_filename (const char *path,
GError **error)
{
GdkTexture *texture;
GFile *file;
g_return_val_if_fail (path, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
file = g_file_new_for_path (path);
texture = gdk_texture_new_from_file (file, error);
g_object_unref (file);
return texture;
}
/**
* gdk_texture_get_width: (attributes org.gtk.Method.get_property=width)
* @texture: a `GdkTexture`
@@ -435,20 +695,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 +731,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 +838,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 [method@Gdk.Texture.save_to_png_bytes] or look into the
* gdk-pixbuf library.
*
* Returns: %TRUE if saving succeeded, %FALSE on failure.
*/
@@ -548,30 +847,110 @@ 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 [ctor@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 [method@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 [ctor@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 [method@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);
}
+41
View File
@@ -38,6 +38,30 @@ 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_TOO_LARGE: Not enough memory to handle this image
* @GDK_TEXTURE_ERROR_CORRUPT_IMAGE: The image data appears corrupted
* @GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT: The image contains features
* that cannot be loaded
* @GDK_TEXTURE_ERROR_UNSUPPORTED_FORMAT: The image format is not supported
*
* Possible errors that can be returned by `GdkTexture` constructors.
*
* Since: 4.6
*/
typedef enum
{
GDK_TEXTURE_ERROR_TOO_LARGE,
GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
GDK_TEXTURE_ERROR_UNSUPPORTED_FORMAT,
} GdkTextureError;
GDK_AVAILABLE_IN_ALL
GType gdk_texture_get_type (void) G_GNUC_CONST;
@@ -49,6 +73,12 @@ 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_filename (const char *path,
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 +89,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
+10 -8
View File
@@ -24,21 +24,23 @@ 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,
int width,
int height);
gboolean gdk_texture_can_load (GBytes *bytes);
GdkTexture * gdk_texture_new_for_surface (cairo_surface_t *surface);
cairo_surface_t * gdk_texture_download_surface (GdkTexture *texture);
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,
+334
View File
@@ -0,0 +1,334 @@
/* 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 "gdkintl.h"
#include "gdktexture.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.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,
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 */
}
/* }}} */
/* {{{ Format conversion */
static void
convert_rgba_to_rgb (guchar *data,
int width,
int height,
int stride)
{
gsize x, y;
guchar *src, *dest;
for (y = 0; y < height; y++)
{
src = data;
dest = data;
for (x = 0; x < width; x++)
{
guint32 pixel;
memcpy (&pixel, src, sizeof (guint32));
dest[0] = (pixel & 0x00ff0000) >> 16;
dest[1] = (pixel & 0x0000ff00) >> 8;
dest[2] = (pixel & 0x000000ff) >> 0;
dest += 3;
src += 4;
}
data += stride;
}
}
static void
convert_grayscale_to_rgb (guchar *data,
int width,
int height,
int stride)
{
gsize x, y;
guchar *dest, *src;
for (y = 0; y < height; y++)
{
src = data + width;
dest = data + 3 * width;
for (x = 0; x < width; x++)
{
dest -= 3;
src -= 1;
dest[0] = *src;
dest[1] = *src;
dest[2] = *src;
}
data += stride;
}
}
static void
convert_cmyk_to_rgba (guchar *data,
int width,
int height,
int stride)
{
gsize x, r;
guchar *dest;
for (r = 0; r < height; r++)
{
dest = data;
for (x = 0; x < width; x++)
{
int c, m, y, k;
c = dest[0];
m = dest[1];
y = dest[2];
k = dest[3];
dest[0] = k * c / 255;
dest[1] = k * m / 255;
dest[2] = k * y / 255;
dest[3] = 255;
dest += 4;
}
data += stride;
}
}
/* }}} */
/* {{{ Public API */
GdkTexture *
gdk_load_jpeg (GBytes *input_bytes,
GError **error)
{
struct jpeg_decompress_struct info;
struct error_handler_data jerr;
guint width, height, stride;
unsigned char *data;
unsigned char *row[1];
GBytes *bytes;
GdkTexture *texture;
GdkMemoryFormat format;
G_GNUC_UNUSED guint64 before = GDK_PROFILER_CURRENT_TIME;
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;
}
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;
switch ((int)info.out_color_space)
{
case JCS_GRAYSCALE:
case JCS_RGB:
stride = 3 * width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_R8G8B8;
break;
case JCS_CMYK:
stride = 4 * width;
data = g_try_malloc_n (stride, height);
format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
break;
default:
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
_("Unsupported JPEG colorspace (%d)"), info.out_color_space);
jpeg_destroy_decompress (&info);
return NULL;
}
if (!data)
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_TOO_LARGE,
_("Not enough memory for image size %ux%u"), width, height);
jpeg_destroy_decompress (&info);
return NULL;
}
while (info.output_scanline < info.output_height)
{
row[0] = (unsigned char *)(&data[stride * info.output_scanline]);
jpeg_read_scanlines (&info, row, 1);
}
switch ((int)info.out_color_space)
{
case JCS_GRAYSCALE:
convert_grayscale_to_rgb (data, width, height, stride);
format = GDK_MEMORY_R8G8B8;
break;
case JCS_RGB:
break;
case JCS_CMYK:
convert_cmyk_to_rgba (data, width, height, stride);
break;
default:
g_assert_not_reached ();
}
jpeg_finish_decompress (&info);
jpeg_destroy_decompress (&info);
bytes = g_bytes_new_take (data, stride * height);
texture = gdk_memory_texture_new (width, height,
format,
bytes, stride);
g_bytes_unref (bytes);
gdk_profiler_end_mark (before, "jpeg load", NULL);
return texture;
}
GBytes *
gdk_save_jpeg (GdkTexture *texture)
{
struct jpeg_compress_struct info;
struct error_handler_data jerr;
struct jpeg_error_mgr err;
guchar *data = NULL;
gulong size = 0;
guchar *input = NULL;
guchar *row;
int width, height, stride;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
info.err = jpeg_std_error (&jerr.pub);
jerr.pub.error_exit = fatal_error_handler;
jerr.pub.output_message = output_message_handler;
jerr.error = NULL;
if (sigsetjmp (jerr.setjmp_buffer, 1))
{
free (data);
g_free (input);
jpeg_destroy_compress (&info);
return NULL;
}
info.err = jpeg_std_error (&err);
jpeg_create_compress (&info);
info.image_width = width;
info.image_height = height;
info.input_components = 3;
info.in_color_space = JCS_RGB;
jpeg_set_defaults (&info);
jpeg_set_quality (&info, 75, TRUE);
jpeg_mem_dest (&info, &data, &size);
stride = width * 4;
input = g_malloc (stride * height);
gdk_texture_download (texture, input, stride);
convert_rgba_to_rgb (data, width, height, stride);
jpeg_start_compress (&info, TRUE);
while (info.next_scanline < info.image_height)
{
row = &input[info.next_scanline * stride];
jpeg_write_scanlines (&info, &row, 1);
}
jpeg_finish_compress (&info);
g_free (input);
jpeg_destroy_compress (&info);
return g_bytes_new_with_free_func (data, size, (GDestroyNotify) free, NULL);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+43
View File
@@ -0,0 +1,43 @@
/* 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);
GBytes *gdk_save_jpeg (GdkTexture *texture);
static inline gboolean
gdk_is_jpeg (GBytes *bytes)
{
const char *data;
gsize size;
data = g_bytes_get_data (bytes, &size);
return size > strlen (JPEG_SIGNATURE) &&
memcmp (data, JPEG_SIGNATURE, strlen (JPEG_SIGNATURE)) == 0;
}
#endif
+577
View File
@@ -0,0 +1,577 @@
/* 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 "gdkintl.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
#include "gdktexture.h"
#include "gdktextureprivate.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.
*/
/* {{{ Callbacks */
/* No sigsetjmp on Windows */
#ifndef HAVE_SIGSETJMP
#define sigjmp_buf jmp_buf
#define sigsetjmp(jb, x) setjmp(jb)
#define siglongjmp longjmp
#endif
typedef struct
{
guchar *data;
gsize size;
gsize position;
} png_io;
static void
png_read_func (png_structp png,
png_bytep data,
png_size_t size)
{
png_io *io;
io = png_get_io_ptr (png);
if (io->position + size > io->size)
png_error (png, "Read past EOF");
memcpy (data, io->data + io->position, size);
io->position += size;
}
static void
png_write_func (png_structp png,
png_bytep data,
png_size_t size)
{
png_io *io;
io = png_get_io_ptr (png);
if (io->position > io->size ||
io->size - io->position < size)
{
io->size = io->position + size;
io->data = g_realloc (io->data, io->size);
}
memcpy (io->data + io->position, data, size);
io->position += size;
}
static void
png_flush_func (png_structp png)
{
}
static png_voidp
png_malloc_callback (png_structp o,
png_size_t size)
{
return g_try_malloc (size);
}
static void
png_free_callback (png_structp o,
png_voidp x)
{
g_free (x);
}
static void
png_simple_error_callback (png_structp png,
png_const_charp error_msg)
{
GError **error = png_get_error_ptr (png);
if (error && !*error)
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
_("Error reading png (%s)"), error_msg);
longjmp (png_jmpbuf (png), 1);
}
static void
png_simple_warning_callback (png_structp png,
png_const_charp error_msg)
{
}
/* }}} */
/* {{{ Format conversion */
static void
unpremultiply (guchar *data,
int width,
int height)
{
gsize x, y;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
guchar *b = &data[x * 4];
guint32 pixel;
guchar alpha;
memcpy (&pixel, b, sizeof (guint32));
alpha = (pixel & 0xff000000) >> 24;
if (alpha == 0)
{
b[0] = 0;
b[1] = 0;
b[2] = 0;
b[3] = 0;
}
else
{
b[0] = (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
b[1] = (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
b[2] = (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
b[3] = alpha;
}
}
data += width * 4;
}
}
static void
unpremultiply_float_to_16bit (guchar *data,
int width,
int height)
{
gsize x, y;
float *src = (float *)data;;
guint16 *dest = (guint16 *)data;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
float r, g, b, a;
r = src[0];
g = src[1];
b = src[2];
a = src[3];
if (a == 0)
{
dest[0] = 0;
dest[1] = 0;
dest[2] = 0;
dest[3] = 0;
}
else
{
dest[0] = (guint16) CLAMP (65536.f * r / a, 0.f, 65535.f);
dest[1] = (guint16) CLAMP (65536.f * g / a, 0.f, 65535.f);
dest[2] = (guint16) CLAMP (65536.f * b / a, 0.f, 65535.f);
dest[3] = (guint16) CLAMP (65536.f * a, 0.f, 65535.f);
}
dest += 4;
src += 4;
}
}
}
static inline int
multiply_alpha (int alpha, int color)
{
int temp = (alpha * color) + 0x80;
return ((temp + (temp >> 8)) >> 8);
}
static void
premultiply_data (png_structp png,
png_row_infop row_info,
png_bytep data)
{
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4)
{
uint8_t *base = &data[i];
uint8_t alpha = base[3];
uint32_t p;
if (alpha == 0)
{
p = 0;
}
else
{
uint8_t red = base[0];
uint8_t green = base[1];
uint8_t blue = base[2];
if (alpha != 0xff)
{
red = multiply_alpha (alpha, red);
green = multiply_alpha (alpha, green);
blue = multiply_alpha (alpha, blue);
}
p = ((uint32_t)alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
}
memcpy (base, &p, sizeof (uint32_t));
}
}
static void
convert_bytes_to_data (png_structp png,
png_row_infop row_info,
png_bytep data)
{
unsigned int i;
for (i = 0; i < row_info->rowbytes; i += 4)
{
uint8_t *base = &data[i];
uint8_t red = base[0];
uint8_t green = base[1];
uint8_t blue = base[2];
uint32_t pixel;
pixel = (0xffu << 24) | (red << 16) | (green << 8) | (blue << 0);
memcpy (base, &pixel, sizeof (uint32_t));
}
}
static void
premultiply_16bit (guchar *data,
int width,
int height,
int stride)
{
gsize x, y;
guint16 *src;
for (y = 0; y < height; y++)
{
src = (guint16 *)data;
for (x = 0; x < width; x++)
{
float alpha = src[x * 4 + 3] / 65535.f;
src[x * 4 ] = (guint16) CLAMP (src[x * 4 ] * alpha, 0.f, 65535.f);
src[x * 4 + 1] = (guint16) CLAMP (src[x * 4 + 1] * alpha, 0.f, 65535.f);
src[x * 4 + 2] = (guint16) CLAMP (src[x * 4 + 2] * alpha, 0.f, 65535.f);
}
data += stride;
}
}
/* }}} */
/* {{{ Public API */
GdkTexture *
gdk_load_png (GBytes *bytes,
GError **error)
{
png_io io;
png_struct *png = NULL;
png_info *info;
guint width, height;
int depth, color_type;
int interlace, stride;
GdkMemoryFormat format;
guchar *buffer = NULL;
guchar **row_pointers = NULL;
GBytes *out_bytes;
GdkTexture *texture;
int bpp;
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
io.data = (guchar *)g_bytes_get_data (bytes, &io.size);
io.position = 0;
png = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING,
error,
png_simple_error_callback,
png_simple_warning_callback,
NULL,
png_malloc_callback,
png_free_callback);
if (png == NULL)
g_error ("Out of memory");
info = png_create_info_struct (png);
if (info == NULL)
g_error ("Out of memory");
png_set_read_fn (png, &io, png_read_func);
if (sigsetjmp (png_jmpbuf (png), 1))
{
g_free (buffer);
g_free (row_pointers);
png_destroy_read_struct (&png, &info, NULL);
return NULL;
}
png_read_info (png, info);
png_get_IHDR (png, info,
&width, &height, &depth,
&color_type, &interlace, NULL, NULL);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb (png);
if (color_type == PNG_COLOR_TYPE_GRAY)
png_set_expand_gray_1_2_4_to_8 (png);
if (png_get_valid (png, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha (png);
if (depth == 8)
png_set_filler (png, 0xff, PNG_FILLER_AFTER);
if (depth < 8)
png_set_packing (png);
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb (png);
if (interlace != PNG_INTERLACE_NONE)
png_set_interlace_handling (png);
png_read_update_info (png, info);
png_get_IHDR (png, info,
&width, &height, &depth,
&color_type, &interlace, NULL, NULL);
if ((depth != 8 && depth != 16) ||
!(color_type == PNG_COLOR_TYPE_RGB ||
color_type == PNG_COLOR_TYPE_RGB_ALPHA))
{
png_destroy_read_struct (&png, &info, NULL);
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT,
_("Failed to parse png image"));
return NULL;
}
switch (color_type)
{
case PNG_COLOR_TYPE_RGB_ALPHA:
if (depth == 8)
{
format = GDK_MEMORY_DEFAULT;
png_set_read_user_transform_fn (png, premultiply_data);
}
else
{
format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
png_set_swap (png);
#endif
}
break;
case PNG_COLOR_TYPE_RGB:
if (depth == 8)
{
format = GDK_MEMORY_DEFAULT;
png_set_read_user_transform_fn (png, convert_bytes_to_data);
}
else
{
format = GDK_MEMORY_R16G16B16;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
png_set_swap (png);
#endif
}
break;
default:
g_assert_not_reached ();
}
bpp = gdk_memory_format_bytes_per_pixel (format);
stride = width * bpp;
if (stride % 8)
stride += 8 - stride % 8;
buffer = g_try_malloc_n (height, stride);
row_pointers = g_try_malloc_n (height, sizeof (char *));
if (!buffer || !row_pointers)
{
g_free (buffer);
g_free (row_pointers);
png_destroy_read_struct (&png, &info, NULL);
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_TOO_LARGE,
_("Not enough memory for image size %ux%u"), width, height);
return NULL;
}
for (int i = 0; i < height; i++)
row_pointers[i] = &buffer[i * stride];
png_read_image (png, row_pointers);
png_read_end (png, info);
if (format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
premultiply_16bit (buffer, width, height, stride);
out_bytes = g_bytes_new_take (buffer, height * stride);
texture = gdk_memory_texture_new (width, height, format, out_bytes, stride);
g_bytes_unref (out_bytes);
g_free (row_pointers);
png_destroy_read_struct (&png, &info, NULL);
if (GDK_PROFILER_IS_RUNNING)
{
gint64 end = GDK_PROFILER_CURRENT_TIME;
if (end - before > 500000)
gdk_profiler_add_mark (before, end - before, "png load", NULL);
}
return texture;
}
GBytes *
gdk_save_png (GdkTexture *texture)
{
png_struct *png = NULL;
png_info *info;
png_io io = { NULL, 0, 0 };
guint width, height, stride;
guchar *data = NULL;
guchar *row;
int y;
GdkTexture *mtexture;
GdkMemoryFormat format;
int png_format;
int depth;
width = gdk_texture_get_width (texture);
height = gdk_texture_get_height (texture);
mtexture = gdk_texture_download_texture (texture);
format = gdk_memory_texture_get_format (GDK_MEMORY_TEXTURE (mtexture));
switch (format)
{
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_R8G8B8:
case GDK_MEMORY_B8G8R8:
stride = width * 4;
data = g_malloc_n (stride, height);
gdk_texture_download (mtexture, data, stride);
unpremultiply (data, width, height);
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
depth = 8;
break;
case GDK_MEMORY_R16G16B16:
case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED:
case GDK_MEMORY_R16G16B16_FLOAT:
case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED:
case GDK_MEMORY_R32G32B32_FLOAT:
case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED:
data = g_malloc_n (width * 16, height);
gdk_texture_download_float (mtexture, (float *)data, width * 4);
unpremultiply_float_to_16bit (data, width, height);
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
stride = width * 8;
depth = 16;
break;
case GDK_MEMORY_N_FORMATS:
default:
g_assert_not_reached ();
}
png = png_create_write_struct_2 (PNG_LIBPNG_VER_STRING, NULL,
png_simple_error_callback,
png_simple_warning_callback,
NULL,
png_malloc_callback,
png_free_callback);
if (!png)
return NULL;
info = png_create_info_struct (png);
if (!info)
{
png_destroy_read_struct (&png, NULL, NULL);
return NULL;
}
if (sigsetjmp (png_jmpbuf (png), 1))
{
g_free (data);
g_free (io.data);
png_destroy_read_struct (&png, &info, NULL);
return NULL;
}
png_set_write_fn (png, &io, png_write_func, png_flush_func);
png_set_IHDR (png, info, width, height, depth,
png_format,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info (png, info);
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
png_set_swap (png);
#endif
for (y = 0, row = data; y < height; y++, row += stride)
png_write_rows (png, &row, 1);
png_write_end (png, info);
png_destroy_write_struct (&png, &info);
g_free (data);
return g_bytes_new_take (io.data, io.size);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+43
View File
@@ -0,0 +1,43 @@
/* 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);
static inline gboolean
gdk_is_png (GBytes *bytes)
{
const char *data;
gsize size;
data = g_bytes_get_data (bytes, &size);
return size > strlen (PNG_SIGNATURE) &&
memcmp (data, PNG_SIGNATURE, strlen (PNG_SIGNATURE)) == 0;
}
#endif
+522
View File
@@ -0,0 +1,522 @@
/* 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 "gdkintl.h"
#include "gdkmemorytextureprivate.h"
#include "gdkprofilerprivate.h"
#include "gdktexture.h"
#include "gdktextureprivate.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_no_read (thandle_t handle,
tdata_t buffer,
tsize_t size)
{
return (tsize_t) -1;
}
static tsize_t
tiff_io_read (thandle_t handle,
tdata_t buffer,
tsize_t size)
{
TiffIO *io = (TiffIO *) handle;
gsize read;
if (io->position >= io->size)
return 0;
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)
{
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->position > io->size ||
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:
return -1;
case SEEK_SET:
break;
case SEEK_CUR:
offset += io->position;
break;
case SEEK_END:
offset += io->size;
break;
}
if (offset < 0)
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_no_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, (guint32 *)data, ORIENTATION_TOPLEFT, 1))
{
g_set_error_literal (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
_("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;
G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME;
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_try_malloc_n (height, stride);
if (!data)
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_TOO_LARGE,
_("Not enough memory for image size %ux%u"), width, height);
TIFFClose (tif);
return NULL;
}
line = data;
for (int y = 0; y < height; y++)
{
if (TIFFReadScanline (tif, line, y, 0) == -1)
{
g_set_error (error,
GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_CORRUPT_IMAGE,
_("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);
if (GDK_PROFILER_IS_RUNNING)
{
gint64 end = GDK_PROFILER_CURRENT_TIME;
if (end - before > 500000)
gdk_profiler_add_mark (before, end - before, "tiff load", NULL);
}
return texture;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+46
View File
@@ -0,0 +1,46 @@
/* 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);
static inline gboolean
gdk_is_tiff (GBytes *bytes)
{
const char *data;
gsize size;
data = g_bytes_get_data (bytes, &size);
return (size > strlen (TIFF_SIGNATURE1) &&
memcmp (data, TIFF_SIGNATURE1, strlen (TIFF_SIGNATURE1)) == 0) ||
(size > strlen (TIFF_SIGNATURE2) &&
memcmp (data, TIFF_SIGNATURE2, strlen (TIFF_SIGNATURE2)) == 0);
}
#endif
+9 -1
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',
@@ -199,6 +204,9 @@ gdk_deps = [
platform_gio_dep,
pangocairo_dep,
vulkan_dep,
png_dep,
tiff_dep,
jpeg_dep,
]
if profiler_enabled
@@ -255,7 +263,7 @@ endif
libgdk = static_library('gdk',
sources: [gdk_sources, gdk_backends_gen_headers, gdkconfig],
dependencies: gdk_deps + [libgtk_css_dep],
link_with: [libgtk_css, ],
link_with: [libgtk_css],
include_directories: [confinc, gdkx11_inc, wlinc],
c_args: libgdk_c_args + common_cflags,
link_whole: gdk_backends,
+1 -1
View File
@@ -39,7 +39,7 @@ typedef enum {
void gsk_cairo_blur_surface (cairo_surface_t *surface,
double radius,
GskBlurFlags flags);
int gsk_cairo_blur_compute_pixels (double radius);
int gsk_cairo_blur_compute_pixels (double radius) G_GNUC_CONST;
cairo_t * gsk_cairo_blur_start_drawing (cairo_t *cr,
float radius,
+1 -1
View File
@@ -8,7 +8,7 @@ G_BEGIN_DECLS
void gsk_ensure_resources (void);
int pango_glyph_string_num_glyphs (PangoGlyphString *glyphs);
int pango_glyph_string_num_glyphs (PangoGlyphString *glyphs) G_GNUC_PURE;
typedef struct _GskVulkanRender GskVulkanRender;
typedef struct _GskVulkanRenderPass GskVulkanRenderPass;
-13
View File
@@ -492,19 +492,6 @@ GskRenderNode * gsk_text_node_new (PangoFont
PangoGlyphString *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset);
GDK_AVAILABLE_IN_4_6
GskRenderNode * gsk_text_node_new_with_font_options (const cairo_font_options_t *options,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset);
GDK_AVAILABLE_IN_4_6
gboolean gsk_text_node_get_hint_metrics (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_6
gboolean gsk_text_node_get_antialias (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_4_6
cairo_hint_style_t gsk_text_node_get_hint_style (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
PangoFont * gsk_text_node_get_font (const GskRenderNode *node) G_GNUC_PURE;
GDK_AVAILABLE_IN_ALL
+32 -156
View File
@@ -4336,10 +4336,7 @@ struct _GskTextNode
GskRenderNode render_node;
PangoFont *font;
guint has_color_glyphs : 1;
guint hint_metrics : 1;
guint antialias : 1;
guint hint_style : 3;
gboolean has_color_glyphs;
GdkRGBA color;
graphene_point_t offset;
@@ -4366,7 +4363,6 @@ gsk_text_node_draw (GskRenderNode *node,
{
GskTextNode *self = (GskTextNode *) node;
PangoGlyphString glyphs;
cairo_font_options_t *options;
glyphs.num_glyphs = self->num_glyphs;
glyphs.glyphs = self->glyphs;
@@ -4374,13 +4370,6 @@ gsk_text_node_draw (GskRenderNode *node,
cairo_save (cr);
options = cairo_font_options_create ();
cairo_font_options_set_hint_metrics (options, self->hint_metrics ? CAIRO_HINT_METRICS_ON : CAIRO_HINT_METRICS_OFF);
cairo_font_options_set_antialias (options, self->antialias ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
cairo_font_options_set_hint_style (options, self->hint_style);
cairo_set_font_options (cr, options);
cairo_font_options_destroy (options);
gdk_cairo_set_source_rgba (cr, &self->color);
cairo_translate (cr, self->offset.x, self->offset.y);
pango_cairo_show_glyph_string (cr, self->font, &glyphs);
@@ -4388,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,
@@ -4422,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);
@@ -4435,12 +4415,25 @@ gsk_text_node_diff (GskRenderNode *node1,
gsk_render_node_diff_impossible (node1, node2, region);
}
static GskRenderNode *
gsk_text_node_new_internal (const cairo_font_options_t *options,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset)
/**
* gsk_text_node_new:
* @font: the `PangoFont` containing the glyphs
* @glyphs: the `PangoGlyphString` to render
* @color: the foreground color to render with
* @offset: offset of the baseline
*
* Creates a render node that renders the given glyphs.
*
* Note that @color may not be used if the font contains
* color glyphs.
*
* Returns: (nullable) (transfer full) (type GskTextNode): a new `GskRenderNode`
*/
GskRenderNode *
gsk_text_node_new (PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset)
{
GskTextNode *self;
GskRenderNode *node;
@@ -4462,16 +4455,6 @@ gsk_text_node_new_internal (const cairo_font_options_t *options,
self->color = *color;
self->offset = *offset;
self->has_color_glyphs = FALSE;
self->antialias = TRUE;
self->hint_style = CAIRO_HINT_STYLE_NONE;
self->hint_metrics = FALSE;
if (options)
{
self->antialias = cairo_font_options_get_antialias (options) != CAIRO_ANTIALIAS_NONE;
self->hint_metrics = cairo_font_options_get_hint_metrics (options) == CAIRO_HINT_METRICS_ON;
self->hint_style = cairo_font_options_get_hint_style (options);
}
glyph_infos = g_malloc_n (glyphs->num_glyphs, sizeof (PangoGlyphInfo));
@@ -4502,117 +4485,6 @@ gsk_text_node_new_internal (const cairo_font_options_t *options,
return node;
}
/**
* gsk_text_node_new_with_font_options:
* @options: `cairo_font_options_t` to render with
* @font: the `PangoFont` containing the glyphs
* @glyphs: the `PangoGlyphString` to render
* @color: the foreground color to render with
* @offset: offset of the baseline
*
* Creates a render node that renders the given glyphs.
*
* Note that @color may not be used if the font contains
* color glyphs.
*
* Returns: (nullable) (transfer full) (type GskTextNode): a new `GskRenderNode`
*
* Since: 4.6
*/
GskRenderNode *
gsk_text_node_new_with_font_options (const cairo_font_options_t *options,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset)
{
return gsk_text_node_new_internal (options, font, glyphs, color, offset);
}
/**
* gsk_text_node_new:
* @font: the `PangoFont` containing the glyphs
* @glyphs: the `PangoGlyphString` to render
* @color: the foreground color to render with
* @offset: offset of the baseline
*
* Creates a render node that renders the given glyphs.
*
* Note that @color may not be used if the font contains
* color glyphs.
*
* Returns: (nullable) (transfer full) (type GskTextNode): a new `GskRenderNode`
*/
GskRenderNode *
gsk_text_node_new (PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
const graphene_point_t *offset)
{
return gsk_text_node_new_internal (NULL, font, glyphs, color, offset);
}
/**
* gsk_text_node_get_hint_metrics:
* @node: (type GskTextNode): a text `GskRenderNode`
*
* Retrieves whether metrics hinting is enabled for rendering.
*
* See the cairo [documentation](https://www.cairographics.org/manual/cairo-cairo-font-options-t.html#cairo-hint-metrics-t).
*
* Returns: whether metrics hinting is enabled
*
* Since: 4.6
*/
gboolean
gsk_text_node_get_hint_metrics (const GskRenderNode *node)
{
const GskTextNode *self = (const GskTextNode *) node;
return self->hint_metrics;
}
/**
* gsk_text_node_get_antialias:
* @node: (type GskTextNode): a text `GskRenderNode`
*
* Retrieves whether antialiasing is enabled for rendering.
*
* See the cairo [documentation](https://www.cairographics.org/manual/cairo-cairo-t.html#cairo-antialias-t).
* Note that GSK only supports grayscale antialiasing.
*
* Returns: whether antialiasing is enabled
*
* Since: 4.6
*/
gboolean
gsk_text_node_get_antialias (const GskRenderNode *node)
{
const GskTextNode *self = (const GskTextNode *) node;
return self->antialias;
}
/**
* gsk_text_node_get_hint_style:
* @node: (type GskTextNode): a text `GskRenderNode`
*
* Retrieves what style of font hinting is used for rendering.
*
* See the cairo [documentation](https://www.cairographics.org/manual/cairo-cairo-font-options-t.html#cairo-hint-style-t).
*
* Returns: what style of hinting is used
*
* Since: 4.6
*/
cairo_hint_style_t
gsk_text_node_get_hint_style (const GskRenderNode *node)
{
const GskTextNode *self = (const GskTextNode *) node;
return self->hint_style;
}
/**
* gsk_text_node_get_color:
* @node: (type GskTextNode): a text `GskRenderNode`
@@ -5802,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);
@@ -5811,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;
@@ -5818,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);
}
+20 -21
View File
@@ -85,24 +85,17 @@ parse_texture (GtkCssParser *parser,
scheme = g_uri_parse_scheme (url);
if (scheme && g_ascii_strcasecmp (scheme, "data") == 0)
{
GInputStream *stream;
GdkPixbuf *pixbuf;
GBytes *bytes;
texture = NULL;
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
{
texture = NULL;
}
}
else
@@ -802,6 +795,11 @@ parse_glyphs (GtkCssParser *parser,
gi.attr.is_cluster_start = 0;
else
gi.attr.is_cluster_start = 1;
if (gtk_css_parser_try_ident (parser, "color"))
gi.attr.is_color = 1;
else
gi.attr.is_color = 0;
}
pango_glyph_string_set_size (glyph_string, glyph_string->num_glyphs + 1);
@@ -2336,7 +2334,8 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
glyphs[i].geometry.width == ascii->glyphs[j].geometry.width &&
glyphs[i].geometry.x_offset == 0 &&
glyphs[i].geometry.y_offset == 0 &&
glyphs[i].attr.is_cluster_start)
glyphs[i].attr.is_cluster_start &&
!glyphs[i].attr.is_color)
{
switch (j + MIN_ASCII_GLYPH)
{
@@ -2366,6 +2365,7 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
g_string_append_printf (p, "%u ", glyphs[i].glyph);
string_append_double (p, (double) glyphs[i].geometry.width / PANGO_SCALE);
if (!glyphs[i].attr.is_cluster_start ||
glyphs[i].attr.is_color ||
glyphs[i].geometry.x_offset != 0 ||
glyphs[i].geometry.y_offset != 0)
{
@@ -2375,6 +2375,8 @@ gsk_text_node_serialize_glyphs (GskRenderNode *node,
string_append_double (p, (double) glyphs[i].geometry.y_offset / PANGO_SCALE);
if (!glyphs[i].attr.is_cluster_start)
g_string_append (p, " same-cluster");
if (!glyphs[i].attr.is_color)
g_string_append (p, " color");
}
if (i + 1 < n_glyphs)
@@ -2690,26 +2692,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;
+2 -2
View File
@@ -24,7 +24,7 @@ void gsk_rounded_rect_scale_affine (GskRoundedRect
float dx,
float dy);
gboolean gsk_rounded_rect_is_circular (const GskRoundedRect *self);
gboolean gsk_rounded_rect_is_circular (const GskRoundedRect *self) G_GNUC_PURE;
void gsk_rounded_rect_path (const GskRoundedRect *self,
cairo_t *cr);
@@ -33,7 +33,7 @@ void gsk_rounded_rect_to_float (const GskRounde
gboolean gsk_rounded_rect_equal (gconstpointer rect1,
gconstpointer rect2) G_GNUC_PURE;
char * gsk_rounded_rect_to_string (const GskRoundedRect *self);
char * gsk_rounded_rect_to_string (const GskRoundedRect *self) G_GNUC_MALLOC;
G_END_DECLS
+304 -36
View File
@@ -36,6 +36,8 @@
#include "gsktransformprivate.h"
/* {{{ Boilerplate */
struct _GskTransformClass
{
gsize struct_size;
@@ -119,7 +121,16 @@ gsk_transform_alloc (const GskTransformClass *transform_class,
return self;
}
/*** IDENTITY ***/
static void
gsk_transform_finalize (GskTransform *self)
{
self->transform_class->finalize (self);
gsk_transform_unref (self->next);
}
/* }}} */
/* {{{ IDENTITY */
static void
gsk_identity_transform_finalize (GskTransform *transform)
@@ -235,7 +246,8 @@ gsk_transform_is_identity (GskTransform *self)
(self->transform_class == &GSK_IDENTITY_TRANSFORM_CLASS && gsk_transform_is_identity (self->next));
}
/*** MATRIX ***/
/* }}} */
/* {{{ MATRIX */
typedef struct _GskMatrixTransform GskMatrixTransform;
@@ -466,7 +478,8 @@ gsk_transform_matrix (GskTransform *next,
return gsk_transform_matrix_with_category (next, matrix, GSK_TRANSFORM_CATEGORY_UNKNOWN);
}
/*** TRANSLATE ***/
/* }}} */
/* {{{ TRANSLATE */
typedef struct _GskTranslateTransform GskTranslateTransform;
@@ -662,7 +675,8 @@ gsk_transform_translate_3d (GskTransform *next,
return &result->parent;
}
/*** ROTATE ***/
/* }}} */
/* {{{ ROTATE */
typedef struct _GskRotateTransform GskRotateTransform;
@@ -873,7 +887,8 @@ gsk_transform_rotate (GskTransform *next,
return &result->parent;
}
/*** ROTATE 3D ***/
/* }}} */
/* {{{ ROTATE 3D */
typedef struct _GskRotate3dTransform GskRotate3dTransform;
@@ -997,7 +1012,182 @@ gsk_transform_rotate_3d (GskTransform *next,
return &result->parent;
}
/*** SCALE ***/
/* }}} */
/* {{{ SKEW */
typedef struct _GskSkewTransform GskSkewTransform;
struct _GskSkewTransform
{
GskTransform parent;
float skew_x;
float skew_y;
};
static void
gsk_skew_transform_finalize (GskTransform *self)
{
}
#define DEG_TO_RAD(x) ((x) / 180.f * G_PI)
#define RAD_TO_DEG(x) ((x) * 180.f / G_PI)
static void
gsk_skew_transform_to_matrix (GskTransform *transform,
graphene_matrix_t *out_matrix)
{
GskSkewTransform *self = (GskSkewTransform *) transform;
graphene_matrix_init_skew (out_matrix,
DEG_TO_RAD (self->skew_x),
DEG_TO_RAD (self->skew_y));
}
static void
gsk_skew_transform_apply_2d (GskTransform *transform,
float *out_xx,
float *out_yx,
float *out_xy,
float *out_yy,
float *out_dx,
float *out_dy)
{
graphene_matrix_t sm, mat;
gsk_skew_transform_to_matrix (transform, &sm);
graphene_matrix_init_from_2d (&mat, *out_xx, *out_yx,
*out_xy, *out_yy,
*out_dx, *out_dy);
graphene_matrix_multiply (&sm, &mat, &mat);
*out_xx = graphene_matrix_get_value (&mat, 0, 0);
*out_yx = graphene_matrix_get_value (&mat, 0, 1);
*out_xy = graphene_matrix_get_value (&mat, 1, 0);
*out_yy = graphene_matrix_get_value (&mat, 1, 1);
*out_dx = graphene_matrix_get_value (&mat, 3, 0);
*out_dy = graphene_matrix_get_value (&mat, 3, 1);
}
static GskTransform *
gsk_skew_transform_apply (GskTransform *transform,
GskTransform *apply_to)
{
GskSkewTransform *self = (GskSkewTransform *) transform;
return gsk_transform_skew (apply_to, self->skew_x, self->skew_y);
}
static void
gsk_skew_transform_print (GskTransform *transform,
GString *string)
{
GskSkewTransform *self = (GskSkewTransform *) transform;
if (self->skew_y == 0)
{
g_string_append (string, "skewX(");
string_append_double (string, self->skew_x);
g_string_append (string, ")");
}
else if (self->skew_x == 0)
{
g_string_append (string, "skewY(");
string_append_double (string, self->skew_y);
g_string_append (string, ")");
}
else
{
g_string_append (string, "skew(");
string_append_double (string, self->skew_x);
g_string_append (string, ", ");
string_append_double (string, self->skew_y);
g_string_append (string, ")");
}
}
static GskTransform *
gsk_skew_transform_invert (GskTransform *transform,
GskTransform *next)
{
GskSkewTransform *self = (GskSkewTransform *) transform;
float tx, ty;
graphene_matrix_t matrix;
tx = tanf (DEG_TO_RAD (self->skew_x));
ty = tanf (DEG_TO_RAD (self->skew_y));
graphene_matrix_init_from_2d (&matrix,
1 / (1 - tx * ty),
- ty / (1 - tx * ty),
- tx / (1 - tx * ty),
1 / (1 - tx * ty),
0, 0);
return gsk_transform_matrix_with_category (next,
&matrix,
GSK_TRANSFORM_CATEGORY_2D);
}
static gboolean
gsk_skew_transform_equal (GskTransform *first_transform,
GskTransform *second_transform)
{
GskSkewTransform *first = (GskSkewTransform *) first_transform;
GskSkewTransform *second = (GskSkewTransform *) second_transform;
return G_APPROX_VALUE (first->skew_x, second->skew_x, FLT_EPSILON) &&
G_APPROX_VALUE (first->skew_y, second->skew_y, FLT_EPSILON);
}
static const GskTransformClass GSK_SKEW_TRANSFORM_CLASS =
{
sizeof (GskSkewTransform),
"GskSkewTransform",
gsk_skew_transform_finalize,
gsk_skew_transform_to_matrix,
gsk_skew_transform_apply_2d,
NULL,
NULL,
gsk_skew_transform_print,
gsk_skew_transform_apply,
gsk_skew_transform_invert,
gsk_skew_transform_equal,
};
/**
* gsk_transform_skew:
* @next: (nullable) (transfer full): the next transform
* @skew_x: skew factor, in degrees, on the X axis
* @skew_y: skew factor, in degrees, on the Y axis
*
* Applies a skew transform.
*
* Returns: The new transform
*
* Since: 4.6
*/
GskTransform *
gsk_transform_skew (GskTransform *next,
float skew_x,
float skew_y)
{
GskSkewTransform *result;
if (skew_x == 0 && skew_y == 0)
return next;
result = gsk_transform_alloc (&GSK_SKEW_TRANSFORM_CLASS,
GSK_TRANSFORM_CATEGORY_2D,
next);
result->skew_x = skew_x;
result->skew_y = skew_y;
return &result->parent;
}
/* }}} */
/* {{{ SCALE */
typedef struct _GskScaleTransform GskScaleTransform;
@@ -1200,7 +1390,8 @@ gsk_transform_scale_3d (GskTransform *next,
return &result->parent;
}
/*** PERSPECTIVE ***/
/* }}} */
/* {{{ PERSPECTIVE */
typedef struct _GskPerspectiveTransform GskPerspectiveTransform;
@@ -1323,15 +1514,8 @@ gsk_transform_perspective (GskTransform *next,
return &result->parent;
}
/*** PUBLIC API ***/
static void
gsk_transform_finalize (GskTransform *self)
{
self->transform_class->finalize (self);
gsk_transform_unref (self->next);
}
/* }}} */
/* {{{ PUBLIC API */
/**
* gsk_transform_ref:
@@ -1516,6 +1700,95 @@ gsk_transform_to_2d (GskTransform *self,
out_dx, out_dy);
}
/**
* gsk_transform_to_2d_components:
* @self: a `GskTransform`
* @out_skew_x: (out): return location for the skew factor
* in the x direction
* @out_skew_y: (out): return location for the skew factor
* in the y direction
* @out_scale_x: (out): return location for the scale
* factor in the x direction
* @out_scale_y: (out): return location for the scale
* factor in the y direction
* @out_angle: (out): return location for the rotation angle
* @out_dx: (out): return location for the translation
* in the x direction
* @out_dy: (out): return location for the translation
* in the y direction
*
* Converts a `GskTransform` to 2D transformation factors.
*
* To recreate an equivalent transform from the factors returned
* by this function, use
*
* gsk_transform_skew (
* gsk_transform_scale (
* gsk_transform_rotate (
* gsk_transform_translate (NULL, &GRAPHENE_POINT_T (dx, dy)),
* angle),
* scale_x, scale_y),
* skew_x, skew_y)
*
* @self must be a 2D transformation. If you are not sure, use
*
* gsk_transform_get_category() >= %GSK_TRANSFORM_CATEGORY_2D
*
* to check.
*
* Since: 4.6
*/
void
gsk_transform_to_2d_components (GskTransform *self,
float *out_skew_x,
float *out_skew_y,
float *out_scale_x,
float *out_scale_y,
float *out_angle,
float *out_dx,
float *out_dy)
{
float a, b, c, d, e, f;
gsk_transform_to_2d (self, &a, &b, &c, &d, &e, &f);
*out_dx = e;
*out_dy = f;
#define sign(f) ((f) < 0 ? -1 : 1)
if (a != 0 || b != 0)
{
float det = a * d - b * c;
float r = sqrtf (a*a + b*b);
*out_angle = RAD_TO_DEG (sign (b) * acosf (a / r));
*out_scale_x = r;
*out_scale_y = det / r;
*out_skew_x = RAD_TO_DEG (atanf ((a*c + b*d) / (r*r)));
*out_skew_y = 0;
}
else if (c != 0 || d != 0)
{
float det = a * d - b * c;
float s = sqrtf (c*c + d*d);
*out_angle = RAD_TO_DEG (G_PI/2 - sign (d) * acosf (-c / s));
*out_scale_x = det / s;
*out_scale_y = s;
*out_skew_x = 0;
*out_skew_y = RAD_TO_DEG (atanf ((a*c + b*d) / (s*s)));
}
else
{
*out_angle = 0;
*out_scale_x = 0;
*out_scale_y = 0;
*out_skew_x = 0;
*out_skew_y = 0;
}
}
/**
* gsk_transform_to_affine:
* @self: a `GskTransform`
@@ -1530,7 +1803,14 @@ gsk_transform_to_2d (GskTransform *self,
*
* Converts a `GskTransform` to 2D affine transformation factors.
*
* @self must be a 2D transformation. If you are not
* To recreate an equivalent transform from the factors returned
* by this function, use
*
* gsk_transform_scale (gsk_transform_translate (NULL,
* &GRAPHENE_POINT_T (dx, dy)),
* sx, sy)
*
* @self must be a 2D affine transformation. If you are not
* sure, use
*
* gsk_transform_get_category() >= %GSK_TRANSFORM_CATEGORY_2D_AFFINE
@@ -2040,40 +2320,24 @@ gsk_transform_parser_parse (GtkCssParser *parser,
}
else if (gtk_css_token_is_function (token, "skew"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 2, 2, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
f[1] = f[1] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, f[0], f[1]);
transform = gsk_transform_matrix (transform, &matrix);
transform = gsk_transform_skew (transform, f[0], f[1]);
}
else if (gtk_css_token_is_function (token, "skewX"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, f[0], 0);
transform = gsk_transform_matrix (transform, &matrix);
transform = gsk_transform_skew (transform, f[0], 0);
}
else if (gtk_css_token_is_function (token, "skewY"))
{
graphene_matrix_t matrix;
if (!gtk_css_parser_consume_function (parser, 1, 1, gsk_transform_parse_float, f))
goto fail;
f[0] = f[0] / 180.0 * G_PI;
graphene_matrix_init_skew (&matrix, 0, f[0]);
transform = gsk_transform_matrix (transform, &matrix);
transform = gsk_transform_skew (transform, 0, f[0]);
}
else
{
@@ -2219,3 +2483,7 @@ gsk_matrix_transform_bounds (const graphene_matrix_t *m,
gsk_matrix_transform_rect (m, r, &q);
graphene_quad_bounds (&q, res);
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */
+13
View File
@@ -59,6 +59,15 @@ void gsk_transform_to_2d (GskTransform
float *out_yy,
float *out_dx,
float *out_dy);
GDK_AVAILABLE_IN_4_6
void gsk_transform_to_2d_components (GskTransform *self,
float *out_skew_x,
float *out_skew_y,
float *out_scale_x,
float *out_scale_y,
float *out_angle,
float *out_dx,
float *out_dy);
GDK_AVAILABLE_IN_ALL
void gsk_transform_to_affine (GskTransform *self,
float *out_scale_x,
@@ -92,6 +101,10 @@ GskTransform * gsk_transform_translate (GskTransform
GDK_AVAILABLE_IN_ALL
GskTransform * gsk_transform_translate_3d (GskTransform *next,
const graphene_point3d_t *point) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_4_6
GskTransform * gsk_transform_skew (GskTransform *next,
float skew_x,
float skew_y) G_GNUC_WARN_UNUSED_RESULT;
GDK_AVAILABLE_IN_ALL
GskTransform * gsk_transform_rotate (GskTransform *next,
float angle) G_GNUC_WARN_UNUSED_RESULT;
+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 -6
View File
@@ -197,9 +197,10 @@ gsk_ngl_command_queue_capture_png (GskNglCommandQueue *self,
guint height,
gboolean flip_y)
{
cairo_surface_t *surface;
guint8 *data;
guint stride;
guint8 *data;
GBytes *bytes;
GdkTexture *texture;
g_assert (GSK_IS_NGL_COMMAND_QUEUE (self));
g_assert (filename != NULL);
@@ -222,11 +223,12 @@ gsk_ngl_command_queue_capture_png (GskNglCommandQueue *self,
data = flipped;
}
surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, width, height, stride);
cairo_surface_write_to_png (surface, filename);
bytes = g_bytes_new_take (data, height * stride);
texture = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride);
g_bytes_unref (bytes);
cairo_surface_destroy (surface);
g_free (data);
gdk_texture_save_to_png (texture, filename);
g_object_unref (texture);
}
static inline gboolean
+18 -31
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,
@@ -1142,20 +1131,18 @@ gsk_ngl_driver_lookup_shader (GskNglDriver *self,
#ifdef G_ENABLE_DEBUG
static void
write_atlas_to_png (GskNglTextureAtlas *atlas,
write_atlas_to_png (GskNglDriver *driver,
GskNglTextureAtlas *atlas,
const char *filename)
{
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, atlas->width);
guchar *data = g_malloc (atlas->height * stride);
cairo_surface_t *s;
GdkTexture *texture;
glBindTexture (GL_TEXTURE_2D, atlas->texture_id);
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, atlas->width, atlas->height, stride);
cairo_surface_write_to_png (s, filename);
cairo_surface_destroy (s);
g_free (data);
texture = gdk_gl_texture_new (gsk_ngl_driver_get_context (driver),
atlas->texture_id,
atlas->width, atlas->height,
NULL, NULL);
gdk_texture_save_to_png (texture, filename);
g_object_unref (texture);
}
void
@@ -1175,7 +1162,7 @@ gsk_ngl_driver_save_atlases_to_png (GskNglDriver *self,
G_DIR_SEPARATOR_S,
(int)self->current_frame_id,
atlas->texture_id);
write_atlas_to_png (atlas, filename);
write_atlas_to_png (self, atlas, filename);
g_free (filename);
}
}
+13 -18
View File
@@ -132,7 +132,8 @@ gsk_ngl_glyph_library_create_surface (GskNglGlyphLibrary *self,
int stride,
int width,
int height,
double device_scale)
int uwidth,
int uheight)
{
cairo_surface_t *surface;
gsize n_bytes;
@@ -153,7 +154,7 @@ gsk_ngl_glyph_library_create_surface (GskNglGlyphLibrary *self,
surface = cairo_image_surface_create_for_data (self->surface_data,
CAIRO_FORMAT_ARGB32,
width, height, stride);
cairo_surface_set_device_scale (surface, device_scale, device_scale);
cairo_surface_set_device_scale (surface, width / (double)uwidth, height / (double)uheight);
return surface;
}
@@ -166,19 +167,11 @@ render_glyph (cairo_surface_t *surface,
{
cairo_t *cr;
cairo_glyph_t glyph;
cairo_font_options_t *options;
g_assert (surface != NULL);
g_assert (scaled_font != NULL);
cr = cairo_create (surface);
options = cairo_font_options_create ();
cairo_font_options_set_hint_metrics (options, key->hint_metrics ? CAIRO_HINT_METRICS_ON : CAIRO_HINT_METRICS_OFF);
cairo_font_options_set_antialias (options, key->antialias ? CAIRO_ANTIALIAS_GRAY : CAIRO_ANTIALIAS_NONE);
cairo_font_options_set_hint_style (options, key->hint_style);
cairo_set_font_options (cr, options);
cairo_font_options_destroy (options);
cairo_set_scaled_font (cr, scaled_font);
cairo_set_source_rgba (cr, 1, 1, 1, 1);
@@ -200,7 +193,8 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self,
int y,
int width,
int height,
double device_scale)
int uwidth,
int uheight)
{
GskNglTextureLibrary *tl = (GskNglTextureLibrary *)self;
G_GNUC_UNUSED gint64 start_time = GDK_PROFILER_CURRENT_TIME;
@@ -228,7 +222,7 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self,
"Uploading glyph %d",
key->glyph);
surface = gsk_ngl_glyph_library_create_surface (self, stride, width, height, device_scale);
surface = gsk_ngl_glyph_library_create_surface (self, stride, width, height, uwidth, uheight);
render_glyph (surface, scaled_font, key, value);
texture_id = GSK_NGL_TEXTURE_ATLAS_ENTRY_TEXTURE (value);
@@ -243,7 +237,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,
@@ -297,10 +291,10 @@ gsk_ngl_glyph_library_add (GskNglGlyphLibrary *self,
pango_font_get_glyph_extents (key->font, key->glyph, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL);
if (key->xshift != 0)
ink_rect.width++;
if (key->yshift != 0)
ink_rect.height++;
ink_rect.x -= 1;
ink_rect.width += 2;
ink_rect.y -= 1;
ink_rect.height += 2;
width = (int) ceil (ink_rect.width * key->scale / 1024.0);
height = (int) ceil (ink_rect.height * key->scale / 1024.0);
@@ -323,7 +317,8 @@ gsk_ngl_glyph_library_add (GskNglGlyphLibrary *self,
packed_y + 1,
width,
height,
key->scale / 1024.0);
ink_rect.width,
ink_rect.height);
*out_value = value;
+1 -4
View File
@@ -35,10 +35,7 @@ typedef struct _GskNglGlyphKey
PangoGlyph glyph;
guint xshift : 2;
guint yshift : 2;
guint hint_metrics : 1;
guint antialias : 1;
guint hint_style : 3;
guint scale : 23; /* times 1024 */
guint scale : 28; /* times 1024 */
} GskNglGlyphKey;
typedef struct _GskNglGlyphValue
+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;
+92 -27
View File
@@ -252,6 +252,9 @@ node_supports_transform (const GskRenderNode *node)
case GSK_TEXT_NODE:
return TRUE;
case GSK_SHADOW_NODE:
return node_supports_transform (gsk_shadow_node_get_child (node));
case GSK_TRANSFORM_NODE:
return node_supports_transform (gsk_transform_node_get_child (node));
@@ -450,10 +453,21 @@ extract_matrix_metadata (GskNglRenderModelview *modelview)
&modelview->dx, &modelview->dy);
break;
case GSK_TRANSFORM_CATEGORY_2D:
{
float xx, xy, yx, yy, dx, dy;
gsk_transform_to_2d (modelview->transform,
&xx, &xy, &yx, &yy, &dx, &dy);
modelview->scale_x = sqrtf (xx * xx + xy * xy);
modelview->scale_y = sqrtf (yx * yx + yy * yy);
}
break;
case GSK_TRANSFORM_CATEGORY_UNKNOWN:
case GSK_TRANSFORM_CATEGORY_ANY:
case GSK_TRANSFORM_CATEGORY_3D:
case GSK_TRANSFORM_CATEGORY_2D:
{
graphene_vec3_t col1;
graphene_vec3_t col2;
@@ -1734,7 +1748,7 @@ gsk_ngl_render_job_visit_rect_border_node (GskNglRenderJob *job,
{
rgba_to_half (&colors[2], color);
gsk_ngl_render_job_draw_rect_with_color (job,
&GRAPHENE_RECT_INIT (origin->x + widths[3], origin->y + size->height - widths[2], size->width - widths[1], widths[2]),
&GRAPHENE_RECT_INIT (origin->x + widths[3], origin->y + size->height - widths[2], size->width - widths[3], widths[2]),
color);
}
@@ -2768,6 +2782,58 @@ gsk_ngl_render_job_visit_cross_fade_node (GskNglRenderJob *job,
gsk_ngl_render_job_end_draw (job);
}
static gboolean
is_non_branching (const GskRenderNode *node)
{
switch ((int)gsk_render_node_get_node_type (node))
{
case GSK_COLOR_NODE:
case GSK_LINEAR_GRADIENT_NODE:
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_RADIAL_GRADIENT_NODE:
case GSK_REPEATING_RADIAL_GRADIENT_NODE:
case GSK_CONIC_GRADIENT_NODE:
case GSK_BORDER_NODE:
case GSK_TEXTURE_NODE:
case GSK_INSET_SHADOW_NODE:
case GSK_OUTSET_SHADOW_NODE:
case GSK_TEXT_NODE:
case GSK_CAIRO_NODE:
return TRUE;
case GSK_TRANSFORM_NODE:
return is_non_branching (gsk_transform_node_get_child (node));
case GSK_OPACITY_NODE:
return is_non_branching (gsk_opacity_node_get_child (node));
case GSK_COLOR_MATRIX_NODE:
return is_non_branching (gsk_color_matrix_node_get_child (node));
case GSK_CLIP_NODE:
return is_non_branching (gsk_clip_node_get_child (node));
case GSK_ROUNDED_CLIP_NODE:
return is_non_branching (gsk_rounded_clip_node_get_child (node));
case GSK_SHADOW_NODE:
return is_non_branching (gsk_shadow_node_get_child (node));
case GSK_BLUR_NODE:
return is_non_branching (gsk_shadow_node_get_child (node));
case GSK_DEBUG_NODE:
return is_non_branching (gsk_debug_node_get_child (node));
case GSK_CONTAINER_NODE:
return gsk_container_node_get_n_children (node) == 1 &&
is_non_branching (gsk_container_node_get_child (node, 0));
default:
return FALSE;
}
}
static inline void
gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
const GskRenderNode *node)
@@ -2780,7 +2846,16 @@ gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
{
float prev_alpha = gsk_ngl_render_job_set_alpha (job, new_alpha);
if (gsk_render_node_get_node_type (child) == GSK_CONTAINER_NODE)
/* Handle a few easy cases without offscreen. We bail out
* as soon as we see nodes with multiple children - in theory,
* we would only need offscreens for overlapping children.
*/
if (is_non_branching (child))
{
gsk_ngl_render_job_visit_node (job, child);
gsk_ngl_render_job_set_alpha (job, prev_alpha);
}
else
{
GskNglRenderOffscreen offscreen = {0};
@@ -2788,9 +2863,7 @@ gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
offscreen.force_offscreen = TRUE;
offscreen.reset_clip = TRUE;
/* The semantics of an opacity node mandate that when, e.g., two
* color nodes overlap, there may not be any blending between them.
*/
/* Note: offscreen rendering resets alpha to 1.0 */
if (!gsk_ngl_render_job_visit_node_with_offscreen (job, child, &offscreen))
return;
@@ -2805,10 +2878,6 @@ gsk_ngl_render_job_visit_opacity_node (GskNglRenderJob *job,
gsk_ngl_render_job_draw_offscreen (job, &node->bounds, &offscreen);
gsk_ngl_render_job_end_draw (job);
}
else
{
gsk_ngl_render_job_visit_node (job, child);
}
gsk_ngl_render_job_set_alpha (job, prev_alpha);
}
@@ -2875,16 +2944,9 @@ gsk_ngl_render_job_visit_text_node (GskNglRenderJob *job,
rgba_to_half (color, cc);
/* We have 23 bits in the key for the scale */
g_assert (text_scale * 1024 < (1 << 24));
lookup.font = (PangoFont *)font;
lookup.scale = (guint) (text_scale * 1024);
lookup.hint_metrics = gsk_text_node_get_hint_metrics (node);
lookup.antialias = gsk_text_node_get_antialias (node);
lookup.hint_style = gsk_text_node_get_hint_style (node);
yshift = compute_phase_and_pos (y, &ypos);
gsk_ngl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, coloring));
@@ -3007,21 +3069,24 @@ gsk_ngl_render_job_visit_shadow_node (GskNglRenderJob *job,
graphene_rect_t bounds;
guint16 color[4];
if (shadow->radius == 0 &&
gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
{
gsk_ngl_render_job_offset (job, dx, dy);
gsk_ngl_render_job_visit_text_node (job, shadow_child, &shadow->color, TRUE);
gsk_ngl_render_job_offset (job, -dx, -dy);
continue;
}
if (RGBA_IS_CLEAR (&shadow->color))
continue;
if (node_is_invisible (shadow_child))
continue;
if (shadow->radius == 0 &&
gsk_render_node_get_node_type (shadow_child) == GSK_TEXT_NODE)
{
if (dx != 0 || dy != 0)
{
gsk_ngl_render_job_offset (job, dx, dy);
gsk_ngl_render_job_visit_text_node (job, shadow_child, &shadow->color, TRUE);
gsk_ngl_render_job_offset (job, -dx, -dy);
}
continue;
}
if (shadow->radius > 0)
{
float min_x;
@@ -4006,7 +4071,7 @@ gsk_ngl_render_job_new (GskNglDriver *driver,
job->scale_y = scale_factor;
job->viewport = *viewport;
gsk_ngl_render_job_set_alpha (job, 1.0);
gsk_ngl_render_job_set_alpha (job, 1.0f);
gsk_ngl_render_job_set_projection_from_rect (job, viewport, NULL);
gsk_ngl_render_job_set_modelview (job, gsk_transform_scale (NULL, scale_factor, scale_factor));
+10 -13
View File
@@ -204,25 +204,22 @@ gsk_ngl_shadow_library_lookup (GskNglShadowLibrary *self,
#if 0
static void
write_shadow_to_png (const Shadow *shadow)
write_shadow_to_png (GskNglDriver *driver,
const Shadow *shadow)
{
int width = shadow->outline.bounds.size.width + (shadow->outline.bounds.origin.x * 2);
int height = shadow->outline.bounds.size.height + (shadow->outline.bounds.origin.y * 2);
int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width);
guchar *data = g_malloc (height * stride);
cairo_surface_t *s;
char *filename = g_strdup_printf ("shadow_cache_%d_%d_%d.png",
width, height, shadow->texture_id);
GdkTexture *texture;
glBindTexture (GL_TEXTURE_2D, shadow->texture_id);
glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32,
width, height,
stride);
cairo_surface_write_to_png (s, filename);
texture = gdk_gl_texture_new (gsk_ngl_driver_get_context (driver),
shadow->texture_id,
width, height,
NULL, NULL);
gdk_texture_save_to_png (texture, filename);
cairo_surface_destroy (s);
g_free (data);
g_object_unref (texture);
g_free (filename);
}
#endif
@@ -240,7 +237,7 @@ gsk_ngl_shadow_library_begin_frame (GskNglShadowLibrary *self)
for (i = 0, p = self->shadows->len; i < p; i++)
{
const Shadow *shadow = &g_array_index (self->shadows, Shadow, i);
write_shadow_to_png (shadow);
write_shadow_to_png (self->driver, shadow);
}
#endif
+1 -1
View File
@@ -167,7 +167,7 @@ gsk_ngl_uniform_state_get_value (GskNglUniformState *state,
return gsk_ngl_uniform_state_init_value (state, program, format, array_count, key, out_mapping);
}
static inline guint
G_GNUC_PURE static inline guint
gsk_ngl_uniform_state_align (guint current_pos,
guint size)
{
+7 -7
View File
@@ -63,13 +63,13 @@ GtkCssParser * gtk_css_parser_new_for_bytes (GBytes
GtkCssParser * gtk_css_parser_ref (GtkCssParser *self);
void gtk_css_parser_unref (GtkCssParser *self);
GFile * gtk_css_parser_get_file (GtkCssParser *self);
GFile * gtk_css_parser_get_file (GtkCssParser *self) G_GNUC_PURE;
GFile * gtk_css_parser_resolve_url (GtkCssParser *self,
const char *url);
const GtkCssLocation * gtk_css_parser_get_start_location (GtkCssParser *self);
const GtkCssLocation * gtk_css_parser_get_end_location (GtkCssParser *self);
const GtkCssLocation * gtk_css_parser_get_block_location (GtkCssParser *self);
const GtkCssLocation * gtk_css_parser_get_start_location (GtkCssParser *self) G_GNUC_PURE;
const GtkCssLocation * gtk_css_parser_get_end_location (GtkCssParser *self) G_GNUC_PURE;
const GtkCssLocation * gtk_css_parser_get_block_location (GtkCssParser *self) G_GNUC_PURE;
const GtkCssToken * gtk_css_parser_peek_token (GtkCssParser *self);
const GtkCssToken * gtk_css_parser_get_token (GtkCssParser *self);
@@ -132,9 +132,9 @@ gboolean gtk_css_parser_try_at_keyword (GtkCssParser
gboolean gtk_css_parser_try_token (GtkCssParser *self,
GtkCssTokenType token_type);
char * gtk_css_parser_consume_ident (GtkCssParser *self) G_GNUC_WARN_UNUSED_RESULT;
char * gtk_css_parser_consume_string (GtkCssParser *self) G_GNUC_WARN_UNUSED_RESULT;
char * gtk_css_parser_consume_url (GtkCssParser *self) G_GNUC_WARN_UNUSED_RESULT;
char * gtk_css_parser_consume_ident (GtkCssParser *self) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
char * gtk_css_parser_consume_string (GtkCssParser *self) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
char * gtk_css_parser_consume_url (GtkCssParser *self) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
gboolean gtk_css_parser_consume_number (GtkCssParser *self,
double *number);
gboolean gtk_css_parser_consume_integer (GtkCssParser *self,
+1 -1
View File
@@ -129,7 +129,7 @@ GtkCssTokenizer * gtk_css_tokenizer_new (GBytes
GtkCssTokenizer * gtk_css_tokenizer_ref (GtkCssTokenizer *tokenizer);
void gtk_css_tokenizer_unref (GtkCssTokenizer *tokenizer);
const GtkCssLocation * gtk_css_tokenizer_get_location (GtkCssTokenizer *tokenizer);
const GtkCssLocation * gtk_css_tokenizer_get_location (GtkCssTokenizer *tokenizer) G_GNUC_CONST;
gboolean gtk_css_tokenizer_read_token (GtkCssTokenizer *tokenizer,
GtkCssToken *token,
+43 -65
View File
@@ -19,6 +19,9 @@
#include <gdk/gdk.h>
#include "gdkpixbufutilsprivate.h"
#include "gtkscalerprivate.h"
#include "gtkloaderprivate.h"
#include "gdk/gdktextureprivate.h"
static GdkPixbuf *
load_from_stream (GdkPixbufLoader *loader,
@@ -91,7 +94,6 @@ size_prepared_cb (GdkPixbufLoader *loader,
*/
GdkPixbuf *
_gdk_pixbuf_new_from_stream_scaled (GInputStream *stream,
const char *format,
double scale,
GCancellable *cancellable,
GError **error)
@@ -99,14 +101,7 @@ _gdk_pixbuf_new_from_stream_scaled (GInputStream *stream,
GdkPixbufLoader *loader;
GdkPixbuf *pixbuf;
if (format)
{
loader = gdk_pixbuf_loader_new_with_type (format, error);
if (!loader)
return NULL;
}
else
loader = gdk_pixbuf_loader_new ();
loader = gdk_pixbuf_loader_new ();
if (scale != 0)
g_signal_connect (loader, "size-prepared",
@@ -153,7 +148,6 @@ size_prepared_cb2 (GdkPixbufLoader *loader,
GdkPixbuf *
_gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream,
const char *format,
int width,
int height,
gboolean aspect,
@@ -164,14 +158,7 @@ _gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream,
GdkPixbuf *pixbuf;
int scales[3];
if (format)
{
loader = gdk_pixbuf_loader_new_with_type (format, error);
if (!loader)
return NULL;
}
else
loader = gdk_pixbuf_loader_new ();
loader = gdk_pixbuf_loader_new ();
scales[0] = width;
scales[1] = height;
@@ -188,11 +175,10 @@ _gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream,
GdkPixbuf *
_gdk_pixbuf_new_from_stream (GInputStream *stream,
const char *format,
GCancellable *cancellable,
GError **error)
{
return _gdk_pixbuf_new_from_stream_scaled (stream, format, 0, cancellable, error);
return _gdk_pixbuf_new_from_stream_scaled (stream, 0, cancellable, error);
}
/* Like gdk_pixbuf_new_from_resource_at_scale, but
@@ -201,7 +187,6 @@ _gdk_pixbuf_new_from_stream (GInputStream *stream,
*/
GdkPixbuf *
_gdk_pixbuf_new_from_resource_scaled (const char *resource_path,
const char *format,
double scale,
GError **error)
{
@@ -212,7 +197,7 @@ _gdk_pixbuf_new_from_resource_scaled (const char *resource_path,
if (stream == NULL)
return NULL;
pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, format, scale, NULL, error);
pixbuf = _gdk_pixbuf_new_from_stream_scaled (stream, scale, NULL, error);
g_object_unref (stream);
return pixbuf;
@@ -220,15 +205,13 @@ _gdk_pixbuf_new_from_resource_scaled (const char *resource_path,
GdkPixbuf *
_gdk_pixbuf_new_from_resource (const char *resource_path,
const char *format,
GError **error)
{
return _gdk_pixbuf_new_from_resource_scaled (resource_path, format, 0, error);
return _gdk_pixbuf_new_from_resource_scaled (resource_path, 0, error);
}
GdkPixbuf *
_gdk_pixbuf_new_from_resource_at_scale (const char *resource_path,
const char *format,
int width,
int height,
gboolean preserve_aspect,
@@ -241,7 +224,7 @@ _gdk_pixbuf_new_from_resource_at_scale (const char *resource_path,
if (stream == NULL)
return NULL;
pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream, format, width, height, preserve_aspect, NULL, error);
pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream, width, height, preserve_aspect, NULL, error);
g_object_unref (stream);
return pixbuf;
@@ -505,14 +488,7 @@ gtk_make_symbolic_pixbuf_from_file (GFile *file,
GdkTexture *
gtk_load_symbolic_texture_from_resource (const char *path)
{
GdkPixbuf *pixbuf;
GdkTexture *texture;
pixbuf = _gdk_pixbuf_new_from_resource (path, "png", NULL);
texture = gdk_texture_new_for_pixbuf (pixbuf);
g_object_unref (pixbuf);
return texture;
return gdk_texture_new_from_resource (path);
}
GdkTexture *
@@ -546,7 +522,7 @@ gtk_load_symbolic_texture_from_file (GFile *file)
if (stream == NULL)
return NULL;
pixbuf = _gdk_pixbuf_new_from_stream (stream, "png", NULL, NULL);
pixbuf = _gdk_pixbuf_new_from_stream (stream, NULL, NULL);
g_object_unref (stream);
if (pixbuf == NULL)
return NULL;
@@ -604,43 +580,45 @@ GdkPaintable *
gdk_paintable_new_from_bytes_scaled (GBytes *bytes,
int scale_factor)
{
GdkPixbufLoader *loader;
GdkPixbuf *pixbuf = NULL;
LoaderData loader_data;
GdkTexture *texture;
GdkPaintable *inner;
GdkPaintable *paintable;
loader_data.scale_factor = scale_factor;
loader = gdk_pixbuf_loader_new ();
g_signal_connect (loader, "size-prepared",
G_CALLBACK (on_loader_size_prepared), &loader_data);
if (!gdk_pixbuf_loader_write_bytes (loader, bytes, NULL))
goto out;
if (!gdk_pixbuf_loader_close (loader, NULL))
goto out;
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
if (pixbuf != NULL)
g_object_ref (pixbuf);
out:
gdk_pixbuf_loader_close (loader, NULL);
g_object_unref (loader);
if (!pixbuf)
return NULL;
texture = gdk_texture_new_for_pixbuf (pixbuf);
if (loader_data.scale_factor != 1)
paintable = gtk_scaler_new (GDK_PAINTABLE (texture), loader_data.scale_factor);
if (gdk_texture_can_load (bytes))
{
/* We know these formats can't be scaled */
inner = GDK_PAINTABLE (gtk_loader_new (bytes));
if (inner == NULL)
return NULL;
}
else
paintable = g_object_ref ((GdkPaintable *)texture);
{
GdkPixbufLoader *loader;
gboolean success;
g_object_unref (pixbuf);
g_object_unref (texture);
loader = gdk_pixbuf_loader_new ();
g_signal_connect (loader, "size-prepared",
G_CALLBACK (on_loader_size_prepared), &loader_data);
success = gdk_pixbuf_loader_write_bytes (loader, bytes, NULL);
/* close even when writing failed */
success &= gdk_pixbuf_loader_close (loader, NULL);
if (!success)
return NULL;
inner = GDK_PAINTABLE (gdk_texture_new_for_pixbuf (gdk_pixbuf_loader_get_pixbuf (loader)));
g_object_unref (loader);
}
if (loader_data.scale_factor != 1)
paintable = gtk_scaler_new (inner, loader_data.scale_factor);
else
paintable = g_object_ref ((GdkPaintable *)inner);
g_object_unref (inner);
return paintable;
}
-6
View File
@@ -23,32 +23,26 @@
G_BEGIN_DECLS
GdkPixbuf *_gdk_pixbuf_new_from_stream (GInputStream *stream,
const char *format,
GCancellable *cancellable,
GError **error);
GdkPixbuf *_gdk_pixbuf_new_from_stream_at_scale (GInputStream *stream,
const char *format,
int width,
int height,
gboolean aspect,
GCancellable *cancellable,
GError **error);
GdkPixbuf *_gdk_pixbuf_new_from_stream_scaled (GInputStream *stream,
const char *format,
double scale,
GCancellable *cancellable,
GError **error);
GdkPixbuf *_gdk_pixbuf_new_from_resource (const char *resource_path,
const char *format,
GError **error);
GdkPixbuf *_gdk_pixbuf_new_from_resource_at_scale (const char *resource_path,
const char *format,
int width,
int height,
gboolean preserve_aspect,
GError **error);
GdkPixbuf *_gdk_pixbuf_new_from_resource_scaled (const char *resource_path,
const char *format,
double scale,
GError **error);
+4 -4
View File
@@ -55,7 +55,7 @@ for f in get_files('theme/Default/assets', '.png'):
xml += '\n'
for f in get_files('theme/Default/assets', '.svg'):
xml += ' <file>theme/Default/assets/{0}</file>\n'.format(f)
xml += ' <file preprocess=\'xml-stripblanks\'>theme/Default/assets/{0}</file>\n'.format(f)
for f in get_files('theme/Default/assets-hc', '.png'):
xml += ' <file>theme/Default/assets-hc/{0}</file>\n'.format(f)
@@ -63,10 +63,10 @@ for f in get_files('theme/Default/assets-hc', '.png'):
xml += '\n'
for f in get_files('theme/Default/assets-hc', '.svg'):
xml += ' <file>theme/Default/assets-hc/{0}</file>\n'.format(f)
xml += ' <file preprocess=\'xml-stripblanks\'>theme/Default/assets-hc/{0}</file>\n'.format(f)
for f in get_files('ui', '.ui'):
xml += ' <file preprocess=\'xml-stripblanks\'>ui/{0}</file>\n'.format(f)
xml += ' <file>ui/{0}</file>\n'.format(f)
xml += '\n'
@@ -77,7 +77,7 @@ for s in ['16x16', '32x32', '64x64', 'scalable']:
for f in get_files(icons_dir, '.png'):
xml += ' <file>icons/{0}/{1}/{2}</file>\n'.format(s,c,f)
for f in get_files(icons_dir, '.svg'):
xml += ' <file>icons/{0}/{1}/{2}</file>\n'.format(s,c,f)
xml += ' <file preprocess=\'xml-stripblanks\'>icons/{0}/{1}/{2}</file>\n'.format(s,c,f)
for f in get_files('inspector', '.ui'):
xml += ' <file preprocess=\'xml-stripblanks\'>inspector/{0}</file>\n'.format(f)
-5
View File
@@ -100,7 +100,6 @@ gsk_pango_renderer_draw_glyph_item (PangoRenderer *renderer,
get_color (crenderer, PANGO_RENDER_PART_FOREGROUND, &color);
gtk_snapshot_append_text (crenderer->snapshot,
crenderer->options,
glyph_item->item->analysis.font,
glyph_item->glyphs,
&color,
@@ -468,18 +467,14 @@ gtk_snapshot_append_layout (GtkSnapshot *snapshot,
const GdkRGBA *color)
{
GskPangoRenderer *crenderer;
PangoContext *context;
g_return_if_fail (snapshot != NULL);
g_return_if_fail (PANGO_IS_LAYOUT (layout));
crenderer = gsk_pango_renderer_acquire ();
context = pango_layout_get_context (layout);
crenderer->snapshot = snapshot;
crenderer->fg_color = color;
crenderer->options = pango_cairo_context_get_font_options (context);
pango_renderer_draw_layout (PANGO_RENDERER (crenderer), layout, 0, 0);
-2
View File
@@ -63,8 +63,6 @@ struct _GskPangoRenderer
/* Error underline color for this widget */
GdkRGBA *error_color;
const cairo_font_options_t *options;
GskPangoRendererState state;
guint is_cached_renderer : 1;
+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
+1 -1
View File
@@ -67,7 +67,7 @@ char * gtk_accelerator_get_label_with_keycode (GdkDisplay *display,
guint keycode,
GdkModifierType accelerator_mods);
GDK_AVAILABLE_IN_ALL
GdkModifierType gtk_accelerator_get_default_mod_mask (void);
GdkModifierType gtk_accelerator_get_default_mod_mask (void) G_GNUC_CONST;
G_END_DECLS
+1 -1
View File
@@ -1032,7 +1032,7 @@ gtk_at_context_get_description_accumulate (GtkATContext *self,
GList *list = gtk_reference_list_accessible_value_get (value);
for (GList *l = list; l != NULL; l = l->data)
for (GList *l = list; l != NULL; l = l->next)
{
GtkAccessible *rel = GTK_ACCESSIBLE (l->data);
GtkATContext *rel_context = gtk_accessible_get_at_context (rel);
+59 -22
View File
@@ -210,7 +210,6 @@
#include "gtkbuilderprivate.h"
#include "gdkpixbufutilsprivate.h"
#include "gtkbuildableprivate.h"
#include "gtkbuilderlistitemfactory.h"
#include "gtkbuilderscopeprivate.h"
@@ -226,7 +225,6 @@
#include "gtktypebuiltins.h"
#include "gtkicontheme.h"
#include "gtkiconthemeprivate.h"
#include "gdkpixbufutilsprivate.h"
#include "gtkdebug.h"
@@ -2296,9 +2294,63 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
break;
case G_TYPE_OBJECT:
case G_TYPE_INTERFACE:
if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF) ||
G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE) ||
if (G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE) ||
G_VALUE_HOLDS (value, GDK_TYPE_TEXTURE))
{
GObject *object = g_hash_table_lookup (priv->objects, string);
char *filename;
GError *tmp_error = NULL;
GdkTexture *texture = NULL;
if (object)
{
if (g_type_is_a (G_OBJECT_TYPE (object), G_VALUE_TYPE (value)))
{
g_value_set_object (value, object);
return TRUE;
}
else
{
g_set_error (error,
GTK_BUILDER_ERROR,
GTK_BUILDER_ERROR_INVALID_VALUE,
"Could not load image '%s': "
" '%s' is already used as object id for a %s",
string, string, G_OBJECT_TYPE_NAME (object));
return FALSE;
}
}
filename = _gtk_builder_get_resource_path (builder, string);
if (filename != NULL)
{
texture = gdk_texture_new_from_resource (filename);
}
else
{
GFile *file;
filename = _gtk_builder_get_absolute_filename (builder, string);
file = g_file_new_for_path (filename);
texture = gdk_texture_new_from_file (file, &tmp_error);
g_object_unref (file);
}
g_free (filename);
if (!texture)
{
g_warning ("Could not load image '%s': %s", string, tmp_error->message);
g_error_free (tmp_error);
texture = gdk_texture_new_from_resource (IMAGE_MISSING_RESOURCE_PATH);
}
g_value_take_object (value, texture);
ret = TRUE;
}
else if (G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF))
{
char *filename;
GError *tmp_error = NULL;
@@ -2344,28 +2396,13 @@ gtk_builder_value_from_string_type (GtkBuilder *builder,
if (pixbuf == NULL)
{
g_warning ("Could not load image '%s': %s",
string, tmp_error->message);
g_warning ("Could not load image '%s': %s", string, tmp_error->message);
g_error_free (tmp_error);
pixbuf = _gdk_pixbuf_new_from_resource (IMAGE_MISSING_RESOURCE_PATH, "png", NULL);
pixbuf = gdk_pixbuf_new_from_resource (IMAGE_MISSING_RESOURCE_PATH, NULL);
}
if (pixbuf)
{
if (G_VALUE_HOLDS (value, GDK_TYPE_TEXTURE) ||
G_VALUE_HOLDS (value, GDK_TYPE_PAINTABLE))
{
GdkTexture *texture = gdk_texture_new_for_pixbuf (pixbuf);
g_value_set_object (value, texture);
g_object_unref (texture);
}
else
{
g_value_set_object (value, pixbuf);
}
g_object_unref (G_OBJECT (pixbuf));
}
g_value_take_object (value, pixbuf);
g_free (filename);
+33 -28
View File
@@ -52,7 +52,9 @@ typedef struct {
} RecordDataString;
static RecordDataTree *
record_data_tree_new (RecordDataTree *parent, RecordTreeType type, const char *data)
record_data_tree_new (RecordDataTree *parent,
RecordTreeType type,
const char *data)
{
RecordDataTree *tree = g_slice_new0 (RecordDataTree);
@@ -83,7 +85,9 @@ record_data_string_free (RecordDataString *s)
}
static const char *
record_data_string_lookup (GHashTable *strings, const char *str, gssize len)
record_data_string_lookup (GHashTable *strings,
const char *str,
gssize len)
{
char *copy = NULL;
RecordDataString *s;
@@ -190,7 +194,7 @@ compare_string (gconstpointer _a,
static void
marshal_uint32 (GString *str,
guint32 v)
guint32 v)
{
/*
We encode in a variable length format similar to
@@ -237,7 +241,7 @@ marshal_uint32 (GString *str,
}
static void
marshal_string (GString *marshaled,
marshal_string (GString *marshaled,
GHashTable *strings,
const char *string)
{
@@ -250,8 +254,8 @@ marshal_string (GString *marshaled,
}
static void
marshal_tree (GString *marshaled,
GHashTable *strings,
marshal_tree (GString *marshaled,
GHashTable *strings,
RecordDataTree *tree)
{
GList *l;
@@ -303,9 +307,9 @@ marshal_tree (GString *marshaled,
* returns: A `GBytes` with the precompiled data
**/
GBytes *
_gtk_buildable_parser_precompile (const char *text,
gssize text_len,
GError **error)
_gtk_buildable_parser_precompile (const char *text,
gssize text_len,
GError **error)
{
GMarkupParseContext *ctx;
RecordData data = { 0 };
@@ -400,7 +404,8 @@ demarshal_uint32 (const char **tree)
}
static const char *
demarshal_string (const char **tree, const char *strings)
demarshal_string (const char **tree,
const char *strings)
{
guint32 offset = demarshal_uint32 (tree);
@@ -417,10 +422,10 @@ propagate_error (GtkBuildableParseContext *context,
}
static gboolean
replay_start_element (GtkBuildableParseContext *context,
const char **tree,
const char *strings,
GError **error)
replay_start_element (GtkBuildableParseContext *context,
const char **tree,
const char *strings,
GError **error)
{
const char *element_name;
guint32 i, n_attrs;
@@ -458,10 +463,10 @@ replay_start_element (GtkBuildableParseContext *context,
}
static gboolean
replay_end_element (GtkBuildableParseContext *context,
const char **tree,
const char *strings,
GError **error)
replay_end_element (GtkBuildableParseContext *context,
const char **tree,
const char *strings,
GError **error)
{
GError *tmp_error = NULL;
@@ -479,10 +484,10 @@ replay_end_element (GtkBuildableParseContext *context,
}
static gboolean
replay_text (GtkBuildableParseContext *context,
const char **tree,
const char *strings,
GError **error)
replay_text (GtkBuildableParseContext *context,
const char **tree,
const char *strings,
GError **error)
{
const char *text;
GError *tmp_error = NULL;
@@ -505,8 +510,8 @@ replay_text (GtkBuildableParseContext *context,
}
gboolean
_gtk_buildable_parser_is_precompiled (const char *data,
gssize data_len)
_gtk_buildable_parser_is_precompiled (const char *data,
gssize data_len)
{
return
data_len > 4 &&
@@ -517,10 +522,10 @@ _gtk_buildable_parser_is_precompiled (const char *data,
}
gboolean
_gtk_buildable_parser_replay_precompiled (GtkBuildableParseContext *context,
const char *data,
gssize data_len,
GError **error)
_gtk_buildable_parser_replay_precompiled (GtkBuildableParseContext *context,
const char *data,
gssize data_len,
GError **error)
{
const char *data_end = data + data_len;
guint32 type, len;
+2 -2
View File
@@ -250,9 +250,9 @@ const char * _gtk_builder_parser_translate (const char *domain,
const char *context,
const char *text);
char * _gtk_builder_get_resource_path (GtkBuilder *builder,
const char *string);
const char *string) G_GNUC_MALLOC;
char * _gtk_builder_get_absolute_filename (GtkBuilder *builder,
const char *string);
const char *string) G_GNUC_MALLOC;
void _gtk_builder_menu_start (ParserData *parser_data,
const char *element_name,
+1 -1
View File
@@ -193,7 +193,7 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
*
* Note that this signal is only emitted when the user changes the color.
* If you need to react to programmatic color changes as well, use
* the notify::color signal.
* the notify::rgba signal.
*/
color_button_signals[COLOR_SET] = g_signal_new (I_("color-set"),
G_TYPE_FROM_CLASS (gobject_class),
+1 -3
View File
@@ -754,7 +754,6 @@ gtk_constraint_solver_optimize (GtkConstraintSolver *self,
double t_c;
double objective_coefficient = 0.0;
double min_ratio;
double r;
gtk_constraint_expression_iter_init (&eiter, z_row);
while (gtk_constraint_expression_iter_prev (&eiter, &t_v, &t_c))
@@ -771,7 +770,6 @@ gtk_constraint_solver_optimize (GtkConstraintSolver *self,
break;
min_ratio = DBL_MAX;
r = 0;
column_vars = gtk_constraint_solver_get_column_set (self, entry);
gtk_constraint_variable_set_iter_init (&viter, column_vars);
@@ -786,7 +784,7 @@ gtk_constraint_solver_optimize (GtkConstraintSolver *self,
{
double constant = gtk_constraint_expression_get_constant (expr);
r = -1.0 * constant / coeff;
double r = -1.0 * constant / coeff;
if (r < min_ratio)
{
min_ratio = r;
+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");
}
+12 -13
View File
@@ -26,10 +26,9 @@
#include "gtkcssimageinvalidprivate.h"
#include "gtkcssimagepaintableprivate.h"
#include "gtkstyleproviderprivate.h"
#include "gdkpixbufutilsprivate.h"
#include "gtk/css/gtkcssdataurlprivate.h"
G_DEFINE_TYPE (GtkCssImageUrl, _gtk_css_image_url, GTK_TYPE_CSS_IMAGE)
static GtkCssImage *
@@ -60,7 +59,7 @@ gtk_css_image_url_load_image (GtkCssImageUrl *url,
if (texture == NULL)
{
if (error)
if (error && local_error)
{
char *uri;
@@ -71,7 +70,7 @@ gtk_css_image_url_load_image (GtkCssImageUrl *url,
"Error loading image '%s': %s", uri, local_error->message);
g_free (uri);
}
url->loaded_image = gtk_css_image_invalid_new ();
}
else
@@ -181,28 +180,28 @@ gtk_css_image_url_parse (GtkCssImage *image,
if (scheme && g_ascii_strcasecmp (scheme, "data") == 0)
{
GBytes *bytes;
GdkPaintable *paintable;
GError *error = NULL;
bytes = gtk_css_data_url_parse (url, NULL, &error);
if (bytes)
{
paintable = gdk_paintable_new_from_bytes_scaled (bytes, 1);
GdkTexture *texture;
texture = gdk_texture_new_from_bytes (bytes, &error);
g_bytes_unref (bytes);
if (paintable == NULL)
if (texture)
{
GdkPaintable *paintable = GDK_PAINTABLE (texture);
self->loaded_image = gtk_css_image_paintable_new (paintable, paintable);
}
else
{
error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
"Failed to load image from '%s'", url);
gtk_css_parser_emit_error (parser,
gtk_css_parser_get_start_location (parser),
gtk_css_parser_get_end_location (parser),
error);
g_clear_error (&error);
}
else
{
self->loaded_image = gtk_css_image_paintable_new (paintable, paintable);
}
}
else
{
-62
View File
@@ -22,68 +22,6 @@
#include "gtkcssnumbervalueprivate.h"
#include "gtkstylecontextprivate.h"
GtkCssChange
_gtk_css_change_for_sibling (GtkCssChange match)
{
#define BASE_STATES ( GTK_CSS_CHANGE_CLASS \
| GTK_CSS_CHANGE_NAME \
| GTK_CSS_CHANGE_ID \
| GTK_CSS_CHANGE_FIRST_CHILD \
| GTK_CSS_CHANGE_LAST_CHILD \
| GTK_CSS_CHANGE_NTH_CHILD \
| GTK_CSS_CHANGE_NTH_LAST_CHILD \
| GTK_CSS_CHANGE_STATE \
| GTK_CSS_CHANGE_HOVER \
| GTK_CSS_CHANGE_DISABLED \
| GTK_CSS_CHANGE_SELECTED \
| GTK_CSS_CHANGE_BACKDROP)
#define KEEP_STATES ( ~(BASE_STATES|GTK_CSS_CHANGE_SOURCE|GTK_CSS_CHANGE_PARENT_STYLE) \
| GTK_CSS_CHANGE_NTH_CHILD \
| GTK_CSS_CHANGE_NTH_LAST_CHILD)
return (match & KEEP_STATES) | ((match & BASE_STATES) << GTK_CSS_CHANGE_SIBLING_SHIFT);
#undef BASE_STATES
#undef KEEP_STATES
}
GtkCssChange
_gtk_css_change_for_child (GtkCssChange match)
{
#define BASE_STATES ( GTK_CSS_CHANGE_CLASS \
| GTK_CSS_CHANGE_NAME \
| GTK_CSS_CHANGE_ID \
| GTK_CSS_CHANGE_FIRST_CHILD \
| GTK_CSS_CHANGE_LAST_CHILD \
| GTK_CSS_CHANGE_NTH_CHILD \
| GTK_CSS_CHANGE_NTH_LAST_CHILD \
| GTK_CSS_CHANGE_STATE \
| GTK_CSS_CHANGE_HOVER \
| GTK_CSS_CHANGE_DISABLED \
| GTK_CSS_CHANGE_BACKDROP \
| GTK_CSS_CHANGE_SELECTED \
| GTK_CSS_CHANGE_SIBLING_CLASS \
| GTK_CSS_CHANGE_SIBLING_NAME \
| GTK_CSS_CHANGE_SIBLING_ID \
| GTK_CSS_CHANGE_SIBLING_FIRST_CHILD \
| GTK_CSS_CHANGE_SIBLING_LAST_CHILD \
| GTK_CSS_CHANGE_SIBLING_NTH_CHILD \
| GTK_CSS_CHANGE_SIBLING_NTH_LAST_CHILD \
| GTK_CSS_CHANGE_SIBLING_STATE \
| GTK_CSS_CHANGE_SIBLING_HOVER \
| GTK_CSS_CHANGE_SIBLING_DISABLED \
| GTK_CSS_CHANGE_SIBLING_BACKDROP \
| GTK_CSS_CHANGE_SIBLING_SELECTED)
#define KEEP_STATES (~(BASE_STATES|GTK_CSS_CHANGE_SOURCE|GTK_CSS_CHANGE_PARENT_STYLE))
return (match & KEEP_STATES) | ((match & BASE_STATES) << GTK_CSS_CHANGE_PARENT_SHIFT);
#undef BASE_STATES
#undef KEEP_STATES
}
void
gtk_css_change_print (GtkCssChange change,
GString *string)
+64 -5
View File
@@ -452,16 +452,75 @@ typedef enum /*< skip >*/ {
GTK_CSS_FONT_VARIANT_EAST_ASIAN_RUBY = 1 << 9
} GtkCssFontVariantEastAsian;
GtkCssChange _gtk_css_change_for_sibling (GtkCssChange match);
GtkCssChange _gtk_css_change_for_child (GtkCssChange match);
static inline GtkCssChange
_gtk_css_change_for_sibling (GtkCssChange match)
{
#define BASE_STATES ( GTK_CSS_CHANGE_CLASS \
| GTK_CSS_CHANGE_NAME \
| GTK_CSS_CHANGE_ID \
| GTK_CSS_CHANGE_FIRST_CHILD \
| GTK_CSS_CHANGE_LAST_CHILD \
| GTK_CSS_CHANGE_NTH_CHILD \
| GTK_CSS_CHANGE_NTH_LAST_CHILD \
| GTK_CSS_CHANGE_STATE \
| GTK_CSS_CHANGE_HOVER \
| GTK_CSS_CHANGE_DISABLED \
| GTK_CSS_CHANGE_SELECTED \
| GTK_CSS_CHANGE_BACKDROP)
GtkCssDimension gtk_css_unit_get_dimension (GtkCssUnit unit);
#define KEEP_STATES ( ~(BASE_STATES|GTK_CSS_CHANGE_SOURCE|GTK_CSS_CHANGE_PARENT_STYLE) \
| GTK_CSS_CHANGE_NTH_CHILD \
| GTK_CSS_CHANGE_NTH_LAST_CHILD)
char * gtk_css_change_to_string (GtkCssChange change);
return (match & KEEP_STATES) | ((match & BASE_STATES) << GTK_CSS_CHANGE_SIBLING_SHIFT);
#undef BASE_STATES
#undef KEEP_STATES
}
static inline GtkCssChange
_gtk_css_change_for_child (GtkCssChange match)
{
#define BASE_STATES ( GTK_CSS_CHANGE_CLASS \
| GTK_CSS_CHANGE_NAME \
| GTK_CSS_CHANGE_ID \
| GTK_CSS_CHANGE_FIRST_CHILD \
| GTK_CSS_CHANGE_LAST_CHILD \
| GTK_CSS_CHANGE_NTH_CHILD \
| GTK_CSS_CHANGE_NTH_LAST_CHILD \
| GTK_CSS_CHANGE_STATE \
| GTK_CSS_CHANGE_HOVER \
| GTK_CSS_CHANGE_DISABLED \
| GTK_CSS_CHANGE_BACKDROP \
| GTK_CSS_CHANGE_SELECTED \
| GTK_CSS_CHANGE_SIBLING_CLASS \
| GTK_CSS_CHANGE_SIBLING_NAME \
| GTK_CSS_CHANGE_SIBLING_ID \
| GTK_CSS_CHANGE_SIBLING_FIRST_CHILD \
| GTK_CSS_CHANGE_SIBLING_LAST_CHILD \
| GTK_CSS_CHANGE_SIBLING_NTH_CHILD \
| GTK_CSS_CHANGE_SIBLING_NTH_LAST_CHILD \
| GTK_CSS_CHANGE_SIBLING_STATE \
| GTK_CSS_CHANGE_SIBLING_HOVER \
| GTK_CSS_CHANGE_SIBLING_DISABLED \
| GTK_CSS_CHANGE_SIBLING_BACKDROP \
| GTK_CSS_CHANGE_SIBLING_SELECTED)
#define KEEP_STATES (~(BASE_STATES|GTK_CSS_CHANGE_SOURCE|GTK_CSS_CHANGE_PARENT_STYLE))
return (match & KEEP_STATES) | ((match & BASE_STATES) << GTK_CSS_CHANGE_PARENT_SHIFT);
#undef BASE_STATES
#undef KEEP_STATES
}
GtkCssDimension gtk_css_unit_get_dimension (GtkCssUnit unit) G_GNUC_CONST;
char * gtk_css_change_to_string (GtkCssChange change) G_GNUC_MALLOC;
void gtk_css_change_print (GtkCssChange change,
GString *string);
const char * gtk_css_pseudoclass_name (GtkStateFlags flags);
const char * gtk_css_pseudoclass_name (GtkStateFlags flags) G_GNUC_CONST;
/* These hash functions are selected so they achieve 2 things:
* 1. collision free among each other
+1 -1
View File
@@ -87,7 +87,7 @@ void gtk_editable_set_text (GtkEditable *editable,
GDK_AVAILABLE_IN_ALL
char * gtk_editable_get_chars (GtkEditable *editable,
int start_pos,
int end_pos);
int end_pos) G_GNUC_MALLOC;
GDK_AVAILABLE_IN_ALL
void gtk_editable_insert_text (GtkEditable *editable,
const char *text,
+11 -8
View File
@@ -8028,15 +8028,15 @@ gtk_file_chooser_widget_set_choice (GtkFileChooser *chooser,
if (GTK_IS_BOX (widget))
{
guint i;
const char **choices;
const char **options;
GtkWidget *dropdown;
dropdown = gtk_widget_get_last_child (widget);
choices = (const char **) g_object_get_data (G_OBJECT (dropdown), "choices");
for (i = 0; choices[i]; i++)
options = (const char **) g_object_get_data (G_OBJECT (dropdown), "options");
for (i = 0; options[i]; i++)
{
if (strcmp (option, choices[i]) == 0)
if (strcmp (option, options[i]) == 0)
{
gtk_drop_down_set_selected (GTK_DROP_DOWN (dropdown), i);
break;
@@ -8060,10 +8060,13 @@ gtk_file_chooser_widget_get_choice (GtkFileChooser *chooser,
widget = (GtkWidget *)g_hash_table_lookup (impl->choices, id);
if (GTK_IS_DROP_DOWN (widget))
{
gpointer selected = gtk_drop_down_get_selected_item (GTK_DROP_DOWN (widget));
if (GTK_IS_STRING_OBJECT (selected))
return gtk_string_object_get_string (GTK_STRING_OBJECT (selected));
return NULL;
const char **options;
guint selected;
options = (const char **) g_object_get_data (G_OBJECT (widget), "options");
selected = gtk_drop_down_get_selected (GTK_DROP_DOWN (widget));
return options[selected];
}
else if (GTK_IS_CHECK_BUTTON (widget))
{
+81 -102
View File
@@ -3742,31 +3742,6 @@ gtk_icon_paintable_is_symbolic (GtkIconPaintable *icon)
return icon->is_symbolic;
}
static GLoadableIcon *
icon_get_loadable (GtkIconPaintable *icon)
{
GFile *file;
GLoadableIcon *loadable;
if (icon->loadable)
return g_object_ref (icon->loadable);
if (icon->is_resource)
{
char *uri = g_strconcat ("resource://", icon->filename, NULL);
file = g_file_new_for_uri (uri);
g_free (uri);
}
else
file = g_file_new_for_path (icon->filename);
loadable = G_LOADABLE_ICON (g_file_icon_new (file));
g_object_unref (file);
return loadable;
}
/* This function contains the complicated logic for deciding
* on the size at which to load the icon and loading it at
* that size.
@@ -3775,7 +3750,6 @@ static void
icon_ensure_texture__locked (GtkIconPaintable *icon,
gboolean in_thread)
{
GdkPixbuf *source_pixbuf;
gint64 before;
int pixel_size;
GError *load_error = NULL;
@@ -3795,11 +3769,10 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
/* At this point, we need to actually get the icon; either from the
* builtin image or by loading the file
*/
source_pixbuf = NULL;
#ifdef G_OS_WIN32
if (icon->win32_icon)
{
source_pixbuf = g_object_ref (icon->win32_icon);
icon->texture = gdk_texture_new_for_pixbuf (icon->win32_icon);
}
else
#endif
@@ -3807,6 +3780,8 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
{
if (icon->is_svg)
{
GdkPixbuf *source_pixbuf;
if (gtk_icon_paintable_is_symbolic (icon))
source_pixbuf = gtk_make_symbolic_pixbuf_from_resource (icon->filename,
pixel_size, pixel_size,
@@ -3814,33 +3789,67 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
&load_error);
else
source_pixbuf = _gdk_pixbuf_new_from_resource_at_scale (icon->filename,
"svg",
pixel_size, pixel_size,
TRUE, &load_error);
if (source_pixbuf)
{
icon->texture = gdk_texture_new_for_pixbuf (source_pixbuf);
g_object_unref (source_pixbuf);
}
}
else
source_pixbuf = _gdk_pixbuf_new_from_resource (icon->filename,
g_str_has_suffix (icon->filename, ".xpm") ? "xpm" : "png",
&load_error);
if (source_pixbuf == NULL)
icon->texture = gdk_texture_new_from_resource (icon->filename);
}
else if (icon->filename)
{
if (icon->is_svg)
{
g_warning ("Failed to load icon %s: %s", icon->filename, load_error->message);
g_clear_error (&load_error);
GdkPixbuf *source_pixbuf;
if (gtk_icon_paintable_is_symbolic (icon))
source_pixbuf = gtk_make_symbolic_pixbuf_from_path (icon->filename,
pixel_size, pixel_size,
icon->desired_scale,
&load_error);
else
{
GFile *file = g_file_new_for_path (icon->filename);
GInputStream *stream = G_INPUT_STREAM (g_file_read (file, NULL, &load_error));
g_object_unref (file);
if (stream)
{
source_pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream,
pixel_size, pixel_size,
TRUE, NULL,
&load_error);
g_object_unref (stream);
}
else
source_pixbuf = NULL;
}
if (source_pixbuf)
{
icon->texture = gdk_texture_new_for_pixbuf (source_pixbuf);
g_object_unref (source_pixbuf);
}
}
else
{
icon->texture = gdk_texture_new_from_filename (icon->filename, &load_error);
}
}
else
{
GLoadableIcon *loadable;
GInputStream *stream;
GdkPixbuf *source_pixbuf;
loadable = icon_get_loadable (icon);
stream = g_loadable_icon_load (loadable,
g_assert (icon->loadable);
stream = g_loadable_icon_load (icon->loadable,
pixel_size,
NULL, NULL,
&load_error);
g_object_unref (loadable);
if (stream)
{
/* SVG icons are a special case - we just immediately scale them
@@ -3848,46 +3857,32 @@ icon_ensure_texture__locked (GtkIconPaintable *icon,
*/
if (icon->is_svg)
{
if (gtk_icon_paintable_is_symbolic (icon))
source_pixbuf = gtk_make_symbolic_pixbuf_from_path (icon->filename,
source_pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream,
pixel_size, pixel_size,
icon->desired_scale,
TRUE, NULL,
&load_error);
else
source_pixbuf = _gdk_pixbuf_new_from_stream_at_scale (stream,
"svg",
pixel_size, pixel_size,
TRUE, NULL,
&load_error);
}
else
source_pixbuf = _gdk_pixbuf_new_from_stream (stream,
g_str_has_suffix (icon->filename, ".xpm") ? "xpm" : "png",
NULL, &load_error);
g_object_unref (stream);
}
if (source_pixbuf == NULL)
{
g_warning ("Failed to load icon %s: %s", icon->filename, load_error->message);
g_clear_error (&load_error);
if (source_pixbuf)
{
icon->texture = gdk_texture_new_for_pixbuf (source_pixbuf);
g_object_unref (source_pixbuf);
}
}
}
if (!source_pixbuf)
if (!icon->texture)
{
source_pixbuf = _gdk_pixbuf_new_from_resource (IMAGE_MISSING_RESOURCE_PATH, "png", NULL);
g_warning ("Failed to load icon %s: %s", icon->filename, load_error->message);
g_clear_error (&load_error);
icon->texture = gdk_texture_new_from_resource (IMAGE_MISSING_RESOURCE_PATH);
icon->icon_name = g_strdup ("image-missing");
icon->is_symbolic = FALSE;
g_assert (source_pixbuf != NULL);
}
/* Actual scaling is done during rendering, so just keep the source pixbuf as a texture */
icon->texture = gdk_texture_new_for_pixbuf (source_pixbuf);
g_object_unref (source_pixbuf);
g_assert (icon->texture != NULL);
if (GDK_PROFILER_IS_RUNNING)
{
gint64 end = GDK_PROFILER_CURRENT_TIME;
@@ -4089,28 +4084,6 @@ gtk_icon_paintable_new_for_file (GFile *file,
return icon;
}
static GtkIconPaintable *
gtk_icon_paintable_new_for_pixbuf (GtkIconTheme *icon_theme,
GdkPixbuf *pixbuf,
int size,
int scale)
{
GtkIconPaintable *icon;
int width, height;
if (size <= 0)
{
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
size = MAX (width, height);
}
icon = icon_paintable_new (NULL, size, scale);
icon->texture = gdk_texture_new_for_pixbuf (pixbuf);
return icon;
}
/**
* gtk_icon_theme_lookup_by_gicon:
* @self: a `GtkIconTheme`
@@ -4136,50 +4109,56 @@ gtk_icon_theme_lookup_by_gicon (GtkIconTheme *self,
GtkTextDirection direction,
GtkIconLookupFlags flags)
{
GtkIconPaintable *icon = NULL;
GtkIconPaintable *paintable = NULL;
g_return_val_if_fail (GTK_IS_ICON_THEME (self), NULL);
g_return_val_if_fail (G_IS_ICON (gicon), NULL);
g_return_val_if_fail (size > 0, NULL);
g_return_val_if_fail (scale > 0, NULL);
/* We can't render emblemed icons atm, but at least render the base */
while (G_IS_EMBLEMED_ICON (gicon))
gicon = g_emblemed_icon_get_icon (G_EMBLEMED_ICON (gicon));
g_assert (gicon); /* shut up gcc -Wnull-dereference */
if (GDK_IS_PIXBUF (gicon))
if (GDK_IS_TEXTURE (gicon))
{
GdkPixbuf *pixbuf = GDK_PIXBUF (gicon);
icon = gtk_icon_paintable_new_for_pixbuf (self, pixbuf, size, scale);
paintable = icon_paintable_new (NULL, size, scale);
paintable->texture = g_object_ref (GDK_TEXTURE (gicon));
}
else if (GDK_IS_PIXBUF (gicon))
{
paintable = icon_paintable_new (NULL, size, scale);
paintable->texture = gdk_texture_new_for_pixbuf (GDK_PIXBUF (gicon));
}
else if (G_IS_FILE_ICON (gicon))
{
GFile *file = g_file_icon_get_file (G_FILE_ICON (gicon));
icon = gtk_icon_paintable_new_for_file (file, size, scale);
paintable = gtk_icon_paintable_new_for_file (file, size, scale);
}
else if (G_IS_LOADABLE_ICON (gicon))
{
icon = icon_paintable_new (NULL, size, scale);
icon->loadable = G_LOADABLE_ICON (g_object_ref (gicon));
icon->is_svg = FALSE;
paintable = icon_paintable_new (NULL, size, scale);
paintable->loadable = G_LOADABLE_ICON (g_object_ref (gicon));
paintable->is_svg = FALSE;
}
else if (G_IS_THEMED_ICON (gicon))
{
const char **names;
names = (const char **) g_themed_icon_get_names (G_THEMED_ICON (gicon));
icon = gtk_icon_theme_lookup_icon (self, names[0], &names[1], size, scale, direction, flags);
paintable = gtk_icon_theme_lookup_icon (self, names[0], &names[1], size, scale, direction, flags);
}
else
{
g_debug ("Unhandled GIcon type %s", G_OBJECT_TYPE_NAME (gicon));
icon = icon_paintable_new ("image-missing", size, scale);
icon->filename = g_strdup (IMAGE_MISSING_RESOURCE_PATH);
icon->is_resource = TRUE;
paintable = icon_paintable_new ("image-missing", size, scale);
paintable->filename = g_strdup (IMAGE_MISSING_RESOURCE_PATH);
paintable->is_resource = TRUE;
}
return icon;
return paintable;
}
/**
+14 -13
View File
@@ -270,7 +270,6 @@ gtk_im_context_simple_init_compose_table (void)
const char *locale;
char **langs = NULL;
char **lang = NULL;
gboolean added;
const char * const sys_langs[] = { "el_gr", "fi_fi", "pt_br", NULL };
const char * const *sys_lang = NULL;
char *x11_compose_file_dir = get_x11_compose_file_dir ();
@@ -278,10 +277,11 @@ gtk_im_context_simple_init_compose_table (void)
path = g_build_filename (g_get_user_config_dir (), "gtk-4.0", "Compose", NULL);
if (g_file_test (path, G_FILE_TEST_EXISTS))
{
added = add_compose_table_from_file (path);
g_free (path);
if (added)
return;
if (add_compose_table_from_file (path))
{
g_free (path);
return;
}
}
g_clear_pointer (&path, g_free);
@@ -292,10 +292,11 @@ gtk_im_context_simple_init_compose_table (void)
path = g_build_filename (home, ".XCompose", NULL);
if (g_file_test (path, G_FILE_TEST_EXISTS))
{
added = add_compose_table_from_file (path);
g_free (path);
if (added)
return;
if (add_compose_table_from_file (path))
{
g_free (path);
return;
}
}
g_clear_pointer (&path, g_free);
@@ -336,13 +337,13 @@ gtk_im_context_simple_init_compose_table (void)
g_free (x11_compose_file_dir);
g_strfreev (langs);
if (path != NULL)
if (path != NULL &&
add_compose_table_from_file (path))
{
added = add_compose_table_from_file (path);
g_free (path);
return;
}
if (added)
return;
g_clear_pointer (&path, g_free);
add_builtin_compose_table ();
}
-1
View File
@@ -3977,7 +3977,6 @@ gtk_label_ensure_layout (GtkLabel *self)
if (self->layout)
return;
align = PANGO_ALIGN_LEFT; /* Quiet gcc */
rtl = _gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL;
self->layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), self->text);
+4 -1
View File
@@ -443,6 +443,7 @@ gtk_list_item_manager_release_items (GtkListItemManager *self,
i = position - i;
while (i < position + query_n_items)
{
g_assert (item != NULL);
if (item->widget)
{
g_queue_push_tail (released, item->widget);
@@ -459,7 +460,7 @@ gtk_list_item_manager_release_items (GtkListItemManager *self,
g_assert_not_reached ();
item = gtk_rb_tree_node_get_next (next);
}
else
else
{
item = next;
}
@@ -511,6 +512,7 @@ gtk_list_item_manager_ensure_items (GtkListItemManager *self,
if (offset > 0)
{
g_assert (item != NULL);
new_item = gtk_rb_tree_insert_before (self->items, item);
new_item->n_items = offset;
item->n_items -= offset;
@@ -519,6 +521,7 @@ gtk_list_item_manager_ensure_items (GtkListItemManager *self,
for (i = 0; i < query_n_items; i++)
{
g_assert (item != NULL);
if (item->n_items > 1)
{
new_item = gtk_rb_tree_insert_before (self->items, item);
+186
View File
@@ -0,0 +1,186 @@
/*
* Copyright © 2018 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 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/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "gtkloaderprivate.h"
#include "gtksnapshot.h"
struct _GtkLoader
{
GObject parent_instance;
GdkTexture *texture;
};
struct _GtkLoaderClass
{
GObjectClass parent_class;
};
static void
gtk_loader_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
{
GtkLoader *self = GTK_LOADER (paintable);
if (self->texture)
gdk_paintable_snapshot (GDK_PAINTABLE (self->texture), snapshot, width, height);
}
static GdkPaintable *
gtk_loader_paintable_get_current_image (GdkPaintable *paintable)
{
GtkLoader *self = GTK_LOADER (paintable);
if (self->texture)
return gdk_paintable_get_current_image (GDK_PAINTABLE (self->texture));
// FIXME: return a loading image
return NULL;
}
static int
gtk_loader_paintable_get_intrinsic_width (GdkPaintable *paintable)
{
GtkLoader *self = GTK_LOADER (paintable);
if (self->texture)
return gdk_paintable_get_intrinsic_width (GDK_PAINTABLE (self->texture));
return 16;
}
static int
gtk_loader_paintable_get_intrinsic_height (GdkPaintable *paintable)
{
GtkLoader *self = GTK_LOADER (paintable);
if (self->texture)
return gdk_paintable_get_intrinsic_height (GDK_PAINTABLE (self->texture));
return 16;
}
static double
gtk_loader_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{
GtkLoader *self = GTK_LOADER (paintable);
if (self->texture)
return gdk_paintable_get_intrinsic_aspect_ratio (GDK_PAINTABLE (self->texture));
return 0;
};
static void
gtk_loader_paintable_init (GdkPaintableInterface *iface)
{
iface->snapshot = gtk_loader_paintable_snapshot;
iface->get_current_image = gtk_loader_paintable_get_current_image;
iface->get_intrinsic_width = gtk_loader_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_loader_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = gtk_loader_paintable_get_intrinsic_aspect_ratio;
}
G_DEFINE_TYPE_EXTENDED (GtkLoader, gtk_loader, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
gtk_loader_paintable_init))
static void
gtk_loader_dispose (GObject *object)
{
GtkLoader *self = GTK_LOADER (object);
g_clear_object (&self->texture);
G_OBJECT_CLASS (gtk_loader_parent_class)->dispose (object);
}
static void
gtk_loader_class_init (GtkLoaderClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = gtk_loader_dispose;
}
static void
gtk_loader_init (GtkLoader *self)
{
}
static void
load_texture_in_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
GBytes *bytes = task_data;
GdkTexture *texture;
GError *error = NULL;
texture = gdk_texture_new_from_bytes (bytes, &error);
if (texture)
g_task_return_pointer (task, texture, g_object_unref);
else
g_task_return_error (task, error);
}
static void
texture_finished (GObject *source,
GAsyncResult *result,
gpointer data)
{
GtkLoader *self = GTK_LOADER (source);
GdkTexture *texture;
GError *error = NULL;
texture = g_task_propagate_pointer (G_TASK (result), &error);
if (texture)
{
self->texture = g_object_ref (texture);
gdk_paintable_invalidate_size (GDK_PAINTABLE (self));
gdk_paintable_invalidate_contents (GDK_PAINTABLE (self));
}
}
GdkPaintable *
gtk_loader_new (GBytes *bytes)
{
GtkLoader *self;
GTask *task;
g_return_val_if_fail (bytes != NULL, NULL);
self = g_object_new (GTK_TYPE_LOADER, NULL);
task = g_task_new (self, NULL, texture_finished, NULL);
g_task_set_task_data (task, g_bytes_ref (bytes), (GDestroyNotify)g_bytes_unref);
g_task_run_in_thread (task, load_texture_in_thread);
g_object_unref (task);
return GDK_PAINTABLE (self);
}
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright © 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.1 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/>.
*
* Authors: Matthias Clasen <mclasen@redhat.com>
*/
#ifndef __GTK_LOADER_H__
#define __GTK_LOADER_H__
#include <gdk/gdk.h>
G_BEGIN_DECLS
#define GTK_TYPE_LOADER (gtk_loader_get_type ())
G_DECLARE_FINAL_TYPE (GtkLoader, gtk_loader, GTK, LOADER, GObject)
GdkPaintable * gtk_loader_new (GBytes *bytes);
G_END_DECLS
#endif /* __GTK_SCALER_H__ */
+1 -1
View File
@@ -84,7 +84,7 @@ gboolean gtk_init_check_abi_check (int num_checks,
GDK_AVAILABLE_IN_ALL
void gtk_disable_setlocale (void);
GDK_AVAILABLE_IN_ALL
PangoLanguage * gtk_get_default_language (void);
PangoLanguage * gtk_get_default_language (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkTextDirection gtk_get_locale_direction (void);
+17
View File
@@ -669,6 +669,11 @@ gtk_menu_button_init (GtkMenuButton *self)
gtk_widget_set_sensitive (self->button, FALSE);
gtk_widget_add_css_class (GTK_WIDGET (self), "popup");
gtk_accessible_update_relation (GTK_ACCESSIBLE (self->button),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, self, NULL,
GTK_ACCESSIBLE_RELATION_DESCRIBED_BY, self, NULL,
-1);
}
static GtkBuildableIface *parent_buildable_iface;
@@ -1017,6 +1022,14 @@ gtk_menu_button_set_icon_name (GtkMenuButton *menu_button,
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
/* Because we are setting only an icon, let the inner button be labelled by us
* so the accessible label can be overridden from, for example, an UI file
* using GtkMenuButton as a child of something.
*/
gtk_accessible_update_relation (GTK_ACCESSIBLE (menu_button->button),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, menu_button, NULL,
-1);
image_widget = g_object_new (GTK_TYPE_IMAGE,
"accessible-role", GTK_ACCESSIBLE_ROLE_PRESENTATION,
"icon-name", icon_name,
@@ -1149,6 +1162,10 @@ gtk_menu_button_set_label (GtkMenuButton *menu_button,
gtk_button_set_child (GTK_BUTTON (menu_button->button), box);
menu_button->label_widget = label_widget;
gtk_accessible_update_relation (GTK_ACCESSIBLE (menu_button->button),
GTK_ACCESSIBLE_RELATION_LABELLED_BY, menu_button->label_widget, NULL,
-1);
menu_button->image_widget = NULL;
menu_button->child = NULL;
+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);
}
+12
View File
@@ -87,6 +87,17 @@ gtk_render_node_paintable_paintable_get_intrinsic_height (GdkPaintable *paintabl
return ceilf (self->bounds.size.height);
}
static double
gtk_render_node_paintable_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable)
{
GtkRenderNodePaintable *self = GTK_RENDER_NODE_PAINTABLE (paintable);
if (self->bounds.size.height != 0)
return self->bounds.size.width / self->bounds.size.height;
return 0;
}
static void
gtk_render_node_paintable_paintable_init (GdkPaintableInterface *iface)
{
@@ -94,6 +105,7 @@ gtk_render_node_paintable_paintable_init (GdkPaintableInterface *iface)
iface->get_flags = gtk_render_node_paintable_paintable_get_flags;
iface->get_intrinsic_width = gtk_render_node_paintable_paintable_get_intrinsic_width;
iface->get_intrinsic_height = gtk_render_node_paintable_paintable_get_intrinsic_height;
iface->get_intrinsic_aspect_ratio = gtk_render_node_paintable_paintable_get_intrinsic_aspect_ratio;
}
G_DEFINE_TYPE_EXTENDED (GtkRenderNodePaintable, gtk_render_node_paintable, G_TYPE_OBJECT, 0,
+1
View File
@@ -366,6 +366,7 @@ gtk_search_bar_init (GtkSearchBar *bar)
gtk_widget_set_hexpand (bar->box_center, TRUE);
bar->close_button = gtk_button_new_from_icon_name ("window-close-symbolic");
gtk_widget_set_valign (bar->close_button, GTK_ALIGN_CENTER);
gtk_widget_add_css_class (bar->close_button, "close");
gtk_center_box_set_end_widget (GTK_CENTER_BOX (bar->box_center), bar->close_button);
gtk_widget_hide (bar->close_button);
+10 -12
View File
@@ -2121,24 +2121,22 @@ gtk_snapshot_render_layout (GtkSnapshot *snapshot,
}
void
gtk_snapshot_append_text (GtkSnapshot *snapshot,
const cairo_font_options_t *options,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
float x,
float y)
gtk_snapshot_append_text (GtkSnapshot *snapshot,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
float x,
float y)
{
GskRenderNode *node;
float dx, dy;
gtk_snapshot_ensure_translate (snapshot, &dx, &dy);
node = gsk_text_node_new_with_font_options (options,
font,
glyphs,
color,
&GRAPHENE_POINT_INIT (x + dx, y + dy));
node = gsk_text_node_new (font,
glyphs,
color,
&GRAPHENE_POINT_INIT (x + dx, y + dy));
if (node == NULL)
return;
+6 -7
View File
@@ -24,13 +24,12 @@
G_BEGIN_DECLS
void gtk_snapshot_append_text (GtkSnapshot *snapshot,
const cairo_font_options_t *options,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
float x,
float y);
void gtk_snapshot_append_text (GtkSnapshot *snapshot,
PangoFont *font,
PangoGlyphString *glyphs,
const GdkRGBA *color,
float x,
float y);
void gtk_snapshot_push_collect (GtkSnapshot *snapshot);
GskRenderNode * gtk_snapshot_pop_collect (GtkSnapshot *snapshot);
+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);
}
+2
View File
@@ -273,6 +273,8 @@ add_child (guint position,
button = g_object_new (GTK_TYPE_TOGGLE_BUTTON,
"accessible-role", GTK_ACCESSIBLE_ROLE_TAB,
"hexpand", TRUE,
"vexpand", TRUE,
NULL);
gtk_widget_set_focus_on_click (button, FALSE);
+50 -15
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)
@@ -7669,7 +7705,6 @@ gtk_text_view_set_attributes_from_style (GtkTextView *text_view,
decoration_line = _gtk_css_text_decoration_line_value_get (style->font_variant->text_decoration_line);
decoration_style = _gtk_css_text_decoration_style_value_get (style->font_variant->text_decoration_style);
color = gtk_css_color_value_get_rgba (style->core->color);
decoration_color = gtk_css_color_value_get_rgba (style->font_variant->text_decoration_color
? style->font_variant->text_decoration_color
: style->core->color);
@@ -7809,8 +7844,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 +7878,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 ();
+19 -17
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,9 +6427,10 @@ gtk_widget_get_effective_font_map (GtkWidget *widget)
return pango_cairo_font_map_get_default ();
}
static gboolean
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);
@@ -6455,9 +6456,10 @@ update_pango_context (GtkWidget *widget,
pango_context_set_round_glyph_positions (context, hint_font_metrics);
}
pango_context_set_base_dir (context,
_gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR ?
PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL);
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));
@@ -6483,14 +6485,14 @@ update_pango_context (GtkWidget *widget,
}
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)
return;
if (update_pango_context (widget, context))
if (gtk_widget_update_pango_context (widget, context, _gtk_widget_get_direction (widget)))
gtk_widget_queue_draw (widget);
}
@@ -6522,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);
}
}
@@ -6551,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);
}
@@ -6588,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);
}
@@ -6631,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;
@@ -7216,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 *
+2 -2
View File
@@ -5892,7 +5892,7 @@ gtk_window_set_auto_startup_notification (gboolean setting)
}
/**
* gtk_window_get_mnemonics_visible: (attributes org.gtk.MEthod.get_property=mnemonics-visible)
* gtk_window_get_mnemonics_visible: (attributes org.gtk.Method.get_property=mnemonics-visible)
* @window: a `GtkWindow`
*
* Gets whether mnemonics are supposed to be visible.
@@ -5911,7 +5911,7 @@ gtk_window_get_mnemonics_visible (GtkWindow *window)
}
/**
* gtk_window_set_mnemonics_visible:
* gtk_window_set_mnemonics_visible: (attributes org.gtk.Method.set_property=mnemonics-visible)
* @window: a `GtkWindow`
* @setting: the new value
*

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