Compare commits
243 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7b68ef7669 | |||
| 11b9b1759a | |||
| 6474c7af35 | |||
| 145a16ff81 | |||
| f079d75d1f | |||
| e1facc548a | |||
| 87e4a542eb | |||
| 56e6a51ac0 | |||
| da115ad075 | |||
| 4a89cfe2c9 | |||
| c9135546b6 | |||
| a94e438a29 | |||
| 164443a99a | |||
| d88c4d122d | |||
| d66bc501a4 | |||
| 1c2c356ed4 | |||
| 1fae91d123 | |||
| 24415a6ffb | |||
| ae08aa3622 | |||
| c24b7877a0 | |||
| 7b22e37371 | |||
| c2ab1f172d | |||
| 136a3f6e5a | |||
| 2bc82da34d | |||
| 41b810da7f | |||
| 155e0f3dfb | |||
| 02bb23486f | |||
| bc0d9488ee | |||
| 5742483422 | |||
| 7f2cb1138a | |||
| 1289e68931 | |||
| 9e6adaa913 | |||
| 9cfce67d0f | |||
| 295d406207 | |||
| ece5fd7db5 | |||
| c4e558da46 | |||
| be1a60d5d0 | |||
| a1adaac69b | |||
| 7e4b2b971f | |||
| c6cacd2b2d | |||
| 2c8e55605b | |||
| 06db477847 | |||
| e9cf8c6cc7 | |||
| aad6b2d279 | |||
| cf3830704b | |||
| d962360fa0 | |||
| 76d31ff04b | |||
| 87af45403a | |||
| 15ffd49efb | |||
| 37a54eb9fc | |||
| 63647cace0 | |||
| bef54a382d | |||
| 6a60214e8c | |||
| 27d662f1aa | |||
| 52a8492887 | |||
| ba5d010e39 | |||
| 8c34dd58c0 | |||
| 0cce92ab19 | |||
| f95c21b67c | |||
| 1d41dc716e | |||
| 3914ecbd0f | |||
| 0428d8ccd6 | |||
| 37a7c6780a | |||
| 1b85b5597b | |||
| fae32846c7 | |||
| b271a94f92 | |||
| e58f70d7bb | |||
| 4fcf54757f | |||
| b5da07f0e1 | |||
| a85f4ec6c2 | |||
| b226478e8b | |||
| 14280b5f5b | |||
| e720f9d35d | |||
| fecb31b706 | |||
| 729ad8e64a | |||
| dcd873a6d8 | |||
| 679c93e843 | |||
| 2d3de8608c | |||
| 100b0bf7d9 | |||
| f2ca9ebbd7 | |||
| 577bf104c0 | |||
| b1bb7c3258 | |||
| c77b5c46a3 | |||
| 5b82cf1145 | |||
| 95a0c93839 | |||
| d27bc74481 | |||
| e30b4c61cb | |||
| daf29e174f | |||
| 729ba8111a | |||
| d30a029689 | |||
| 945c2531ac | |||
| f925e12e1d | |||
| a03594df52 | |||
| d7c8f92733 | |||
| d6ce65f81c | |||
| 7949aaabb7 | |||
| a71877bf99 | |||
| f51f7f85eb | |||
| 66031fd00b | |||
| 698b3542a1 | |||
| 83ea623775 | |||
| 345faa7250 | |||
| 08df891070 | |||
| 56b31c3923 | |||
| 93323be22a | |||
| 9e14de2534 | |||
| 62954a0338 | |||
| 7cf5e5546b | |||
| 58f66ebd07 | |||
| 47330598fb | |||
| 90ed7b92b2 | |||
| 625b5ce91a | |||
| c84d5b1f7f | |||
| 46bb160923 | |||
| 390a0b2f2a | |||
| 0dfab46c15 | |||
| 3a8ec683d3 | |||
| de53b0c7a3 | |||
| 75dfb4d63b | |||
| 64acaf99fb | |||
| 551f76ea69 | |||
| a4f3fbbda1 | |||
| b6d3561f4a | |||
| 01944d57b7 | |||
| c9aec9b5a2 | |||
| 025759e614 | |||
| ed679703b8 | |||
| fe46da1bf4 | |||
| 7fd8899092 | |||
| 9f8d6ff29c | |||
| 1230bce133 | |||
| 7c2be93a56 | |||
| eb23e23b03 | |||
| 75b45aeabf | |||
| 23ffd6923d | |||
| d2eb0288d9 | |||
| a4b976f7a2 | |||
| 4930faa984 | |||
| 84fdda4f56 | |||
| ec6228b3a4 | |||
| 8b85e7f35a | |||
| d7909dccdc | |||
| 7773ae4538 | |||
| bec44acdeb | |||
| 5bfac597f6 | |||
| 423a4d4c3e | |||
| 38fce67a9b | |||
| 04ef7055cd | |||
| 44a031c3c1 | |||
| be885c888f | |||
| 6faef4416f | |||
| 5f452a5e6c | |||
| 060f2d5f65 | |||
| ebca260f2d | |||
| d4b1f85e14 | |||
| 4439ff0c12 | |||
| ffab67ac70 | |||
| 0120ff3518 | |||
| 2e63b53b1e | |||
| 878c9da736 | |||
| 955d50a080 | |||
| 2b4f798e34 | |||
| cda5d2dadd | |||
| b664b2d1fd | |||
| c70fdd6331 | |||
| ddec3dedd0 | |||
| b1a5c3ff55 | |||
| 8f9a5175f0 | |||
| 099c923679 | |||
| 2a12a3e6d9 | |||
| cdc1fa166d | |||
| f572ca52d2 | |||
| 193b383739 | |||
| 6785461c26 | |||
| b9ee9979e7 | |||
| 6bbec87700 | |||
| b35608a351 | |||
| 416763bf2d | |||
| 9179ebb28e | |||
| bcc17b3033 | |||
| 00439f9e5c | |||
| c9d748fc51 | |||
| 719eafa60c | |||
| 1759d27da9 | |||
| 53275481a5 | |||
| cbe6d0da76 | |||
| c349ed9562 | |||
| 74ce69a8a1 | |||
| 4f17f3ac24 | |||
| 9c8e464b04 | |||
| 51d0d13a9e | |||
| 0ee3b1c861 | |||
| 46f88c69a1 | |||
| 140976a670 | |||
| 9f2b847835 | |||
| 9e11ea699c | |||
| 1a4eebe022 | |||
| 2963468019 | |||
| bfbd95d7d6 | |||
| c1c1d4431d | |||
| 155a4fac5c | |||
| 76f481eb7b | |||
| 0782c8a051 | |||
| 3d27ff1177 | |||
| 3ada664a89 | |||
| 643a91bd08 | |||
| c86733b4fa | |||
| 55099b7d0e | |||
| db3858a204 | |||
| 07bff74544 | |||
| b4262883a8 | |||
| 563c85e222 | |||
| d75246a543 | |||
| b3856a3ea0 | |||
| bd4d24f8ed | |||
| 65ce3eb207 | |||
| 865ac44963 | |||
| 55a935db53 | |||
| 6fefae3dbb | |||
| f7c84ddc7f | |||
| f4a4dd2615 | |||
| b718d99d1f | |||
| c7215d1199 | |||
| 24d69ef125 | |||
| 7c3fbdecf2 | |||
| b77938f40f | |||
| f703744564 | |||
| a3ccff3773 | |||
| 9869082c1c | |||
| 754212d0f9 | |||
| a9b81577c6 | |||
| eaa2dada54 | |||
| ce2b2128bb | |||
| 41c25b8809 | |||
| b5ff35ff3e | |||
| 06423d807f | |||
| 0395395d52 | |||
| c3ca48b249 | |||
| 464e0aed04 | |||
| d46e4fcecd | |||
| 363fb96e81 | |||
| 2382bd3bb2 | |||
| 3b0a9e84ab |
+1
-1
@@ -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:
|
||||
|
||||
@@ -53,6 +53,7 @@ RUN dnf -y install \
|
||||
libpng-devel \
|
||||
librsvg2 \
|
||||
libselinux-devel \
|
||||
libtiff-devel \
|
||||
libubsan \
|
||||
libXcomposite-devel \
|
||||
libXcursor-devel \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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 ();
|
||||
|
||||
|
||||
@@ -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"><Control>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"><Control>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>
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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: */
|
||||
@@ -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
|
||||
@@ -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: */
|
||||
@@ -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
|
||||
@@ -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: */
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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: */
|
||||
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
@@ -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 ();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
Reference in New Issue
Block a user