summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/forkfd/forkfd.c186
-rw-r--r--src/3rdparty/forkfd/forkfd.h5
-rw-r--r--src/3rdparty/forkfd/forkfd_atomic.h39
-rw-r--r--src/3rdparty/forkfd/forkfd_c11.h64
-rw-r--r--src/3rdparty/forkfd/forkfd_freebsd.c101
-rw-r--r--src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties2
-rw-r--r--src/android/jar/jar.pro1
-rw-r--r--src/android/java/java.pro2
-rw-r--r--src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java77
-rw-r--r--src/android/templates/AndroidManifest.xml5
-rw-r--r--src/android/templates/build.gradle2
-rw-r--r--src/android/templates/res/values/libs.xml9
-rw-r--r--src/android/templates/templates.pro2
-rw-r--r--src/corelib/codecs/qicucodec.cpp2
-rw-r--r--src/corelib/corelib.pro1
-rw-r--r--src/corelib/io/forkfd_qt.cpp29
-rw-r--r--src/corelib/itemmodels/qabstractitemmodel.cpp15
-rw-r--r--src/corelib/kernel/qobject.cpp22
-rw-r--r--src/corelib/kernel/qobject_p.h6
-rw-r--r--src/corelib/plugin/qlibrary_unix.cpp21
-rw-r--r--src/corelib/serialization/qcborvalue.cpp16
-rw-r--r--src/corelib/serialization/qcborvalue.h3
-rw-r--r--src/corelib/serialization/qcborvalue_p.h56
-rw-r--r--src/corelib/text/qstring.h9
-rw-r--r--src/corelib/thread/qthread_unix.cpp23
-rw-r--r--src/corelib/tools/qsize.cpp18
-rw-r--r--src/corelib/tools/qsize.h11
-rw-r--r--src/gui/doc/qtgui.qdocconf3
-rw-r--r--src/gui/doc/src/includes/qt-colors.qdocinc86
-rw-r--r--src/gui/doc/src/includes/svg-colors.qdocinc594
-rw-r--r--src/gui/image/image.pri19
-rw-r--r--src/gui/image/qimage.cpp15
-rw-r--r--src/gui/image/qimage.h1
-rw-r--r--src/gui/image/qimage_conversions.cpp222
-rw-r--r--src/gui/image/qimage_p.h1
-rw-r--r--src/gui/image/qimage_ssse3.cpp7
-rw-r--r--src/gui/image/qpixmap_win.cpp3
-rw-r--r--src/gui/image/qpnghandler.cpp2
-rw-r--r--src/gui/kernel/qevent.cpp56
-rw-r--r--src/gui/opengl/qopengltextureuploader.cpp18
-rw-r--r--src/gui/painting/painting.pri42
-rw-r--r--src/gui/painting/qbezier.cpp16
-rw-r--r--src/gui/painting/qbezier_p.h37
-rw-r--r--src/gui/painting/qcolor.cpp81
-rw-r--r--src/gui/painting/qcolor.h187
-rw-r--r--src/gui/painting/qdrawhelper.cpp28
-rw-r--r--src/gui/painting/qpainterpath.cpp21
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess.cpp37
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess_p.h2
-rw-r--r--src/gui/text/qcssparser.cpp13
-rw-r--r--src/gui/text/qcssparser_p.h2
-rw-r--r--src/gui/text/qfont.cpp8
-rw-r--r--src/gui/text/qfont_p.h10
-rw-r--r--src/gui/text/qfontmetrics.cpp8
-rw-r--r--src/gui/text/qtextdocument.cpp80
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp26
-rw-r--r--src/gui/text/qtexthtmlparser.cpp34
-rw-r--r--src/gui/text/qtexthtmlparser_p.h8
-rw-r--r--src/network/access/access.pri6
-rw-r--r--src/network/access/http2/hpack.cpp5
-rw-r--r--src/network/access/http2/hpack_p.h1
-rw-r--r--src/network/access/http2/http2frames.cpp4
-rw-r--r--src/network/access/http2/http2protocol.cpp116
-rw-r--r--src/network/access/http2/http2protocol_p.h64
-rw-r--r--src/network/access/qhttp2configuration.cpp312
-rw-r--r--src/network/access/qhttp2configuration.h100
-rw-r--r--src/network/access/qhttp2protocolhandler.cpp45
-rw-r--r--src/network/access/qhttp2protocolhandler_p.h25
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp11
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h8
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp6
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp4
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h3
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp3
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp64
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h2
-rw-r--r--src/network/access/qnetworkrequest.cpp71
-rw-r--r--src/network/access/qnetworkrequest.h5
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice.cpp2
-rw-r--r--src/platformsupport/kmsconvenience/qkmsdevice_p.h1
-rw-r--r--src/plugins/bearer/android/jar/jar.pro2
-rw-r--r--src/plugins/imageformats/jpeg/qjpeghandler.cpp29
-rw-r--r--src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp3
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp2
-rw-r--r--src/plugins/printsupport/cups/qppdprintdevice.cpp2
-rw-r--r--src/tools/androiddeployqt/main.cpp922
-rw-r--r--src/tools/androidtestrunner/main.cpp4
-rw-r--r--src/widgets/dialogs/qfiledialog.cpp45
-rw-r--r--src/widgets/dialogs/qfiledialog.h1
-rw-r--r--src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp5
-rw-r--r--src/widgets/graphicsview/qgraphicsproxywidget.cpp12
-rw-r--r--src/widgets/kernel/qapplication.cpp4
-rw-r--r--src/widgets/kernel/qshortcut.cpp2
-rw-r--r--src/widgets/kernel/qwidget.cpp30
-rw-r--r--src/widgets/kernel/qwidget_p.h4
-rw-r--r--src/widgets/widgets/qdockarealayout.cpp21
-rw-r--r--src/widgets/widgets/qdockwidget.cpp7
97 files changed, 3057 insertions, 1290 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c
index 12537b6199..e4f3bd85de 100644
--- a/src/3rdparty/forkfd/forkfd.c
+++ b/src/3rdparty/forkfd/forkfd.c
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2019 Intel Corporation.
** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -59,9 +59,6 @@
# define HAVE_PIPE2 1
# endif
#endif
-#if defined(__FreeBSD__) && __FreeBSD__ >= 9
-# include <sys/procdesc.h>
-#endif
#if _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500
# define HAVE_WAITID 1
@@ -93,9 +90,11 @@
# endif
#endif
-#ifndef FFD_ATOMIC_RELAXED
-# include "forkfd_gcc.h"
-#endif
+#include "forkfd_atomic.h"
+
+static int system_has_forkfd(void);
+static int system_forkfd(int flags, pid_t *ppid, int *system);
+static int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage);
#define CHILDREN_IN_SMALL_ARRAY 16
#define CHILDREN_IN_BIG_ARRAY 256
@@ -448,6 +447,37 @@ static void ignore_sigpipe()
#endif
}
+#if defined(__GNUC__) && (!defined(__FreeBSD__) || __FreeBSD__ < 10)
+__attribute((destructor, unused)) static void cleanup();
+#endif
+
+static void cleanup()
+{
+ BigArray *array;
+ /* This function is not thread-safe!
+ * It must only be called when the process is shutting down.
+ * At shutdown, we expect no one to be calling forkfd(), so we don't
+ * need to be thread-safe with what is done there.
+ *
+ * But SIGCHLD might be delivered to any thread, including this one.
+ * There's no way to prevent that. The correct solution would be to
+ * cooperatively delete. We don't do that.
+ */
+ if (ffd_atomic_load(&forkfd_status, FFD_ATOMIC_RELAXED) == 0)
+ return;
+
+ /* notify the handler that we're no longer in operation */
+ ffd_atomic_store(&forkfd_status, 0, FFD_ATOMIC_RELAXED);
+
+ /* free any arrays we might have */
+ array = ffd_atomic_load(&children.header.nextArray, FFD_ATOMIC_ACQUIRE);
+ while (array != NULL) {
+ BigArray *next = ffd_atomic_load(&array->header.nextArray, FFD_ATOMIC_ACQUIRE);
+ free(array);
+ array = next;
+ }
+}
+
static void forkfd_initialize()
{
#if defined(HAVE_BROKEN_WAITID)
@@ -489,44 +519,15 @@ static void forkfd_initialize()
ignore_sigpipe();
#endif
-#ifndef __GNUC__
+#ifdef __GNUC__
+ (void) cleanup; /* suppress unused static function warning */
+#else
atexit(cleanup);
#endif
ffd_atomic_store(&forkfd_status, 1, FFD_ATOMIC_RELAXED);
}
-#ifdef __GNUC__
-__attribute((destructor, unused)) static void cleanup();
-#endif
-
-static void cleanup()
-{
- BigArray *array;
- /* This function is not thread-safe!
- * It must only be called when the process is shutting down.
- * At shutdown, we expect no one to be calling forkfd(), so we don't
- * need to be thread-safe with what is done there.
- *
- * But SIGCHLD might be delivered to any thread, including this one.
- * There's no way to prevent that. The correct solution would be to
- * cooperatively delete. We don't do that.
- */
- if (ffd_atomic_load(&forkfd_status, FFD_ATOMIC_RELAXED) == 0)
- return;
-
- /* notify the handler that we're no longer in operation */
- ffd_atomic_store(&forkfd_status, 0, FFD_ATOMIC_RELAXED);
-
- /* free any arrays we might have */
- array = ffd_atomic_load(&children.header.nextArray, FFD_ATOMIC_ACQUIRE);
- while (array != NULL) {
- BigArray *next = ffd_atomic_load(&array->header.nextArray, FFD_ATOMIC_ACQUIRE);
- free(array);
- array = next;
- }
-}
-
static int create_pipe(int filedes[], int flags)
{
int ret = -1;
@@ -565,55 +566,6 @@ static int create_pipe(int filedes[], int flags)
return ret;
}
-#if defined(FORKFD_NO_SPAWNFD) && defined(__FreeBSD__) && __FreeBSD__ >= 9
-# if __FreeBSD__ == 9
-/* PROCDESC is an optional feature in the kernel and wasn't enabled
- * by default on FreeBSD 9. So we need to check for it at runtime. */
-static ffd_atomic_int system_has_forkfd = FFD_ATOMIC_INIT(1);
-# else
-/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option
- * anymore and can't be disabled. */
-static const int system_has_forkfd = 1;
-# endif
-
-static int system_forkfd(int flags, pid_t *ppid)
-{
- int ret;
- pid_t pid;
- pid = pdfork(&ret, PD_DAEMON);
- if (__builtin_expect(pid == -1, 0)) {
-# if __FreeBSD__ == 9
- if (errno == ENOSYS) {
- /* PROCDESC wasn't compiled into the kernel: don't try it again. */
- ffd_atomic_store(&system_has_forkfd, 0, FFD_ATOMIC_RELAXED);
- }
-# endif
- return -1;
- }
- if (pid == 0) {
- /* child process */
- return FFD_CHILD_PROCESS;
- }
-
- /* parent process */
- if (flags & FFD_CLOEXEC)
- fcntl(ret, F_SETFD, FD_CLOEXEC);
- if (flags & FFD_NONBLOCK)
- fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK);
- if (ppid)
- *ppid = pid;
- return ret;
-}
-#else
-static const int system_has_forkfd = 0;
-static int system_forkfd(int flags, pid_t *ppid)
-{
- (void)flags;
- (void)ppid;
- return -1;
-}
-#endif
-
#ifndef FORKFD_NO_FORKFD
/**
* @brief forkfd returns a file descriptor representing a child process
@@ -661,11 +613,9 @@ int forkfd(int flags, pid_t *ppid)
int efd;
#endif
- if (system_has_forkfd) {
- ret = system_forkfd(flags, ppid);
- if (system_has_forkfd)
- return ret;
- }
+ fd = system_forkfd(flags, ppid, &ret);
+ if (ret)
+ return fd;
(void) pthread_once(&forkfd_initialization, forkfd_initialize);
@@ -790,7 +740,7 @@ int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_act
/* we can only do work if we have a way to start the child in stopped mode;
* otherwise, we have a major race condition. */
- assert(!system_has_forkfd);
+ assert(!system_has_forkfd());
(void) pthread_once(&forkfd_initialization, forkfd_initialize);
@@ -843,30 +793,13 @@ out:
#endif // _POSIX_SPAWN && !FORKFD_NO_SPAWNFD
-int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage)
+int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
{
struct pipe_payload payload;
int ret;
- if (system_has_forkfd) {
-#if defined(__FreeBSD__) && __FreeBSD__ >= 9
- pid_t pid;
- int status;
- int options = WEXITED;
-
- ret = pdgetpid(ffd, &pid);
- if (ret == -1)
- return ret;
- ret = fcntl(ffd, F_GETFL);
- if (ret == -1)
- return ret;
- options |= (ret & O_NONBLOCK) ? WNOHANG : 0;
- ret = wait4(pid, &status, options, rusage);
- if (ret != -1 && info)
- convertStatusToForkfdInfo(status, info);
- return ret == -1 ? -1 : 0;
-#endif
- }
+ if (system_has_forkfd())
+ return system_forkfd_wait(ffd, info, rusage);
ret = read(ffd, &payload, sizeof(payload));
if (ret == -1)
@@ -886,3 +819,28 @@ int forkfd_close(int ffd)
{
return close(ffd);
}
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 9
+# include "forkfd_freebsd.c"
+#else
+int system_has_forkfd()
+{
+ return 0;
+}
+
+int system_forkfd(int flags, pid_t *ppid, int *system)
+{
+ (void)flags;
+ (void)ppid;
+ *system = 0;
+ return -1;
+}
+
+int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+{
+ (void)ffd;
+ (void)info;
+ (void)rusage;
+ return -1;
+}
+#endif
diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h
index 958321c299..eb121de593 100644
--- a/src/3rdparty/forkfd/forkfd.h
+++ b/src/3rdparty/forkfd/forkfd.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2019 Intel Corporation.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
@@ -27,6 +27,7 @@
#include <fcntl.h>
#include <stdint.h>
+#include <sys/wait.h>
#include <unistd.h> // to get the POSIX flags
#if _POSIX_SPAWN > 0
@@ -48,7 +49,7 @@ struct forkfd_info {
};
int forkfd(int flags, pid_t *ppid);
-int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage);
+int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage);
int forkfd_close(int ffd);
#if _POSIX_SPAWN > 0
diff --git a/src/3rdparty/forkfd/forkfd_atomic.h b/src/3rdparty/forkfd/forkfd_atomic.h
new file mode 100644
index 0000000000..394e30d26c
--- /dev/null
+++ b/src/3rdparty/forkfd/forkfd_atomic.h
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Intel Corporation.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#if !defined(FFD_ATOMIC_H) & !defined(FFD_ATOMIC_RELAXED)
+#define FFD_ATOMIC_H
+
+#if defined(__cplusplus) && __cplusplus >= 201103L
+# include "forkfd_c11.h"
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+# include "forkfd_c11.h"
+#elif defined(__GNUC__)
+# include "forkfd_gcc.h"
+#endif
+
+#endif /* FFD_ATOMIC_h && FFD_ATOMIC_RELAXED */
+#ifndef FFD_ATOMIC_RELAXED
+# error "Could not determine atomics for this platform"
+#endif
diff --git a/src/3rdparty/forkfd/forkfd_c11.h b/src/3rdparty/forkfd/forkfd_c11.h
new file mode 100644
index 0000000000..f3dc2b5357
--- /dev/null
+++ b/src/3rdparty/forkfd/forkfd_c11.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Intel Corporation.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef FFD_ATOMIC_C11_H
+#define FFD_ATOMIC_C11_H
+
+/* atomics */
+/* Using the C11 <stdatomic.h> header or C++11's <atomic>
+ */
+
+#if defined(__cplusplus)
+# include <atomic>
+# define ffd_atomic_pointer(type) std::atomic<type*>
+# define FFD_ATOMIC_RELAXED std::memory_order_relaxed
+# define FFD_ATOMIC_ACQUIRE std::memory_order_acquire
+# define FFD_ATOMIC_RELEASE std::memory_order_release
+// acq_rel & cst not necessary
+typedef std::atomic_int ffd_atomic_int;
+#else
+# include <stdatomic.h>
+# define ffd_atomic_pointer(type) _Atomic(type*)
+# define FFD_ATOMIC_RELAXED memory_order_relaxed
+# define FFD_ATOMIC_ACQUIRE memory_order_acquire
+# define FFD_ATOMIC_RELEASE memory_order_release
+// acq_rel & cst not necessary
+
+typedef atomic_int ffd_atomic_int;
+#endif
+
+#define FFD_ATOMIC_INIT(val) ATOMIC_VAR_INIT(val)
+
+#define ffd_atomic_load(ptr, order) \
+ atomic_load_explicit(ptr, order)
+#define ffd_atomic_store(ptr, val, order) \
+ atomic_store_explicit(ptr, val, order)
+#define ffd_atomic_exchange(ptr,val,order) \
+ atomic_exchange_explicit(ptr, val, order)
+#define ffd_atomic_compare_exchange(ptr, expected, desired, order1, order2) \
+ atomic_compare_exchange_strong_explicit(ptr, expected, desired, order1, order2)
+#define ffd_atomic_add_fetch(ptr, val, order) \
+ (atomic_fetch_add_explicit(ptr, val, order) + (val))
+
+#endif
diff --git a/src/3rdparty/forkfd/forkfd_freebsd.c b/src/3rdparty/forkfd/forkfd_freebsd.c
new file mode 100644
index 0000000000..77ce3fcfad
--- /dev/null
+++ b/src/3rdparty/forkfd/forkfd_freebsd.c
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Intel Corporation.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#include "forkfd.h"
+
+#include <sys/types.h>
+#include <sys/procdesc.h>
+
+#include "forkfd_atomic.h"
+
+#if __FreeBSD__ >= 10
+/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option
+ * anymore and can't be disabled. */
+static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(1);
+#else
+static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(0);
+#endif
+
+int system_has_forkfd()
+{
+ return ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED) > 0;
+}
+
+int system_forkfd(int flags, pid_t *ppid, int *system)
+{
+ int ret;
+ pid_t pid;
+
+ int state = ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED);
+ *system = 0;
+ if (state < 0)
+ return -1;
+
+ pid = pdfork(&ret, PD_DAEMON);
+# if __FreeBSD__ == 9
+ if (state == 0 && pid != 0) {
+ /* Parent process: remember whether PROCDESC was compiled into the kernel */
+ state = (pid == -1 && errno == ENOSYS) ? -1 : 1;
+ ffd_atomic_store(&system_forkfd_state, state, FFD_ATOMIC_RELAXED);
+ }
+ if (state < 0)
+ return -1;
+# endif
+ *system = 1;
+ if (__builtin_expect(pid == -1, 0))
+ return -1;
+
+ if (pid == 0) {
+ /* child process */
+ return FFD_CHILD_PROCESS;
+ }
+
+ /* parent process */
+ if (flags & FFD_CLOEXEC)
+ fcntl(ret, F_SETFD, FD_CLOEXEC);
+ if (flags & FFD_NONBLOCK)
+ fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK);
+ if (ppid)
+ *ppid = pid;
+ return ret;
+}
+
+int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+{
+ pid_t pid;
+ int status;
+ int options = WEXITED;
+
+ int ret = pdgetpid(ffd, &pid);
+ if (ret == -1)
+ return ret;
+ ret = fcntl(ffd, F_GETFL);
+ if (ret == -1)
+ return ret;
+ options |= (ret & O_NONBLOCK) ? WNOHANG : 0;
+ ret = wait4(pid, &status, options, rusage);
+ if (ret != -1 && info)
+ convertStatusToForkfdInfo(status, info);
+ return ret == -1 ? -1 : 0;
+}
diff --git a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
index bf3de21830..4b7e1f3d38 100644
--- a/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
+++ b/src/3rdparty/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/src/android/jar/jar.pro b/src/android/jar/jar.pro
index ac6fc79968..24a83d56a1 100644
--- a/src/android/jar/jar.pro
+++ b/src/android/jar/jar.pro
@@ -1,6 +1,7 @@
TARGET = QtAndroid
CONFIG += java
+
DESTDIR = $$[QT_INSTALL_PREFIX/get]/jar
PATHPREFIX = $$PWD/src/org/qtproject/qt5/android/
diff --git a/src/android/java/java.pro b/src/android/java/java.pro
index 9d37eb1026..7f0dfa8a1b 100644
--- a/src/android/java/java.pro
+++ b/src/android/java/java.pro
@@ -1,3 +1,5 @@
+CONFIG += single_arch
+
CONFIG -= qt android_install
javaresources.files = \
diff --git a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
index d3b0600b2f..45941e8ed8 100644
--- a/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
+++ b/src/android/java/src/org/qtproject/qt5/android/bindings/QtLoader.java
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2016, BogDan Vatra <bogdan@kde.org>
+ Copyright (c) 2019, BogDan Vatra <bogdan@kde.org>
Contact: http://www.qt.io/licensing/
Commercial License Usage
@@ -63,9 +63,12 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
import dalvik.system.DexClassLoader;
@@ -85,7 +88,6 @@ public abstract class QtLoader {
public static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables";
public static final String APPLICATION_PARAMETERS_KEY = "application.parameters";
public static final String BUNDLED_LIBRARIES_KEY = "bundled.libraries";
- public static final String QT_LIBS_RESOURCE_ID_KEY = "android.app.qt_libs_resource_id";
public static final String BUNDLED_IN_LIB_RESOURCE_ID_KEY = "android.app.bundled_in_lib_resource_id";
public static final String BUNDLED_IN_ASSETS_RESOURCE_ID_KEY = "android.app.bundled_in_assets_resource_id";
public static final String MAIN_LIBRARY_KEY = "main.library";
@@ -153,7 +155,7 @@ public abstract class QtLoader {
// this repository is used to push a new release, and should be used to test your application.
// * unstable - unstable repository, DO NOT use this repository in production,
// this repository is used to push Qt snapshots.
- public String[] m_qtLibs = null; // required qt libs
+ public ArrayList<String> m_qtLibs = null; // required qt libs
public int m_displayDensity = -1;
private ContextWrapper m_context;
protected ComponentInfo m_contextInfo;
@@ -191,6 +193,36 @@ public abstract class QtLoader {
}
// Implement in subclass
+ private final List<String> supportedAbis = Arrays.asList(Build.SUPPORTED_ABIS);
+ private String preferredAbi = null;
+
+ private ArrayList<String> prefferedAbiLibs(String []libs)
+ {
+ HashMap<String, ArrayList<String>> abisLibs = new HashMap<>();
+ for (String lib : libs) {
+ String[] archLib = lib.split(";", 2);
+ if (preferredAbi != null && !archLib[0].equals(preferredAbi))
+ continue;
+ if (!abisLibs.containsKey(archLib[0]))
+ abisLibs.put(archLib[0], new ArrayList<String>());
+ abisLibs.get(archLib[0]).add(archLib[1]);
+ }
+
+ if (preferredAbi != null) {
+ if (abisLibs.containsKey(preferredAbi)) {
+ return abisLibs.get(preferredAbi);
+ }
+ return new ArrayList<String>();
+ }
+
+ for (String abi: supportedAbis) {
+ if (abisLibs.containsKey(abi)) {
+ preferredAbi = abi;
+ return abisLibs.get(abi);
+ }
+ }
+ return new ArrayList<String>();
+ }
// this function is used to load and start the loader
private void loadApplication(Bundle loaderParams)
@@ -218,12 +250,14 @@ public abstract class QtLoader {
// add all bundled Qt libs to loader params
ArrayList<String> libs = new ArrayList<String>();
- if (m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id"))
- libs.addAll(Arrays.asList(m_context.getResources().getStringArray(m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id"))));
+ if (m_contextInfo.metaData.containsKey("android.app.bundled_libs_resource_id")) {
+ int resourceId = m_contextInfo.metaData.getInt("android.app.bundled_libs_resource_id");
+ libs.addAll(prefferedAbiLibs(m_context.getResources().getStringArray(resourceId)));
+ }
String libName = null;
if (m_contextInfo.metaData.containsKey("android.app.lib_name")) {
- libName = m_contextInfo.metaData.getString("android.app.lib_name");
+ libName = m_contextInfo.metaData.getString("android.app.lib_name") + "_" + preferredAbi;
loaderParams.putString(MAIN_LIBRARY_KEY, libName); //main library contains main() function
}
@@ -278,7 +312,7 @@ public abstract class QtLoader {
try {
if (m_service != null) {
Bundle parameters = new Bundle();
- parameters.putStringArray(REQUIRED_MODULES_KEY, m_qtLibs);
+ parameters.putStringArray(REQUIRED_MODULES_KEY, (String[]) m_qtLibs.toArray());
parameters.putString(APPLICATION_TITLE_KEY, getTitle());
parameters.putInt(MINIMUM_MINISTRO_API_KEY, MINISTRO_API_LEVEL);
parameters.putInt(MINIMUM_QT_VERSION_KEY, QT_VERSION);
@@ -464,7 +498,8 @@ public abstract class QtLoader {
// why can't we load the plugins directly from libs ?!?!
String key = BUNDLED_IN_LIB_RESOURCE_ID_KEY;
if (m_contextInfo.metaData.containsKey(key)) {
- String[] list = m_context.getResources().getStringArray(m_contextInfo.metaData.getInt(key));
+ int resourceId = m_contextInfo.metaData.getInt(key);
+ ArrayList<String> list = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId));
for (String bundledImportBinary : list) {
String[] split = bundledImportBinary.split(":");
@@ -603,7 +638,7 @@ public abstract class QtLoader {
if (m_contextInfo.metaData.containsKey("android.app.qt_libs_resource_id")) {
int resourceId = m_contextInfo.metaData.getInt("android.app.qt_libs_resource_id");
- m_qtLibs = m_context.getResources().getStringArray(resourceId);
+ m_qtLibs = prefferedAbiLibs(m_context.getResources().getStringArray(resourceId));
}
if (m_contextInfo.metaData.containsKey("android.app.use_local_qt_libs")
@@ -617,6 +652,7 @@ public abstract class QtLoader {
apkDeployFromSystem = true;
String libsDir = null;
+ String bundledLibsDir = null;
if (apkDeployFromSystem) {
String systemLibsPrefix = SYSTEM_LIB_PATH;
if (m_contextInfo.metaData.containsKey("android.app.system_libs_prefix")) {
@@ -633,8 +669,11 @@ public abstract class QtLoader {
} else {
String nativeLibraryPrefix = m_context.getApplicationInfo().nativeLibraryDir + "/";
File nativeLibraryDir = new File(nativeLibraryPrefix);
- if (nativeLibraryDir.exists() && nativeLibraryDir.isDirectory() && nativeLibraryDir.list().length > 0)
+ if (nativeLibraryDir.exists() && nativeLibraryDir.isDirectory() && nativeLibraryDir.list().length > 0) {
libsDir = nativeLibraryPrefix;
+ bundledLibsDir = nativeLibraryPrefix;
+ }
+
}
if (apkDeployFromSystem && libsDir == null)
@@ -643,8 +682,8 @@ public abstract class QtLoader {
if (m_qtLibs != null) {
String libPrefix = libsDir + "lib";
- for (int i = 0; i < m_qtLibs.length; i++)
- libraryList.add(libPrefix + m_qtLibs[i] + ".so");
+ for (String lib : m_qtLibs)
+ libraryList.add(libPrefix + lib + ".so");
}
if (m_contextInfo.metaData.containsKey("android.app.bundle_local_qt_libs")
@@ -654,22 +693,26 @@ public abstract class QtLoader {
String pluginsPrefix = dataPath + "qt-reserved-files/";
if (libsDir == null)
- throw new Exception("");
+ throw new Exception("Invalid libsDir");
cleanOldCacheIfNecessary(dataPath, pluginsPrefix);
extractBundledPluginsAndImports(pluginsPrefix, libsDir);
if (m_contextInfo.metaData.containsKey(BUNDLED_IN_LIB_RESOURCE_ID_KEY)) {
- String[] extraLibs = m_contextInfo.metaData.getString("android.app.load_local_libs").split(":");
- for (String lib : extraLibs) {
- if (!lib.isEmpty())
- libraryList.add(pluginsPrefix + lib);
+ int resourceId = m_contextInfo.metaData.getInt("android.app.load_local_libs_resource_id");
+ for (String libs : prefferedAbiLibs(m_context.getResources().getStringArray(resourceId))) {
+ for (String lib : libs.split(":")) {
+ if (!lib.isEmpty())
+ libraryList.add(libsDir + lib);
+ }
}
}
ENVIRONMENT_VARIABLES += "\tQML2_IMPORT_PATH=" + pluginsPrefix + "/qml"
+ "\tQML_IMPORT_PATH=" + pluginsPrefix + "/imports"
+ "\tQT_PLUGIN_PATH=" + pluginsPrefix + "/plugins";
+ if (bundledLibsDir != null)
+ ENVIRONMENT_VARIABLES += "\tQT_BUNDLED_LIBS_PATH=" + bundledLibsDir;
}
Bundle loaderParams = new Bundle();
diff --git a/src/android/templates/AndroidManifest.xml b/src/android/templates/AndroidManifest.xml
index aed8a3c888..75da314c2b 100644
--- a/src/android/templates/AndroidManifest.xml
+++ b/src/android/templates/AndroidManifest.xml
@@ -12,7 +12,7 @@
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
- <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --">
+ <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --" android:extractNativeLibs="true">
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
android:name="org.qtproject.qt5.android.bindings.QtActivity"
android:label="-- %%INSERT_APP_NAME%% --"
@@ -36,10 +36,11 @@
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/>
<meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/>
+
<!-- Run with local libs -->
<meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/>
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
- <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/>
+ <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
<meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/>
<meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/>
<!-- Used to specify custom system library path to run with local system libs -->
diff --git a/src/android/templates/build.gradle b/src/android/templates/build.gradle
index 8d4aa63153..d2da115936 100644
--- a/src/android/templates/build.gradle
+++ b/src/android/templates/build.gradle
@@ -5,7 +5,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.0'
+ classpath 'com.android.tools.build:gradle:3.5.0'
}
}
diff --git a/src/android/templates/res/values/libs.xml b/src/android/templates/res/values/libs.xml
index 4009a7785a..db777bf433 100644
--- a/src/android/templates/res/values/libs.xml
+++ b/src/android/templates/res/values/libs.xml
@@ -1,7 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<array name="qt_sources">
- <item>https://download.qt.io/ministro/android/qt5/qt-5.9</item>
+ <item>https://download.qt.io/ministro/android/qt5/qt-5.14</item>
</array>
<!-- The following is handled automatically by the deployment tool. It should
@@ -12,12 +12,17 @@
</array>
<array name="qt_libs">
- <!-- %%INSERT_QT_LIBS%% -->
+ <!-- %%INSERT_QT_LIBS%% -->
</array>
<array name="bundled_in_lib">
<!-- %%INSERT_BUNDLED_IN_LIB%% -->
</array>
+
+ <array name="load_local_libs">
+ <!-- %%INSERT_LOCAL_LIBS%% -->
+ </array>
+
<array name="bundled_in_assets">
<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->
</array>
diff --git a/src/android/templates/templates.pro b/src/android/templates/templates.pro
index 55387f3af7..9a64251ee3 100644
--- a/src/android/templates/templates.pro
+++ b/src/android/templates/templates.pro
@@ -1,3 +1,5 @@
+CONFIG += single_arch
+
CONFIG -= qt android_install
templates.files = \
diff --git a/src/corelib/codecs/qicucodec.cpp b/src/corelib/codecs/qicucodec.cpp
index 101c3a3278..b9f1a814fa 100644
--- a/src/corelib/codecs/qicucodec.cpp
+++ b/src/corelib/codecs/qicucodec.cpp
@@ -42,8 +42,10 @@
#include "qtextcodec_p.h"
#include "qutfcodec_p.h"
#include "qlatincodec_p.h"
+#if QT_CONFIG(codecs)
#include "qtsciicodec_p.h"
#include "qisciicodec_p.h"
+#endif
#include "qsimplecodec_p.h"
#include "private/qcoreglobaldata_p.h"
#include "qdebug.h"
diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro
index b9bcc70e17..121db51eb5 100644
--- a/src/corelib/corelib.pro
+++ b/src/corelib/corelib.pro
@@ -12,6 +12,7 @@ CONFIG += qt_tracepoints
CONFIG += $$MODULE_CONFIG
DEFINES += $$MODULE_DEFINES
+android: DEFINES += LIBS_SUFFIX='\\"_$${QT_ARCH}.so\\"'
DEFINES += QT_NO_USING_NAMESPACE QT_NO_FOREACH
msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x67000000
diff --git a/src/corelib/io/forkfd_qt.cpp b/src/corelib/io/forkfd_qt.cpp
index 80d1cd54d7..cf44874153 100644
--- a/src/corelib/io/forkfd_qt.cpp
+++ b/src/corelib/io/forkfd_qt.cpp
@@ -37,37 +37,12 @@
**
****************************************************************************/
-// these might be defined via precompiled headers
-#include <QtCore/qatomic.h>
+#include <QtCore/qglobal.h>
#define FORKFD_NO_SPAWNFD
-
#if defined(QT_NO_DEBUG) && !defined(NDEBUG)
# define NDEBUG
#endif
-typedef QT_PREPEND_NAMESPACE(QBasicAtomicInt) ffd_atomic_int;
-#define ffd_atomic_pointer(type) QT_PREPEND_NAMESPACE(QBasicAtomicPointer<type>)
-
-QT_BEGIN_NAMESPACE
-
-#define FFD_ATOMIC_INIT(val) Q_BASIC_ATOMIC_INITIALIZER(val)
-
-#define FFD_ATOMIC_RELAXED Relaxed
-#define FFD_ATOMIC_ACQUIRE Acquire
-#define FFD_ATOMIC_RELEASE Release
-
-#define FFD_CONCAT(x, y) x ## y
-
-#define ffd_atomic_load(ptr,order) (ptr)->FFD_CONCAT(load, order)()
-#define ffd_atomic_store(ptr,val,order) (ptr)->FFD_CONCAT(store, order)(val)
-#define ffd_atomic_exchange(ptr,val,order) (ptr)->FFD_CONCAT(fetchAndStore, order)(val)
-#define ffd_atomic_compare_exchange(ptr,expected,desired,order1,order2) \
- (ptr)->FFD_CONCAT(testAndSet, order1)(*expected, desired, *expected)
-#define ffd_atomic_add_fetch(ptr,val,order) ((ptr)->FFD_CONCAT(fetchAndAdd, order)(val) + val)
-
-QT_END_NAMESPACE
-
-extern "C" {
+#include <forkfd.h>
#include "../../3rdparty/forkfd/forkfd.c"
-}
diff --git a/src/corelib/itemmodels/qabstractitemmodel.cpp b/src/corelib/itemmodels/qabstractitemmodel.cpp
index c5fb5b9fc5..6e97c2fd39 100644
--- a/src/corelib/itemmodels/qabstractitemmodel.cpp
+++ b/src/corelib/itemmodels/qabstractitemmodel.cpp
@@ -1898,10 +1898,17 @@ bool QAbstractItemModel::clearItemData(const QModelIndex &index)
*/
bool QAbstractItemModel::setItemData(const QModelIndex &index, const QMap<int, QVariant> &roles)
{
- bool b = true;
- for (QMap<int, QVariant>::ConstIterator it = roles.begin(); it != roles.end(); ++it)
- b = b && setData(index, it.value(), it.key());
- return b;
+ // ### Qt 6: Consider change the semantics of this function,
+ // or deprecating/removing it altogether.
+ //
+ // For instance, it should try setting *all* the data
+ // in \a roles, and not bail out at the first setData that returns
+ // false. It should also have a transactional approach.
+ for (auto it = roles.begin(), e = roles.end(); it != e; ++it) {
+ if (!setData(index, it.value(), it.key()))
+ return false;
+ }
+ return true;
}
/*!
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 4a26e9cdc0..9251a3c05f 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -527,28 +527,6 @@ inline void QMetaCallEvent::allocArgs()
/*!
\internal
- Only used by QtDeclarative - to be removed when migrated.
- */
-QMetaCallEvent::QMetaCallEvent(ushort method_offset, ushort method_relative,
- QObjectPrivate::StaticMetaCallFunction callFunction,
- const QObject *sender, int signalId,
- int nargs, int *types_, void **args_)
- : QAbstractMetaCallEvent(sender, signalId),
- d({nullptr, nullptr, callFunction, nargs, method_offset, method_relative}),
- prealloc_()
-{
- allocArgs();
- for (int arg = 0; arg < nargs; ++arg) {
- types()[arg] = types_[arg];
- args()[arg] = args_[arg];
- }
- free(types_);
- free(args_);
-}
-
-/*!
- \internal
-
Used for blocking queued connections, just passes \a args through without
allocating any memory.
*/
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 5d0b3a8399..feafcaf323 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -509,12 +509,6 @@ private:
class Q_CORE_EXPORT QMetaCallEvent : public QAbstractMetaCallEvent
{
public:
- // kept for compatibility until QtDeclarative has moved over
- QMetaCallEvent(ushort method_offset, ushort method_relative,
- QObjectPrivate::StaticMetaCallFunction callFunction,
- const QObject *sender, int signalId,
- int nargs, int *types, void **args);
-
// blocking queued with semaphore - args always owned by caller
QMetaCallEvent(ushort method_offset, ushort method_relative,
QObjectPrivate::StaticMetaCallFunction callFunction,
diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp
index 84fcc53d52..44d5513163 100644
--- a/src/corelib/plugin/qlibrary_unix.cpp
+++ b/src/corelib/plugin/qlibrary_unix.cpp
@@ -52,6 +52,10 @@
# include <private/qcore_mac_p.h>
#endif
+#ifdef Q_OS_ANDROID
+# include <private/qjnihelpers_p.h>
+#endif
+
QT_BEGIN_NAMESPACE
static QString qdlerror()
@@ -96,6 +100,9 @@ QStringList QLibraryPrivate::suffixes_sys(const QString& fullVersion)
suffixes << QLatin1String(".so.%1").arg(fullVersion);
} else {
suffixes << QLatin1String(".so");
+# ifdef Q_OS_ANDROID
+ suffixes << QStringLiteral(LIBS_SUFFIX);
+# endif
}
#endif
# ifdef Q_OS_MAC
@@ -157,9 +164,12 @@ bool QLibraryPrivate::load_sys()
// Do not unload the library during dlclose(). Consequently, the
// library's specific static variables are not reinitialized if the
// library is reloaded with dlopen() at a later time.
-#if defined(RTLD_NODELETE) && !defined(Q_OS_ANDROID)
+#if defined(RTLD_NODELETE)
if (loadHints & QLibrary::PreventUnloadHint) {
- dlFlags |= RTLD_NODELETE;
+# ifdef Q_OS_ANDROID // RTLD_NODELETE flag is supported by Android 23+
+ if (QtAndroidPrivate::androidSdkVersion() > 22)
+# endif
+ dlFlags |= RTLD_NODELETE;
}
#endif
@@ -219,7 +229,14 @@ bool QLibraryPrivate::load_sys()
} else {
attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix);
}
+
pHnd = dlopen(QFile::encodeName(attempt), dlFlags);
+#ifdef Q_OS_ANDROID
+ if (!pHnd) {
+ auto attemptFromBundle = attempt;
+ pHnd = dlopen(QFile::encodeName(attemptFromBundle.replace(QLatin1Char('/'), QLatin1Char('_'))), dlFlags);
+ }
+#endif
if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) {
// We only want to continue if dlopen failed due to that the shared library did not exist.
diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp
index ba616c0a7d..9053618014 100644
--- a/src/corelib/serialization/qcborvalue.cpp
+++ b/src/corelib/serialization/qcborvalue.cpp
@@ -915,7 +915,7 @@ void QCborContainerPrivate::replaceAt_complex(Element &e, const QCborValue &valu
// in qstring.cpp
void qt_to_latin1_unchecked(uchar *dst, const ushort *uc, qsizetype len);
-Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(const QString &s)
+Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(QStringView s)
{
qsizetype len = s.size();
QtCbor::Element e;
@@ -926,7 +926,7 @@ Q_NEVER_INLINE void QCborContainerPrivate::appendAsciiString(const QString &s)
char *ptr = data.data() + e.value + sizeof(ByteData);
uchar *l = reinterpret_cast<uchar *>(ptr);
- const ushort *uc = (const ushort *)s.unicode();
+ const ushort *uc = (const ushort *)s.utf16();
qt_to_latin1_unchecked(l, uc, len);
}
@@ -1646,13 +1646,23 @@ QCborValue::QCborValue(const QByteArray &ba)
container->ref.storeRelaxed(1);
}
+#if QT_STRINGVIEW_LEVEL < 2
/*!
Creates a QCborValue with string value \a s. The value can later be
retrieved using toString().
\sa toString(), isString(), isByteArray()
*/
-QCborValue::QCborValue(const QString &s)
+QCborValue::QCborValue(const QString &s) : QCborValue(qToStringViewIgnoringNull(s)) {}
+#endif
+
+/*!
+ Creates a QCborValue with string value \a s. The value can later be
+ retrieved using toString().
+
+ \sa toString(), isString(), isByteArray()
+*/
+QCborValue::QCborValue(QStringView s)
: n(0), container(new QCborContainerPrivate), t(String)
{
container->append(s);
diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h
index f542e44c47..f79fc572c4 100644
--- a/src/corelib/serialization/qcborvalue.h
+++ b/src/corelib/serialization/qcborvalue.h
@@ -143,7 +143,10 @@ public:
QCborValue(QCborSimpleType st) : t(type_helper(st)) {}
QCborValue(const QByteArray &ba);
+#if QT_STRINGVIEW_LEVEL < 2
QCborValue(const QString &s);
+#endif
+ QCborValue(QStringView s);
QCborValue(QLatin1String s);
#ifndef QT_NO_CAST_FROM_ASCII
QT_ASCII_CAST_WARN QCborValue(const char *s) : QCborValue(QString::fromUtf8(s)) {}
diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h
index 4050d18fa9..590c2d6e05 100644
--- a/src/corelib/serialization/qcborvalue_p.h
+++ b/src/corelib/serialization/qcborvalue_p.h
@@ -245,13 +245,21 @@ public:
appendByteData(s.latin1(), s.size(), QCborValue::String,
QtCbor::Element::StringIsAscii);
}
- void appendAsciiString(const QString &s);
+ void appendAsciiString(QStringView s);
+
+#if QT_STRINGVIEW_LEVEL < 2
void append(const QString &s)
{
+ append(qToStringViewIgnoringNull(s));
+ }
+#endif
+
+ void append(QStringView s)
+ {
if (QtPrivate::isAscii(s))
appendAsciiString(s);
else
- appendByteData(reinterpret_cast<const char *>(s.constData()), s.size() * 2,
+ appendByteData(reinterpret_cast<const char *>(s.utf16()), s.size() * 2,
QCborValue::String, QtCbor::Element::StringIsUtf16);
}
void append(const QCborValue &v)
@@ -345,33 +353,41 @@ public:
return e;
}
- bool stringEqualsElement(qsizetype idx, QLatin1String s) const
+ static int compareUtf8(const QtCbor::ByteData *b, const QLatin1String &s)
{
- const auto &e = elements.at(idx);
- if (e.type != QCborValue::String)
- return false;
-
- const QtCbor::ByteData *b = byteData(idx);
- if (!b)
- return s.isEmpty();
+ return QUtf8::compareUtf8(b->byte(), b->len, s);
+ }
- if (e.flags & QtCbor::Element::StringIsUtf16)
- return QtPrivate::compareStrings(b->asStringView(), s) == 0;
- return QUtf8::compareUtf8(b->byte(), b->len, s) == 0;
+ static int compareUtf8(const QtCbor::ByteData *b, QStringView s)
+ {
+ return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size());
}
- bool stringEqualsElement(qsizetype idx, const QString &s) const
+
+ template<typename String>
+ int stringCompareElement(const QtCbor::Element &e, String s) const
{
- const auto &e = elements.at(idx);
if (e.type != QCborValue::String)
- return false;
+ return int(e.type) - int(QCborValue::String);
- const QtCbor::ByteData *b = byteData(idx);
+ const QtCbor::ByteData *b = byteData(e);
if (!b)
- return s.isEmpty();
+ return s.isEmpty() ? 0 : -1;
if (e.flags & QtCbor::Element::StringIsUtf16)
- return QtPrivate::compareStrings(b->asStringView(), s) == 0;
- return QUtf8::compareUtf8(b->byte(), b->len, s.data(), s.size()) == 0;
+ return QtPrivate::compareStrings(b->asStringView(), s);
+ return compareUtf8(b, s);
+ }
+
+ template<typename String>
+ bool stringEqualsElement(const QtCbor::Element &e, String s) const
+ {
+ return stringCompareElement(e, s) == 0;
+ }
+
+ template<typename String>
+ bool stringEqualsElement(qsizetype idx, String s) const
+ {
+ return stringEqualsElement(elements.at(idx), s);
}
static int compareElement_helper(const QCborContainerPrivate *c1, QtCbor::Element e1,
diff --git a/src/corelib/text/qstring.h b/src/corelib/text/qstring.h
index 88286b902a..7b1351666d 100644
--- a/src/corelib/text/qstring.h
+++ b/src/corelib/text/qstring.h
@@ -57,15 +57,6 @@
#include <string>
#include <iterator>
-#if defined(Q_OS_ANDROID) && !defined(ANDROID_HAS_WSTRING)
-// std::wstring is disabled on android's glibc, as bionic lacks certain features
-// that libstdc++ checks for (like mbcslen).
-namespace std
-{
- typedef basic_string<wchar_t> wstring;
-}
-#endif
-
#include <stdarg.h>
#ifdef truncate
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index 38e9c1c3ec..cb3c0d6bb1 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -108,20 +108,8 @@ Q_STATIC_ASSERT(sizeof(pthread_t) <= sizeof(Qt::HANDLE));
enum { ThreadPriorityResetFlag = 0x80000000 };
-#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL)) && !defined(QT_LINUXBASE)
-/* LSB doesn't have __thread, https://lsbbugs.linuxfoundation.org/show_bug.cgi?id=993 */
-#define HAVE_TLS
-#endif
-#if defined(Q_CC_XLC) || defined (Q_CC_SUN)
-#define HAVE_TLS
-#endif
-#if defined(Q_OS_RTEMS)
-#define HAVE_TLS
-#endif
-#ifdef HAVE_TLS
-static __thread QThreadData *currentThreadData = 0;
-#endif
+static thread_local QThreadData *currentThreadData = 0;
static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
static pthread_key_t current_thread_data_key;
@@ -182,28 +170,19 @@ Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
// Utility functions for getting, setting and clearing thread specific data.
static QThreadData *get_thread_data()
{
-#ifdef HAVE_TLS
return currentThreadData;
-#else
- pthread_once(&current_thread_data_once, create_current_thread_data_key);
- return reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
-#endif
}
static void set_thread_data(QThreadData *data)
{
-#ifdef HAVE_TLS
currentThreadData = data;
-#endif
pthread_once(&current_thread_data_once, create_current_thread_data_key);
pthread_setspecific(current_thread_data_key, data);
}
static void clear_thread_data()
{
-#ifdef HAVE_TLS
currentThreadData = 0;
-#endif
pthread_setspecific(current_thread_data_key, 0);
}
diff --git a/src/corelib/tools/qsize.cpp b/src/corelib/tools/qsize.cpp
index fe508ad459..2cbaae117d 100644
--- a/src/corelib/tools/qsize.cpp
+++ b/src/corelib/tools/qsize.cpp
@@ -390,7 +390,25 @@ QSize QSize::scaled(const QSize &s, Qt::AspectRatioMode mode) const noexcept
\sa expandedTo(), scale()
*/
+/*!
+ \fn QSize QSize::grownBy(QMargins margins) const
+ \fn QSizeF QSizeF::grownBy(QMarginsF margins) const
+ \since 5.14
+
+ Returns the size that results from growing this size by \a margins.
+
+ \sa shrunkBy()
+*/
+/*!
+ \fn QSize QSize::shrunkBy(QMargins margins) const
+ \fn QSizeF QSizeF::shrunkBy(QMarginsF margins) const
+ \since 5.14
+
+ Returns the size that results from shrinking this size by \a margins.
+
+ \sa grownBy()
+*/
/*****************************************************************************
QSize stream functions
diff --git a/src/corelib/tools/qsize.h b/src/corelib/tools/qsize.h
index 4114609856..06de1cd63f 100644
--- a/src/corelib/tools/qsize.h
+++ b/src/corelib/tools/qsize.h
@@ -41,6 +41,7 @@
#define QSIZE_H
#include <QtCore/qnamespace.h>
+#include <QtCore/qmargins.h>
#if defined(Q_OS_DARWIN) || defined(Q_QDOC)
struct CGSize;
@@ -74,6 +75,11 @@ public:
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSize expandedTo(const QSize &) const noexcept;
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSize boundedTo(const QSize &) const noexcept;
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSize grownBy(QMargins m) const noexcept
+ { return {width() + m.left() + m.right(), height() + m.top() + m.bottom()}; }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSize shrunkBy(QMargins m) const noexcept
+ { return {width() - m.left() - m.right(), height() - m.top() - m.bottom()}; }
+
Q_DECL_RELAXED_CONSTEXPR inline int &rwidth() noexcept;
Q_DECL_RELAXED_CONSTEXPR inline int &rheight() noexcept;
@@ -238,6 +244,11 @@ public:
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSizeF expandedTo(const QSizeF &) const noexcept;
Q_REQUIRED_RESULT Q_DECL_CONSTEXPR inline QSizeF boundedTo(const QSizeF &) const noexcept;
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSizeF grownBy(QMarginsF m) const noexcept
+ { return {width() + m.left() + m.right(), height() + m.top() + m.bottom()}; }
+ Q_REQUIRED_RESULT Q_DECL_CONSTEXPR QSizeF shrunkBy(QMarginsF m) const noexcept
+ { return {width() - m.left() - m.right(), height() - m.top() - m.bottom()}; }
+
Q_DECL_RELAXED_CONSTEXPR inline qreal &rwidth() noexcept;
Q_DECL_RELAXED_CONSTEXPR inline qreal &rheight() noexcept;
diff --git a/src/gui/doc/qtgui.qdocconf b/src/gui/doc/qtgui.qdocconf
index 049b9ef179..76dd6d7ea1 100644
--- a/src/gui/doc/qtgui.qdocconf
+++ b/src/gui/doc/qtgui.qdocconf
@@ -67,3 +67,6 @@ navigation.cppclassespage = "Qt GUI C++ Classes"
# Ignore warnings about undocumented enum values for the QGradient presets
spurious += "Undocumented enum item '.*' in QGradient::Preset"
+
+# \svgcolor {#ffdead}
+macro.svgcolor.HTML = "<div style=\"padding:10px;color:#fff;background:\1;\"></div>"
diff --git a/src/gui/doc/src/includes/qt-colors.qdocinc b/src/gui/doc/src/includes/qt-colors.qdocinc
new file mode 100644
index 0000000000..4c082323b6
--- /dev/null
+++ b/src/gui/doc/src/includes/qt-colors.qdocinc
@@ -0,0 +1,86 @@
+\table
+\header
+ \li Name
+ \li Hex
+ \li Color
+\row
+ \li Color0
+ \li #000000
+ \li \svgcolor {#000000}
+\row
+ \li Color1
+ \li #ffffff
+ \li \svgcolor {#ffffff}
+\row
+ \li Black
+ \li #000000
+ \li \svgcolor {#000000}
+\row
+ \li White
+ \li #ffffff
+ \li \svgcolor {#ffffff}
+\row
+ \li DarkGray
+ \li #808080
+ \li \svgcolor {#808080}
+\row
+ \li Gray
+ \li #a0a0a4
+ \li \svgcolor {#a0a0a4}
+\row
+ \li LightGray
+ \li #c0c0c0
+ \li \svgcolor {#c0c0c0}
+\row
+ \li Red
+ \li #ff0000
+ \li \svgcolor {#ff0000}
+\row
+ \li Green
+ \li #00ff00
+ \li \svgcolor {#00ff00}
+\row
+ \li Blue
+ \li #0000ff
+ \li \svgcolor {#0000ff}
+\row
+ \li Cyan
+ \li #00ffff
+ \li \svgcolor {#00ffff}
+\row
+ \li Magenta
+ \li #ff00ff
+ \li \svgcolor {#ff00ff}
+\row
+ \li Yellow
+ \li #ffff00
+ \li \svgcolor {#ffff00}
+\row
+ \li DarkRed
+ \li #800000
+ \li \svgcolor {#800000}
+\row
+ \li DarkGreen
+ \li #008000
+ \li \svgcolor {#008000}
+\row
+ \li DarkBlue
+ \li #000080
+ \li \svgcolor {#000080}
+\row
+ \li DarkCyan
+ \li #008080
+ \li \svgcolor {#008080}
+\row
+ \li DarkMagenta
+ \li #800080
+ \li \svgcolor {#800080}
+\row
+ \li DarkYellow
+ \li #808000
+ \li \svgcolor {#808000}
+\row
+ \li Transparent
+ \li #00000000
+ \li (transparent)
+\endtable
diff --git a/src/gui/doc/src/includes/svg-colors.qdocinc b/src/gui/doc/src/includes/svg-colors.qdocinc
new file mode 100644
index 0000000000..4e5fb56d5e
--- /dev/null
+++ b/src/gui/doc/src/includes/svg-colors.qdocinc
@@ -0,0 +1,594 @@
+\table
+\header
+ \li Name
+ \li Hex
+ \li Color
+\row
+ \li aliceblue
+ \li #f0f8ff
+ \li \svgcolor {#f0f8ff}
+\row
+ \li antiquewhite
+ \li #faebd7
+ \li \svgcolor {#faebd7}
+\row
+ \li aqua
+ \li #00ffff
+ \li \svgcolor {#00ffff}
+\row
+ \li aquamarine
+ \li #7fffd4
+ \li \svgcolor {#7fffd4}
+\row
+ \li azure
+ \li #f0ffff
+ \li \svgcolor {#f0ffff}
+\row
+ \li beige
+ \li #f5f5dc
+ \li \svgcolor {#f5f5dc}
+\row
+ \li bisque
+ \li #ffe4c4
+ \li \svgcolor {#ffe4c4}
+\row
+ \li black
+ \li #000000
+ \li \svgcolor {#000000}
+\row
+ \li blanchedalmond
+ \li #ffebcd
+ \li \svgcolor {#ffebcd}
+\row
+ \li blue
+ \li #0000ff
+ \li \svgcolor {#0000ff}
+\row
+ \li blueviolet
+ \li #8a2be2
+ \li \svgcolor {#8a2be2}
+\row
+ \li brown
+ \li #a52a2a
+ \li \svgcolor {#a52a2a}
+\row
+ \li burlywood
+ \li #deb887
+ \li \svgcolor {#deb887}
+\row
+ \li cadetblue
+ \li #5f9ea0
+ \li \svgcolor {#5f9ea0}
+\row
+ \li chartreuse
+ \li #7fff00
+ \li \svgcolor {#7fff00}
+\row
+ \li chocolate
+ \li #d2691e
+ \li \svgcolor {#d2691e}
+\row
+ \li coral
+ \li #ff7f50
+ \li \svgcolor {#ff7f50}
+\row
+ \li cornflowerblue
+ \li #6495ed
+ \li \svgcolor {#6495ed}
+\row
+ \li cornsilk
+ \li #fff8dc
+ \li \svgcolor {#fff8dc}
+\row
+ \li crimson
+ \li #dc143c
+ \li \svgcolor {#dc143c}
+\row
+ \li cyan
+ \li #00ffff
+ \li \svgcolor {#00ffff}
+\row
+ \li darkblue
+ \li #00008b
+ \li \svgcolor {#00008b}
+\row
+ \li darkcyan
+ \li #008b8b
+ \li \svgcolor {#008b8b}
+\row
+ \li darkgoldenrod
+ \li #b8860b
+ \li \svgcolor {#b8860b}
+\row
+ \li darkgray
+ \li #a9a9a9
+ \li \svgcolor {#a9a9a9}
+\row
+ \li darkgreen
+ \li #006400
+ \li \svgcolor {#006400}
+\row
+ \li darkgrey
+ \li #a9a9a9
+ \li \svgcolor {#a9a9a9}
+\row
+ \li darkkhaki
+ \li #bdb76b
+ \li \svgcolor {#bdb76b}
+\row
+ \li darkmagenta
+ \li #8b008b
+ \li \svgcolor {#8b008b}
+\row
+ \li darkolivegreen
+ \li #556b2f
+ \li \svgcolor {#556b2f}
+\row
+ \li darkorange
+ \li #ff8c00
+ \li \svgcolor {#ff8c00}
+\row
+ \li darkorchid
+ \li #9932cc
+ \li \svgcolor {#9932cc}
+\row
+ \li darkred
+ \li #8b0000
+ \li \svgcolor {#8b0000}
+\row
+ \li darksalmon
+ \li #e9967a
+ \li \svgcolor {#e9967a}
+\row
+ \li darkseagreen
+ \li #8fbc8f
+ \li \svgcolor {#8fbc8f}
+\row
+ \li darkslateblue
+ \li #483d8b
+ \li \svgcolor {#483d8b}
+\row
+ \li darkslategray
+ \li #2f4f4f
+ \li \svgcolor {#2f4f4f}
+\row
+ \li darkslategrey
+ \li #2f4f4f
+ \li \svgcolor {#2f4f4f}
+\row
+ \li darkturquoise
+ \li #00ced1
+ \li \svgcolor {#00ced1}
+\row
+ \li darkviolet
+ \li #9400d3
+ \li \svgcolor {#9400d3}
+\row
+ \li deeppink
+ \li #ff1493
+ \li \svgcolor {#ff1493}
+\row
+ \li deepskyblue
+ \li #00bfff
+ \li \svgcolor {#00bfff}
+\row
+ \li dimgray
+ \li #696969
+ \li \svgcolor {#696969}
+\row
+ \li dimgrey
+ \li #696969
+ \li \svgcolor {#696969}
+\row
+ \li dodgerblue
+ \li #1e90ff
+ \li \svgcolor {#1e90ff}
+\row
+ \li firebrick
+ \li #b22222
+ \li \svgcolor {#b22222}
+\row
+ \li floralwhite
+ \li #fffaf0
+ \li \svgcolor {#fffaf0}
+\row
+ \li forestgreen
+ \li #228b22
+ \li \svgcolor {#228b22}
+\row
+ \li fuchsia
+ \li #ff00ff
+ \li \svgcolor {#ff00ff}
+\row
+ \li gainsboro
+ \li #dcdcdc
+ \li \svgcolor {#dcdcdc}
+\row
+ \li ghostwhite
+ \li #f8f8ff
+ \li \svgcolor {#f8f8ff}
+\row
+ \li gold
+ \li #ffd700
+ \li \svgcolor {#ffd700}
+\row
+ \li goldenrod
+ \li #daa520
+ \li \svgcolor {#daa520}
+\row
+ \li gray
+ \li #808080
+ \li \svgcolor {#808080}
+\row
+ \li grey
+ \li #808080
+ \li \svgcolor {#808080}
+\row
+ \li green
+ \li #008000
+ \li \svgcolor {#008000}
+\row
+ \li greenyellow
+ \li #adff2f
+ \li \svgcolor {#adff2f}
+\row
+ \li honeydew
+ \li #f0fff0
+ \li \svgcolor {#f0fff0}
+\row
+ \li hotpink
+ \li #ff69b4
+ \li \svgcolor {#ff69b4}
+\row
+ \li indianred
+ \li #cd5c5c
+ \li \svgcolor {#cd5c5c}
+\row
+ \li indigo
+ \li #4b0082
+ \li \svgcolor {#4b0082}
+\row
+ \li ivory
+ \li #fffff0
+ \li \svgcolor {#fffff0}
+\row
+ \li khaki
+ \li #f0e68c
+ \li \svgcolor {#f0e68c}
+\row
+ \li lavender
+ \li #e6e6fa
+ \li \svgcolor {#e6e6fa}
+\row
+ \li lavenderblush
+ \li #fff0f5
+ \li \svgcolor {#fff0f5}
+\row
+ \li lawngreen
+ \li #7cfc00
+ \li \svgcolor {#7cfc00}
+\row
+ \li lemonchiffon
+ \li #fffacd
+ \li \svgcolor {#fffacd}
+\row
+ \li lightblue
+ \li #add8e6
+ \li \svgcolor {#add8e6}
+\row
+ \li lightcoral
+ \li #f08080
+ \li \svgcolor {#f08080}
+\row
+ \li lightcyan
+ \li #e0ffff
+ \li \svgcolor {#e0ffff}
+\row
+ \li lightgoldenrodyellow
+ \li #fafad2
+ \li \svgcolor {#fafad2}
+\row
+ \li lightgray
+ \li #d3d3d3
+ \li \svgcolor {#d3d3d3}
+\row
+ \li lightgreen
+ \li #90ee90
+ \li \svgcolor {#90ee90}
+\row
+ \li lightgrey
+ \li #d3d3d3
+ \li \svgcolor {#d3d3d3}
+\row
+ \li lightpink
+ \li #ffb6c1
+ \li \svgcolor {#ffb6c1}
+\row
+ \li lightsalmon
+ \li #ffa07a
+ \li \svgcolor {#ffa07a}
+\row
+ \li lightseagreen
+ \li #20b2aa
+ \li \svgcolor {#20b2aa}
+\row
+ \li lightskyblue
+ \li #87cefa
+ \li \svgcolor {#87cefa}
+\row
+ \li lightslategray
+ \li #778899
+ \li \svgcolor {#778899}
+\row
+ \li lightslategrey
+ \li #778899
+ \li \svgcolor {#778899}
+\row
+ \li lightsteelblue
+ \li #b0c4de
+ \li \svgcolor {#b0c4de}
+\row
+ \li lightyellow
+ \li #ffffe0
+ \li \svgcolor {#ffffe0}
+\row
+ \li lime
+ \li #00ff00
+ \li \svgcolor {#00ff00}
+\row
+ \li limegreen
+ \li #32cd32
+ \li \svgcolor {#32cd32}
+\row
+ \li linen
+ \li #faf0e6
+ \li \svgcolor {#faf0e6}
+\row
+ \li magenta
+ \li #ff00ff
+ \li \svgcolor {#ff00ff}
+\row
+ \li maroon
+ \li #800000
+ \li \svgcolor {#800000}
+\row
+ \li mediumaquamarine
+ \li #66cdaa
+ \li \svgcolor {#66cdaa}
+\row
+ \li mediumblue
+ \li #0000cd
+ \li \svgcolor {#0000cd}
+\row
+ \li mediumorchid
+ \li #ba55d3
+ \li \svgcolor {#ba55d3}
+\row
+ \li mediumpurple
+ \li #9370db
+ \li \svgcolor {#9370db}
+\row
+ \li mediumseagreen
+ \li #3cb371
+ \li \svgcolor {#3cb371}
+\row
+ \li mediumslateblue
+ \li #7b68ee
+ \li \svgcolor {#7b68ee}
+\row
+ \li mediumspringgreen
+ \li #00fa9a
+ \li \svgcolor {#00fa9a}
+\row
+ \li mediumturquoise
+ \li #48d1cc
+ \li \svgcolor {#48d1cc}
+\row
+ \li mediumvioletred
+ \li #c71585
+ \li \svgcolor {#c71585}
+\row
+ \li midnightblue
+ \li #191970
+ \li \svgcolor {#191970}
+\row
+ \li mintcream
+ \li #f5fffa
+ \li \svgcolor {#f5fffa}
+\row
+ \li mistyrose
+ \li #ffe4e1
+ \li \svgcolor {#ffe4e1}
+\row
+ \li moccasin
+ \li #ffe4b5
+ \li \svgcolor {#ffe4b5}
+\row
+ \li navajowhite
+ \li #ffdead
+ \li \svgcolor {#ffdead}
+\row
+ \li navy
+ \li #000080
+ \li \svgcolor {#000080}
+\row
+ \li oldlace
+ \li #fdf5e6
+ \li \svgcolor {#fdf5e6}
+\row
+ \li olive
+ \li #808000
+ \li \svgcolor {#808000}
+\row
+ \li olivedrab
+ \li #6b8e23
+ \li \svgcolor {#6b8e23}
+\row
+ \li orange
+ \li #ffa500
+ \li \svgcolor {#ffa500}
+\row
+ \li orangered
+ \li #ff4500
+ \li \svgcolor {#ff4500}
+\row
+ \li orchid
+ \li #da70d6
+ \li \svgcolor {#da70d6}
+\row
+ \li palegoldenrod
+ \li #eee8aa
+ \li \svgcolor {#eee8aa}
+\row
+ \li palegreen
+ \li #98fb98
+ \li \svgcolor {#98fb98}
+\row
+ \li paleturquoise
+ \li #afeeee
+ \li \svgcolor {#afeeee}
+\row
+ \li palevioletred
+ \li #db7093
+ \li \svgcolor {#db7093}
+\row
+ \li papayawhip
+ \li #ffefd5
+ \li \svgcolor {#ffefd5}
+\row
+ \li peachpuff
+ \li #ffdab9
+ \li \svgcolor {#ffdab9}
+\row
+ \li peru
+ \li #cd853f
+ \li \svgcolor {#cd853f}
+\row
+ \li pink
+ \li #ffc0cb
+ \li \svgcolor {#ffc0cb}
+\row
+ \li plum
+ \li #dda0dd
+ \li \svgcolor {#dda0dd}
+\row
+ \li powderblue
+ \li #b0e0e6
+ \li \svgcolor {#b0e0e6}
+\row
+ \li purple
+ \li #800080
+ \li \svgcolor {#800080}
+\row
+ \li red
+ \li #ff0000
+ \li \svgcolor {#ff0000}
+\row
+ \li rosybrown
+ \li #bc8f8f
+ \li \svgcolor {#bc8f8f}
+\row
+ \li royalblue
+ \li #4169e1
+ \li \svgcolor {#4169e1}
+\row
+ \li saddlebrown
+ \li #8b4513
+ \li \svgcolor {#8b4513}
+\row
+ \li salmon
+ \li #fa8072
+ \li \svgcolor {#fa8072}
+\row
+ \li sandybrown
+ \li #f4a460
+ \li \svgcolor {#f4a460}
+\row
+ \li seagreen
+ \li #2e8b57
+ \li \svgcolor {#2e8b57}
+\row
+ \li seashell
+ \li #fff5ee
+ \li \svgcolor {#fff5ee}
+\row
+ \li sienna
+ \li #a0522d
+ \li \svgcolor {#a0522d}
+\row
+ \li silver
+ \li #c0c0c0
+ \li \svgcolor {#c0c0c0}
+\row
+ \li skyblue
+ \li #87ceeb
+ \li \svgcolor {#87ceeb}
+\row
+ \li slateblue
+ \li #6a5acd
+ \li \svgcolor {#6a5acd}
+\row
+ \li slategray
+ \li #708090
+ \li \svgcolor {#708090}
+\row
+ \li slategrey
+ \li #708090
+ \li \svgcolor {#708090}
+\row
+ \li snow
+ \li #fffafa
+ \li \svgcolor {#fffafa}
+\row
+ \li springgreen
+ \li #00ff7f
+ \li \svgcolor {#00ff7f}
+\row
+ \li steelblue
+ \li #4682b4
+ \li \svgcolor {#4682b4}
+\row
+ \li tan
+ \li #d2b48c
+ \li \svgcolor {#d2b48c}
+\row
+ \li teal
+ \li #008080
+ \li \svgcolor {#008080}
+\row
+ \li thistle
+ \li #d8bfd8
+ \li \svgcolor {#d8bfd8}
+\row
+ \li tomato
+ \li #ff6347
+ \li \svgcolor {#ff6347}
+\row
+ \li turquoise
+ \li #40e0d0
+ \li \svgcolor {#40e0d0}
+\row
+ \li violet
+ \li #ee82ee
+ \li \svgcolor {#ee82ee}
+\row
+ \li wheat
+ \li #f5deb3
+ \li \svgcolor {#f5deb3}
+\row
+ \li white
+ \li #ffffff
+ \li \svgcolor {#ffffff}
+\row
+ \li whitesmoke
+ \li #f5f5f5
+ \li \svgcolor {#f5f5f5}
+\row
+ \li yellow
+ \li #ffff00
+ \li \svgcolor {#ffff00}
+\row
+ \li yellowgreen
+ \li #9acd32
+ \li \svgcolor {#9acd32}
+\endtable
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index 70fccbc378..3b2ced3f58 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -82,7 +82,18 @@ qtConfig(png) {
}
# SIMD
-SSSE3_SOURCES += image/qimage_ssse3.cpp
-NEON_SOURCES += image/qimage_neon.cpp
-MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp
-MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S
+!android {
+ SSSE3_SOURCES += image/qimage_ssse3.cpp
+ NEON_SOURCES += image/qimage_neon.cpp
+ MIPS_DSPR2_SOURCES += image/qimage_mips_dspr2.cpp
+ MIPS_DSPR2_ASM += image/qimage_mips_dspr2_asm.S
+} else {
+ # see https://developer.android.com/ndk/guides/abis
+ arm64-v8a {
+ SOURCES += image/qimage_neon.cpp
+ }
+ x86 | x86_64 {
+ DEFINES += QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSSE3
+ SOURCES += image/qimage_ssse3.cpp
+ }
+}
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 8e0bbb6907..b7f67cd7ef 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -287,6 +287,7 @@ bool QImageData::checkForAlphaPixels() const
case QImage::Format_RGB555:
case QImage::Format_RGB666:
case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
case QImage::Format_RGBX8888:
case QImage::Format_BGR30:
case QImage::Format_RGB30:
@@ -720,6 +721,7 @@ bool QImageData::checkForAlphaPixels() const
\value Format_RGBA64 The image is stored using a 64-bit halfword-ordered RGBA format (16-16-16-16). (added in Qt 5.12)
\value Format_RGBA64_Premultiplied The image is stored using a premultiplied 64-bit halfword-ordered
RGBA format (16-16-16-16). (added in Qt 5.12)
+ \value Format_BGR888 The image is stored using a 24-bit BGR format. (added in Qt 5.14)
\note Drawing into a QImage with QImage::Format_Indexed8 is not
supported.
@@ -5550,6 +5552,19 @@ static Q_CONSTEXPR QPixelFormat pixelformats[] = {
/*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
/*INTERPRETATION*/ QPixelFormat::UnsignedShort,
/*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
+ //QImage::Format_BGR888:
+ QPixelFormat(QPixelFormat::BGR,
+ /*RED*/ 8,
+ /*GREEN*/ 8,
+ /*BLUE*/ 8,
+ /*FOURTH*/ 0,
+ /*FIFTH*/ 0,
+ /*ALPHA*/ 0,
+ /*ALPHA USAGE*/ QPixelFormat::IgnoresAlpha,
+ /*ALPHA POSITION*/ QPixelFormat::AtBeginning,
+ /*PREMULTIPLIED*/ QPixelFormat::NotPremultiplied,
+ /*INTERPRETATION*/ QPixelFormat::UnsignedByte,
+ /*BYTE ORDER*/ QPixelFormat::CurrentSystemEndian),
};
Q_STATIC_ASSERT(sizeof(pixelformats) / sizeof(*pixelformats) == QImage::NImageFormats);
diff --git a/src/gui/image/qimage.h b/src/gui/image/qimage.h
index 7c68168be8..7544ccca05 100644
--- a/src/gui/image/qimage.h
+++ b/src/gui/image/qimage.h
@@ -131,6 +131,7 @@ public:
Format_RGBA64,
Format_RGBA64_Premultiplied,
Format_Grayscale16,
+ Format_BGR888,
#ifndef Q_QDOC
NImageFormats
#endif
diff --git a/src/gui/image/qimage_conversions.cpp b/src/gui/image/qimage_conversions.cpp
index 837ac88470..539bac222a 100644
--- a/src/gui/image/qimage_conversions.cpp
+++ b/src/gui/image/qimage_conversions.cpp
@@ -429,8 +429,8 @@ typedef void (QT_FASTCALL *Rgb888ToRgbConverter)(quint32 *dst, const uchar *src,
template <bool rgbx>
static void convert_RGB888_to_RGB(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
- Q_ASSERT(src->format == QImage::Format_RGB888);
- if (rgbx)
+ Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888);
+ if (rgbx ^ (src->format == QImage::Format_BGR888))
Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied);
else
Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
@@ -1421,6 +1421,69 @@ static void convert_RGBA64_to_gray16(QImageData *dest, const QImageData *src, Qt
}
}
+static void convert_RGB888_to_BGR888(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888);
+ Q_ASSERT(dest->format == QImage::Format_RGB888 || dest->format == QImage::Format_BGR888);
+ Q_ASSERT(src->width == dest->width);
+ Q_ASSERT(src->height == dest->height);
+
+ const qsizetype sbpl = src->bytes_per_line;
+ const qsizetype dbpl = dest->bytes_per_line;
+ const uchar *src_data = src->data;
+ uchar *dest_data = dest->data;
+
+ for (int i = 0; i < src->height; ++i) {
+ int pixel = 0;
+ // Handle 4 pixels (12 bytes) at a time
+ for (; pixel + 3 < src->width; pixel += 4) {
+ const uchar *src = src_data + pixel * 3;
+ quint32 *dest_packed = (quint32 *) (dest_data + pixel * 3);
+ dest_packed[0] = (src[5] << 24) | (src[0] << 16) | (src[1] << 8) | (src[2] << 0);
+ dest_packed[1] = (src[7] << 24) | (src[8] << 16) | (src[3] << 8) | (src[4] << 0);
+ dest_packed[2] = (src[9] << 24) | (src[10] << 16) | (src[11] << 8) | (src[6] << 0);
+ }
+
+ // epilog: handle left over pixels
+ for (; pixel < src->width; ++pixel) {
+ dest_data[pixel * 3 + 0] = src_data[pixel * 3 + 2];
+ dest_data[pixel * 3 + 1] = src_data[pixel * 3 + 1];
+ dest_data[pixel * 3 + 2] = src_data[pixel * 3 + 0];
+ }
+
+ src_data += sbpl;
+ dest_data += dbpl;
+ }
+}
+
+static bool convert_RGB888_to_BGR888_inplace(QImageData *data, Qt::ImageConversionFlags)
+{
+ Q_ASSERT(data->format == QImage::Format_RGB888 || data->format == QImage::Format_BGR888);
+
+ const qsizetype bpl = data->bytes_per_line;
+ uchar *line_data = data->data;
+
+ for (int i = 0; i < data->height; ++i) {
+ for (int j = 0; j < data->width; ++j)
+ qSwap(line_data[j * 3 + 0], line_data[j * 3 + 2]);
+ line_data += bpl;
+ }
+
+ switch (data->format) {
+ case QImage::Format_RGB888:
+ data->format = QImage::Format_BGR888;
+ break;
+ case QImage::Format_BGR888:
+ data->format = QImage::Format_RGB888;
+ break;
+ default:
+ Q_UNREACHABLE();
+ data->format = QImage::Format_Invalid;
+ return false;
+ }
+ return true;
+}
+
static QVector<QRgb> fix_color_table(const QVector<QRgb> &ctbl, QImage::Format format)
{
QVector<QRgb> colorTable = ctbl;
@@ -2265,7 +2328,7 @@ static bool convert_Grayscale8_to_Indexed8_inplace(QImageData *data, Qt::ImageCo
Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
{
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
},
{
0,
@@ -2286,7 +2349,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Mono
{
@@ -2308,7 +2371,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_MonoLSB
{
@@ -2333,7 +2396,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0, 0, 0, 0,
convert_Indexed8_to_Alpha8,
convert_Indexed8_to_Grayscale8,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_Indexed8
{
@@ -2361,7 +2424,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB_to_RGB30<PixelOrderRGB, false>,
0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_RGB32
{
@@ -2391,7 +2454,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0,
0,
convert_ARGB32_to_RGBA64<false>,
- 0, 0
+ 0, 0, 0
}, // Format_ARGB32
{
@@ -2416,7 +2479,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_ARGB_to_RGBA,
0, 0, 0, 0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_ARGB32_Premultiplied
{
@@ -2438,7 +2501,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB16
{
@@ -2460,7 +2523,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8565_Premultiplied
{
@@ -2482,7 +2545,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB666
{
@@ -2504,7 +2567,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB6666_Premultiplied
{
@@ -2526,7 +2589,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB555
{
@@ -2548,7 +2611,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8555_Premultiplied
{
@@ -2565,13 +2628,14 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0,
+ 0, // self
0,
0,
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
convert_RGB888_to_RGB<true>,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ convert_RGB888_to_BGR888,
}, // Format_RGB888
{
@@ -2593,7 +2657,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB444
{
@@ -2614,7 +2678,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB4444_Premultiplied
{
0,
@@ -2641,7 +2705,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGB_to_RGB30<PixelOrderRGB, true>,
0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_RGBX8888
{
0,
@@ -2670,7 +2734,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0, 0,
0,
convert_ARGB32_to_RGBA64<true>,
- 0, 0
+ 0, 0, 0
}, // Format_RGBA8888
{
@@ -2692,7 +2756,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBA8888_Premultiplied
{
@@ -2720,7 +2784,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_BGR30_to_RGB30,
convert_BGR30_to_RGB30,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_BGR30
{
0,
@@ -2747,7 +2811,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_A2RGB30_PM_to_RGB30<true>,
convert_BGR30_to_RGB30,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_A2BGR30_Premultiplied
{
0,
@@ -2773,7 +2837,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_BGR30_to_RGB30,
0,
convert_passthrough,
- 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB30
{
0,
@@ -2800,7 +2864,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_A2RGB30_PM_to_RGB30<false>,
0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_A2RGB30_Premultiplied
{
0,
@@ -2820,7 +2884,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Alpha8
{
0,
@@ -2840,14 +2904,15 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Grayscale8
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // self
convert_passthrough,
convert_passthrough,
- convert_RGBA64_to_gray16
+ convert_RGBA64_to_gray16,
+ 0
}, // Format_RGBX64
{
0,
@@ -2874,6 +2939,7 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGBA64_to_RGBx64,
0, // self
convert_RGBA64_to_RGBA64PM,
+ 0,
0
}, // Format_RGBA64
{
@@ -2901,7 +2967,8 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_RGBA64PM_to_RGBA64<true>,
convert_RGBA64PM_to_RGBA64<false>,
0, // self
- convert_RGBA64_to_gray16
+ convert_RGBA64_to_gray16,
+ 0
}, // Format_RGBA64_Premultiplied
{
0,
@@ -2931,20 +2998,46 @@ Image_Converter qimage_converter_map[QImage::NImageFormats][QImage::NImageFormat
convert_gray16_to_RGBA64,
convert_gray16_to_RGBA64,
convert_gray16_to_RGBA64,
- 0 // self
+ 0, // self
+ 0
}, // Format_Grayscale16
+ {
+ 0,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ convert_RGB888_to_BGR888,
+ 0,
+ 0,
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ convert_RGB888_to_RGB<false>,
+ convert_RGB888_to_RGB<false>,
+ convert_RGB888_to_RGB<false>,
+#else
+ 0, 0, 0,
+#endif
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, // self
+ }, // Format_BGR888
};
InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QImage::NImageFormats] =
{
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
},
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Mono
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_MonoLSB
{
0,
@@ -2968,7 +3061,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, 0, 0, 0, 0,
convert_Indexed8_to_Alpha8_inplace,
convert_Indexed8_to_Grayscale8_inplace,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_Indexed8
{
0,
@@ -2995,7 +3088,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, false>,
0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_RGB32
{
0,
@@ -3022,7 +3115,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, false>,
0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_ARGB32
{
0,
@@ -3046,34 +3139,35 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_ARGB_to_RGBA_inplace<QImage::Format_RGBA8888_Premultiplied>,
0, 0, 0, 0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_ARGB32_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB16
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8565_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB666
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB6666_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB555
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB8555_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ convert_RGB888_to_BGR888_inplace
}, // Format_RGB888
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB444
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_ARGB4444_Premultiplied
{
0,
@@ -3100,7 +3194,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, true>,
0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_RGBX8888
{
0,
@@ -3127,7 +3221,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_RGB_to_RGB30_inplace<PixelOrderRGB, true>,
0,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_RGBA8888
{
0,
@@ -3149,7 +3243,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0,
0,
0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_RGBA8888_Premultiplied
{
0,
@@ -3176,7 +3270,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_BGR30_to_RGB30_inplace,
convert_BGR30_to_A2RGB30_inplace,
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_BGR30
{
0,
@@ -3202,7 +3296,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, // self
convert_A2RGB30_PM_to_RGB30_inplace<true>,
convert_BGR30_to_RGB30_inplace,
- 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0
}, // Format_A2BGR30_Premultiplied
{
0,
@@ -3228,7 +3322,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_BGR30_to_A2RGB30_inplace,
0, // self
convert_passthrough_inplace<QImage::Format_A2RGB30_Premultiplied>,
- 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0
}, // Format_RGB30
{
0,
@@ -3255,7 +3349,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
convert_A2RGB30_PM_to_RGB30_inplace<false>,
0, // self
0, 0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_A2RGB30_Premultiplied
{
0,
@@ -3280,7 +3374,7 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, 0, 0, 0,
0, // self
0,
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_Alpha8
{
0,
@@ -3305,32 +3399,37 @@ InPlace_Image_Converter qimage_inplace_converter_map[QImage::NImageFormats][QIma
0, 0, 0, 0,
0,
0, // self
- 0, 0, 0, 0
+ 0, 0, 0, 0, 0
}, // Format_Grayscale8
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, // self
convert_passthrough_inplace<QImage::Format_RGBA64>,
convert_passthrough_inplace<QImage::Format_RGBA64_Premultiplied>,
- 0
+ 0, 0
}, // Format_RGBX64
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
convert_RGBA64_to_RGBx64_inplace,
0, // self
convert_RGBA64_to_RGBA64PM_inplace,
- 0
+ 0, 0
}, // Format_RGBA64
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
convert_RGBA64PM_to_RGBA64_inplace<true>,
convert_RGBA64PM_to_RGBA64_inplace<false>,
0, // self
- 0
+ 0, 0
}, // Format_RGBA64_Premultiplied
{
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}, // Format_Grayscale16
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ convert_RGB888_to_BGR888_inplace,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }, // Format_BGR888
};
static void qInitImageConversions()
@@ -3341,6 +3440,9 @@ static void qInitImageConversions()
qimage_converter_map[QImage::Format_RGB888][QImage::Format_RGB32] = convert_RGB888_to_RGB32_ssse3;
qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32] = convert_RGB888_to_RGB32_ssse3;
qimage_converter_map[QImage::Format_RGB888][QImage::Format_ARGB32_Premultiplied] = convert_RGB888_to_RGB32_ssse3;
+ qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBX8888] = convert_RGB888_to_RGB32_ssse3;
+ qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888] = convert_RGB888_to_RGB32_ssse3;
+ qimage_converter_map[QImage::Format_BGR888][QImage::Format_RGBA8888_Premultiplied] = convert_RGB888_to_RGB32_ssse3;
}
#endif
diff --git a/src/gui/image/qimage_p.h b/src/gui/image/qimage_p.h
index 9da6acd0a7..9e2d9c86bb 100644
--- a/src/gui/image/qimage_p.h
+++ b/src/gui/image/qimage_p.h
@@ -207,6 +207,7 @@ inline int qt_depthForFormat(QImage::Format format)
case QImage::Format_ARGB8565_Premultiplied:
case QImage::Format_ARGB8555_Premultiplied:
case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
depth = 24;
break;
case QImage::Format_RGBX64:
diff --git a/src/gui/image/qimage_ssse3.cpp b/src/gui/image/qimage_ssse3.cpp
index 9cdfba20e3..fb81a1a6c3 100644
--- a/src/gui/image/qimage_ssse3.cpp
+++ b/src/gui/image/qimage_ssse3.cpp
@@ -121,8 +121,11 @@ Q_GUI_EXPORT void QT_FASTCALL qt_convert_rgb888_to_rgb32_ssse3(quint32 *dst, con
void convert_RGB888_to_RGB32_ssse3(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
{
- Q_ASSERT(src->format == QImage::Format_RGB888);
- Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
+ Q_ASSERT(src->format == QImage::Format_RGB888 || src->format == QImage::Format_BGR888);
+ if (src->format == QImage::Format_BGR888)
+ Q_ASSERT(dest->format == QImage::Format_RGBX8888 || dest->format == QImage::Format_RGBA8888 || dest->format == QImage::Format_RGBA8888_Premultiplied);
+ else
+ Q_ASSERT(dest->format == QImage::Format_RGB32 || dest->format == QImage::Format_ARGB32 || dest->format == QImage::Format_ARGB32_Premultiplied);
Q_ASSERT(src->width == dest->width);
Q_ASSERT(src->height == dest->height);
diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp
index 3a2db74098..8aad77b991 100644
--- a/src/gui/image/qpixmap_win.cpp
+++ b/src/gui/image/qpixmap_win.cpp
@@ -281,6 +281,7 @@ Q_GUI_EXPORT HBITMAP qt_imageToWinHBITMAP(const QImage &imageIn, int hbitmapForm
}
break;
case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
compression = BI_RGB;
bitCount = 24u;
break;
@@ -368,7 +369,7 @@ static QImage::Format imageFromWinHBITMAP_Format(const BITMAPINFOHEADER &header,
? QImage::Format_RGB32 : QImage::Format_ARGB32_Premultiplied;
break;
case 24:
- result = QImage::Format_RGB888;
+ result = QImage::Format_BGR888;
break;
case 16:
result = QImage::Format_RGB555;
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp
index 16d6c25b8b..4ab45337b0 100644
--- a/src/gui/image/qpnghandler.cpp
+++ b/src/gui/image/qpnghandler.cpp
@@ -1079,6 +1079,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int compression_i
if (color_type == PNG_COLOR_TYPE_RGB) {
switch (image.format()) {
case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
break;
case QImage::Format_RGBX8888:
case QImage::Format_RGBX64:
@@ -1131,6 +1132,7 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int compression_i
case QImage::Format_RGB32:
case QImage::Format_ARGB32:
case QImage::Format_RGB888:
+ case QImage::Format_BGR888:
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBX64:
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index ec52791010..616cca1422 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -535,13 +535,6 @@ Qt::MouseEventFlags QMouseEvent::flags() const
*/
/*!
- \fn QPointF QMouseEvent::posF() const
- \obsolete
-
- Use localPos() instead.
-*/
-
-/*!
\class QHoverEvent
\ingroup events
\inmodule QtGui
@@ -750,12 +743,14 @@ QHoverEvent::~QHoverEvent()
\l inverted always returns false.
*/
+#if QT_DEPRECATED_SINCE(5, 15)
/*!
\fn Qt::Orientation QWheelEvent::orientation() const
\obsolete
Use angleDelta() instead.
*/
+#endif
#if QT_CONFIG(wheelevent)
#if QT_DEPRECATED_SINCE(5, 15)
@@ -936,6 +931,7 @@ QWheelEvent::~QWheelEvent()
\endlist
*/
+#if QT_DEPRECATED_SINCE(5, 15)
/*!
\fn int QWheelEvent::delta() const
\obsolete
@@ -999,6 +995,7 @@ QWheelEvent::~QWheelEvent()
This function has been deprecated, use globalPosition() instead.
*/
+#endif
/*!
\fn Qt::ScrollPhase QWheelEvent::phase() const
@@ -1102,16 +1099,6 @@ QKeyEvent::~QKeyEvent()
}
/*!
- \fn QKeyEvent *QKeyEvent::createExtendedKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString& text, bool autorep, ushort count)
- \internal
-*/
-
-/*!
- \fn bool QKeyEvent::hasExtendedInfo() const
- \internal
-*/
-
-/*!
\fn quint32 QKeyEvent::nativeScanCode() const
\since 4.2
@@ -2539,7 +2526,7 @@ Qt::MouseButtons QTabletEvent::buttons() const
globalPos() can differ significantly from the current position
QCursor::pos().
- \sa globalX(), globalY(), hiResGlobalPos()
+ \sa globalX(), globalY()
*/
/*!
@@ -2584,15 +2571,6 @@ Qt::MouseButtons QTabletEvent::buttons() const
*/
/*!
- \fn const QPointF &QTabletEvent::hiResGlobalPos() const
-
- The high precision coordinates delivered from the tablet expressed.
- Sub pixeling information is in the fractional part of the QPointF.
-
- \sa globalPos(), hiResGlobalX(), hiResGlobalY()
-*/
-
-/*!
\fn qreal &QTabletEvent::hiResGlobalX() const
The high precision x position of the tablet device.
@@ -2674,10 +2652,10 @@ Qt::MouseButtons QTabletEvent::buttons() const
\sa Qt::NativeGestureType, QGestureEvent
*/
+#if QT_DEPRECATED_SINCE(5, 10)
/*!
\deprecated The QTouchDevice parameter is now required
*/
-#if QT_DEPRECATED_SINCE(5, 10)
QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QPointF &localPos, const QPointF &windowPos,
const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue)
: QInputEvent(QEvent::NativeGesture), mGestureType(type),
@@ -4290,18 +4268,6 @@ QWindowStateChangeEvent::~QWindowStateChangeEvent()
QGraphicsItem::acceptTouchEvents()
*/
-/*! \enum QTouchEvent::DeviceType
- \obsolete
-
- This enum represents the type of device that generated a QTouchEvent.
-
- This enum has been deprecated. Use QTouchDevice::DeviceType instead.
- \omitvalue TouchPad
- \omitvalue TouchScreen
-
- \sa QTouchDevice::DeviceType, QTouchDevice::type(), QTouchEvent::device()
-*/
-
/*!
Constructs a QTouchEvent with the given \a eventType, \a device, and
\a touchPoints. The \a touchPointStates and \a modifiers
@@ -4341,16 +4307,6 @@ QTouchEvent::~QTouchEvent()
This is typically a QWidget or a QQuickItem. May be 0 when no specific target is available.
*/
-/*! \fn QTouchEvent::DeviceType QTouchEvent::deviceType() const
- \obsolete
-
- Returns the touch device Type, which is of type \l {QTouchEvent::DeviceType} {DeviceType}.
-
- This function has been deprecated. Use QTouchDevice::type() instead.
-
- \sa QTouchDevice::type(), QTouchEvent::device()
-*/
-
/*! \fn QTouchEvent::TouchPoint::TouchPoint(TouchPoint &&other)
Move-constructs a TouchPoint instance, making it point to the same
diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp
index d9d5403cf3..9e393bc47a 100644
--- a/src/gui/opengl/qopengltextureuploader.cpp
+++ b/src/gui/opengl/qopengltextureuploader.cpp
@@ -65,6 +65,10 @@
#define GL_RGBA16 0x805B
#endif
+#ifndef GL_BGR
+#define GL_BGR 0x80E0
+#endif
+
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@@ -202,6 +206,20 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
pixelType = GL_UNSIGNED_BYTE;
targetFormat = QImage::Format_RGB888;
break;
+ case QImage::Format_BGR888:
+ if (isOpenGL12orBetter) {
+ externalFormat = GL_BGR;
+ internalFormat = GL_RGB;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = QImage::Format_BGR888;
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
+ funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
+ externalFormat = internalFormat = GL_RGB;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = QImage::Format_BGR888;
+ }
+ break;
case QImage::Format_RGBX8888:
case QImage::Format_RGBA8888:
case QImage::Format_RGBA8888_Premultiplied:
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 972cf387ff..fcf6488edd 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -135,23 +135,41 @@ gcc:equals(QT_GCC_MAJOR_VERSION, 5) {
NO_PCH_SOURCES += painting/qdrawhelper.cpp
}
-SSE2_SOURCES += painting/qdrawhelper_sse2.cpp
-SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp
-SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \
- painting/qimagescale_sse4.cpp
-ARCH_HASWELL_SOURCES += painting/qdrawhelper_avx2.cpp
+!android {
+ SSE2_SOURCES += painting/qdrawhelper_sse2.cpp
+ SSSE3_SOURCES += painting/qdrawhelper_ssse3.cpp
+ SSE4_1_SOURCES += painting/qdrawhelper_sse4.cpp \
+ painting/qimagescale_sse4.cpp
+ ARCH_HASWELL_SOURCES += painting/qdrawhelper_avx2.cpp
-NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp
-NEON_HEADERS += painting/qdrawhelper_neon_p.h
+ NEON_SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp
+ NEON_HEADERS += painting/qdrawhelper_neon_p.h
+}
!uikit:!win32:contains(QT_ARCH, "arm"): CONFIG += no_clang_integrated_as
-!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") {
+!android:!uikit:!win32:!integrity:!contains(QT_ARCH, "arm64") {
NEON_ASM += ../3rdparty/pixman/pixman-arm-neon-asm.S painting/qdrawhelper_neon_asm.S
DEFINES += ENABLE_PIXMAN_DRAWHELPERS
}
-MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp
-MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h
-MIPS_DSP_ASM += painting/qdrawhelper_mips_dsp_asm.S
-MIPS_DSPR2_ASM += painting/qdrawhelper_mips_dspr2_asm.S
+!android {
+ MIPS_DSP_SOURCES += painting/qdrawhelper_mips_dsp.cpp
+ MIPS_DSP_HEADERS += painting/qdrawhelper_mips_dsp_p.h painting/qt_mips_asm_dsp_p.h
+ MIPS_DSP_ASM += painting/qdrawhelper_mips_dsp_asm.S
+ MIPS_DSPR2_ASM += painting/qdrawhelper_mips_dspr2_asm.S
+} else {
+ # see https://developer.android.com/ndk/guides/abis
+ x86 | x86_64 {
+ DEFINES += QT_COMPILER_SUPPORTS_SSE2 QT_COMPILER_SUPPORTS_SSE3 QT_COMPILER_SUPPORTS_SSSE3
+ SOURCES += painting/qdrawhelper_sse2.cpp painting/qdrawhelper_ssse3.cpp
+ }
+ x86_64 {
+ DEFINES += QT_COMPILER_SUPPORTS_SSE4_1 QT_COMPILER_SUPPORTS_SSE4_2
+ SOURCES += painting/qdrawhelper_sse4.cpp painting/qimagescale_sse4.cpp
+ }
+ arm64-v8a {
+ SOURCES += painting/qdrawhelper_neon.cpp painting/qimagescale_neon.cpp
+ HEADERS += painting/qdrawhelper_neon_p.h
+ }
+}
include($$PWD/../../3rdparty/zlib_dependency.pri)
diff --git a/src/gui/painting/qbezier.cpp b/src/gui/painting/qbezier.cpp
index daf19fffe1..9861fffff3 100644
--- a/src/gui/painting/qbezier.cpp
+++ b/src/gui/painting/qbezier.cpp
@@ -47,6 +47,8 @@
#include <private/qnumeric_p.h>
+#include <tuple> // for std::tie()
+
QT_BEGIN_NAMESPACE
//#define QDEBUG_BEZIER
@@ -128,7 +130,7 @@ void QBezier::addToPolygon(QPolygonF *polygon, qreal bezier_flattening_threshold
--lvl;
} else {
// split, second half of the polygon goes lower into the stack
- b->split(b+1, b);
+ std::tie(b[1], b[0]) = b->split();
lvl[1] = --lvl[0];
++b;
++lvl;
@@ -166,7 +168,7 @@ void QBezier::addToPolygon(QDataBuffer<QPointF> &polygon, qreal bezier_flattenin
--lvl;
} else {
// split, second half of the polygon goes lower into the stack
- b->split(b+1, b);
+ std::tie(b[1], b[0]) = b->split();
lvl[1] = --lvl[0];
++b;
++lvl;
@@ -422,7 +424,7 @@ redo:
o += 2;
--b;
} else {
- b->split(b+1, b);
+ std::tie(b[1], b[0]) = b->split();
++b;
}
}
@@ -464,8 +466,6 @@ qreal QBezier::length(qreal error) const
void QBezier::addIfClose(qreal *length, qreal error) const
{
- QBezier left, right; /* bez poly splits */
-
qreal len = qreal(0.0); /* arc length */
qreal chord; /* chord length */
@@ -476,9 +476,9 @@ void QBezier::addIfClose(qreal *length, qreal error) const
chord = QLineF(QPointF(x1, y1),QPointF(x4, y4)).length();
if((len-chord) > error) {
- split(&left, &right); /* split in two */
- left.addIfClose(length, error); /* try left side */
- right.addIfClose(length, error); /* try right side */
+ const auto halves = split(); /* split in two */
+ halves.first.addIfClose(length, error); /* try left side */
+ halves.second.addIfClose(length, error); /* try right side */
return;
}
diff --git a/src/gui/painting/qbezier_p.h b/src/gui/painting/qbezier_p.h
index f88e3b35b3..1c49f82416 100644
--- a/src/gui/painting/qbezier_p.h
+++ b/src/gui/painting/qbezier_p.h
@@ -107,7 +107,7 @@ public:
inline QLineF endTangent() const;
inline void parameterSplitLeft(qreal t, QBezier *left);
- inline void split(QBezier *firstHalf, QBezier *secondHalf) const;
+ inline std::pair<QBezier, QBezier> split() const;
int shifted(QBezier *curveSegments, int maxSegmets,
qreal offset, float threshold) const;
@@ -223,28 +223,21 @@ inline QPointF QBezier::secondDerivedAt(qreal t) const
a * y1 + b * y2 + c * y3 + d * y4);
}
-inline void QBezier::split(QBezier *firstHalf, QBezier *secondHalf) const
+std::pair<QBezier, QBezier> QBezier::split() const
{
- Q_ASSERT(firstHalf);
- Q_ASSERT(secondHalf);
-
- qreal c = (x2 + x3)*.5;
- firstHalf->x2 = (x1 + x2)*.5;
- secondHalf->x3 = (x3 + x4)*.5;
- firstHalf->x1 = x1;
- secondHalf->x4 = x4;
- firstHalf->x3 = (firstHalf->x2 + c)*.5;
- secondHalf->x2 = (secondHalf->x3 + c)*.5;
- firstHalf->x4 = secondHalf->x1 = (firstHalf->x3 + secondHalf->x2)*.5;
-
- c = (y2 + y3)/2;
- firstHalf->y2 = (y1 + y2)*.5;
- secondHalf->y3 = (y3 + y4)*.5;
- firstHalf->y1 = y1;
- secondHalf->y4 = y4;
- firstHalf->y3 = (firstHalf->y2 + c)*.5;
- secondHalf->y2 = (secondHalf->y3 + c)*.5;
- firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2)*.5;
+ const auto mid = [](QPointF lhs, QPointF rhs) { return (lhs + rhs) * .5; };
+
+ const QPointF mid_12 = mid(pt1(), pt2());
+ const QPointF mid_23 = mid(pt2(), pt3());
+ const QPointF mid_34 = mid(pt3(), pt4());
+ const QPointF mid_12_23 = mid(mid_12, mid_23);
+ const QPointF mid_23_34 = mid(mid_23, mid_34);
+ const QPointF mid_12_23__23_34 = mid(mid_12_23, mid_23_34);
+
+ return {
+ fromPoints(pt1(), mid_12, mid_12_23, mid_12_23__23_34),
+ fromPoints(mid_12_23__23_34, mid_23_34, mid_34, pt4()),
+ };
}
inline void QBezier::parameterSplitLeft(qreal t, QBezier *left)
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index 6cbc30e79a..8780cce223 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -147,6 +147,7 @@ static bool get_hex_rgb(const QChar *str, size_t len, QRgba64 *rgb)
#endif
#define rgb(r,g,b) (0xff000000 | (r << 16) | (g << 8) | b)
+// keep this is in sync with QColorConstants
static const struct RGBData {
const char name[21];
uint value;
@@ -475,25 +476,35 @@ static QStringList get_colornames()
\section1 Predefined Colors
- There are 20 predefined QColors described by the Qt::GlobalColor enum,
- including black, white, primary and secondary colors, darker versions
- of these colors and three shades of gray. QColor also recognizes a
- variety of color names; the static colorNames() function returns a
- QStringList color names that QColor knows about.
+ There are 20 predefined QColor objects in the \c{QColorConstants}
+ namespace, including black, white, primary and secondary colors,
+ darker versions of these colors, and three shades of gray.
+ Furthermore, the \c{QColorConstants::Svg} namespace defines QColor
+ objects for the standard \l{https://www.w3.org/TR/SVG11/types.html#ColorKeywords}{SVG color keyword names}.
\image qt-colors.png Qt Colors
- Additionally, the Qt::color0, Qt::color1 and Qt::transparent colors
- are used for special purposes.
+ The \c{QColorConstants::Color0}, \c{QColorConstants::Color1} and
+ \c{QColorConstants::Transparent} colors are used for special
+ purposes.
- Qt::color0 (zero pixel value) and Qt::color1 (non-zero pixel value)
- are special colors for drawing in QBitmaps. Painting with Qt::color0
- sets the bitmap bits to 0 (transparent; i.e., background), and painting
- with Qt::color1 sets the bits to 1 (opaque; i.e., foreground).
+ \c{QColorConstants::Color0} (zero pixel value) and
+ \c{QColorConstants::Color1} (non-zero pixel value) are special
+ colors for drawing in QBitmaps. Painting with
+ \c{QColorConstants::Color0} sets the bitmap bits to 0 (transparent;
+ i.e., background), and painting with c{QColorConstants::Color1}
+ sets the bits to 1 (opaque; i.e., foreground).
- Qt::transparent is used to indicate a transparent pixel. When painting
- with this value, a pixel value will be used that is appropriate for the
- underlying pixel format in use.
+ \c{QColorConstants::Transparent} is used to indicate a transparent
+ pixel. When painting with this value, a pixel value will be used
+ that is appropriate for the underlying pixel format in use.
+
+ For historical reasons, the 20 predefined colors are also available
+ in the Qt::GlobalColor enumeration.
+
+ Finally, QColor recognizes a variety of color names (as strings);
+ the static colorNames() function returns a QStringList color names
+ that QColor knows about.
\section1 The Extended RGB Color Model
@@ -586,7 +597,7 @@ static QStringList get_colornames()
alpha-channel to feature \l {QColor#Alpha-Blended
Drawing}{alpha-blended drawing}.
- \sa QPalette, QBrush
+ \sa QPalette, QBrush, QColorConstants
*/
#define QCOLOR_INT_RANGE_CHECK(fn, var) \
@@ -886,7 +897,8 @@ QString QColor::name(NameFormat format) const
\li #AARRGGBB (Since 5.2)
\li #RRRGGGBBB
\li #RRRRGGGGBBBB
- \li A name from the list of colors defined in the list of \l{http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG color keyword names}
+ \li A name from the list of colors defined in the list of
+ \l{https://www.w3.org/TR/SVG11/types.html#ColorKeywords}{SVG color keyword names}
provided by the World Wide Web Consortium; for example, "steelblue" or "gainsboro".
These color names work on all platforms. Note that these color names are \e not the
same as defined by the Qt::GlobalColor enums, e.g. "green" and Qt::green does not
@@ -3249,4 +3261,41 @@ const uint qt_inv_premul_factor[256] = {
\sa QColor::rgb(), QColor::rgba()
*/
+/*!
+ \namespace QColorConstants
+ \inmodule QtGui
+
+ \brief The QColorConstants namespace contains QColor predefined constants.
+
+ These constants are usable everywhere a QColor object is expected:
+
+ \code
+ painter.setBrush(QColorConstants::Svg::lightblue);
+ \endcode
+
+ Their usage is much cheaper than e.g. passing a string to QColor's constructor,
+ as they don't require any parsing of the string, and always result in a valid
+ QColor object:
+
+ \badcode
+ object.setColor(QColor("lightblue")); // expensive
+ \endcode
+
+ \section1 Qt Colors
+
+ The following colors are defined in the \c{QColorConstants} namespace:
+
+ \include qt-colors.qdocinc
+
+ \section1 SVG Colors
+
+ The following table lists the available
+ \l {http://www.w3.org/TR/SVG/types.html#ColorKeywords}{SVG colors}.
+ They are available in the \c{QColorConstants::Svg} inner namespace.
+
+ \include svg-colors.qdocinc
+
+ \sa QColor, Qt::GlobalColor
+*/
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h
index 723b9fce73..f0d7dd23ad 100644
--- a/src/gui/painting/qcolor.h
+++ b/src/gui/painting/qcolor.h
@@ -309,6 +309,12 @@ private:
friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QColor &);
friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QColor &);
#endif
+
+#ifdef Q_COMPILER_UNIFORM_INIT
+public: // can't give friendship to a namespace, so it needs to be public
+ Q_DECL_CONSTEXPR explicit QColor(Spec spec, ushort a1, ushort a2, ushort a3, ushort a4, ushort a5=0) noexcept
+ : cspec(spec), ct(a1, a2, a3, a4, a5) {}
+#endif // Q_COMPILER_UNIFORM_INIT
};
Q_DECLARE_TYPEINFO(QColor, QT_VERSION >= QT_VERSION_CHECK(6,0,0) ? Q_MOVABLE_TYPE : Q_RELOCATABLE_TYPE);
@@ -326,6 +332,187 @@ inline QColor::QColor(const QString& aname)
inline bool QColor::isValid() const noexcept
{ return cspec != Invalid; }
+// define these namespaces even if the contents are ifdef'd out
+namespace QColorConstants
+{
+namespace Svg {}
+
+#if defined(Q_COMPILER_CONSTEXPR) & defined(Q_COMPILER_UNIFORM_INIT)
+ // Qt::GlobalColor names
+ constexpr Q_DECL_UNUSED QColor Color0 {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor Color1 {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor Black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor White {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor DarkGray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor Gray {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0xa0 * 0x101, 0xa4 * 0x101};
+ constexpr Q_DECL_UNUSED QColor LightGray {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor Red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor Green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor Blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor Cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor Magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor Yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor DarkRed {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor DarkGreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor DarkBlue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor DarkCyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor DarkMagenta {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor DarkYellow {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor Transparent {QColor::Rgb, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+
+ // SVG names supported by QColor (see qcolor.cpp).
+namespace Svg {
+ constexpr Q_DECL_UNUSED QColor aliceblue {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xf8 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor antiquewhite {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xeb * 0x101, 0xd7 * 0x101};
+ constexpr Q_DECL_UNUSED QColor aqua {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor aquamarine {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0xd4 * 0x101};
+ constexpr Q_DECL_UNUSED QColor azure {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor beige {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xdc * 0x101};
+ constexpr Q_DECL_UNUSED QColor bisque {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xc4 * 0x101};
+ constexpr Q_DECL_UNUSED QColor black {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor blanchedalmond {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xeb * 0x101, 0xcd * 0x101};
+ constexpr Q_DECL_UNUSED QColor blue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor blueviolet {QColor::Rgb, 0xff * 0x101, 0x8a * 0x101, 0x2b * 0x101, 0xe2 * 0x101};
+ constexpr Q_DECL_UNUSED QColor brown {QColor::Rgb, 0xff * 0x101, 0xa5 * 0x101, 0x2a * 0x101, 0x2a * 0x101};
+ constexpr Q_DECL_UNUSED QColor burlywood {QColor::Rgb, 0xff * 0x101, 0xde * 0x101, 0xb8 * 0x101, 0x87 * 0x101};
+ constexpr Q_DECL_UNUSED QColor cadetblue {QColor::Rgb, 0xff * 0x101, 0x5f * 0x101, 0x9e * 0x101, 0xa0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor chartreuse {QColor::Rgb, 0xff * 0x101, 0x7f * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor chocolate {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0x69 * 0x101, 0x1e * 0x101};
+ constexpr Q_DECL_UNUSED QColor coral {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x7f * 0x101, 0x50 * 0x101};
+ constexpr Q_DECL_UNUSED QColor cornflowerblue {QColor::Rgb, 0xff * 0x101, 0x64 * 0x101, 0x95 * 0x101, 0xed * 0x101};
+ constexpr Q_DECL_UNUSED QColor cornsilk {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf8 * 0x101, 0xdc * 0x101};
+ constexpr Q_DECL_UNUSED QColor crimson {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0x14 * 0x101, 0x3c * 0x101};
+ constexpr Q_DECL_UNUSED QColor cyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x8b * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkcyan {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x8b * 0x101, 0x8b * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkgoldenrod {QColor::Rgb, 0xff * 0x101, 0xb8 * 0x101, 0x86 * 0x101, 0x0b * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkgray {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x64 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkgrey {QColor::Rgb, 0xff * 0x101, 0xa9 * 0x101, 0xa9 * 0x101, 0xa9 * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkkhaki {QColor::Rgb, 0xff * 0x101, 0xbd * 0x101, 0xb7 * 0x101, 0x6b * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkmagenta {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x8b * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkolivegreen {QColor::Rgb, 0xff * 0x101, 0x55 * 0x101, 0x6b * 0x101, 0x2f * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkorange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x8c * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkorchid {QColor::Rgb, 0xff * 0x101, 0x99 * 0x101, 0x32 * 0x101, 0xcc * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkred {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor darksalmon {QColor::Rgb, 0xff * 0x101, 0xe9 * 0x101, 0x96 * 0x101, 0x7a * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkseagreen {QColor::Rgb, 0xff * 0x101, 0x8f * 0x101, 0xbc * 0x101, 0x8f * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkslateblue {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0x3d * 0x101, 0x8b * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkslategray {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkslategrey {QColor::Rgb, 0xff * 0x101, 0x2f * 0x101, 0x4f * 0x101, 0x4f * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkturquoise {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xce * 0x101, 0xd1 * 0x101};
+ constexpr Q_DECL_UNUSED QColor darkviolet {QColor::Rgb, 0xff * 0x101, 0x94 * 0x101, 0x00 * 0x101, 0xd3 * 0x101};
+ constexpr Q_DECL_UNUSED QColor deeppink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x14 * 0x101, 0x93 * 0x101};
+ constexpr Q_DECL_UNUSED QColor deepskyblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xbf * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor dimgray {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101};
+ constexpr Q_DECL_UNUSED QColor dimgrey {QColor::Rgb, 0xff * 0x101, 0x69 * 0x101, 0x69 * 0x101, 0x69 * 0x101};
+ constexpr Q_DECL_UNUSED QColor dodgerblue {QColor::Rgb, 0xff * 0x101, 0x1e * 0x101, 0x90 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor firebrick {QColor::Rgb, 0xff * 0x101, 0xb2 * 0x101, 0x22 * 0x101, 0x22 * 0x101};
+ constexpr Q_DECL_UNUSED QColor floralwhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor forestgreen {QColor::Rgb, 0xff * 0x101, 0x22 * 0x101, 0x8b * 0x101, 0x22 * 0x101};
+ constexpr Q_DECL_UNUSED QColor fuchsia {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor gainsboro {QColor::Rgb, 0xff * 0x101, 0xdc * 0x101, 0xdc * 0x101, 0xdc * 0x101};
+ constexpr Q_DECL_UNUSED QColor ghostwhite {QColor::Rgb, 0xff * 0x101, 0xf8 * 0x101, 0xf8 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor gold {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xd7 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor goldenrod {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0xa5 * 0x101, 0x20 * 0x101};
+ constexpr Q_DECL_UNUSED QColor gray {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor green {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor greenyellow {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xff * 0x101, 0x2f * 0x101};
+ constexpr Q_DECL_UNUSED QColor grey {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor honeydew {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xff * 0x101, 0xf0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor hotpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x69 * 0x101, 0xb4 * 0x101};
+ constexpr Q_DECL_UNUSED QColor indianred {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x5c * 0x101, 0x5c * 0x101};
+ constexpr Q_DECL_UNUSED QColor indigo {QColor::Rgb, 0xff * 0x101, 0x4b * 0x101, 0x00 * 0x101, 0x82 * 0x101};
+ constexpr Q_DECL_UNUSED QColor ivory {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor khaki {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0xe6 * 0x101, 0x8c * 0x101};
+ constexpr Q_DECL_UNUSED QColor lavender {QColor::Rgb, 0xff * 0x101, 0xe6 * 0x101, 0xe6 * 0x101, 0xfa * 0x101};
+ constexpr Q_DECL_UNUSED QColor lavenderblush {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf0 * 0x101, 0xf5 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lawngreen {QColor::Rgb, 0xff * 0x101, 0x7c * 0x101, 0xfc * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lemonchiffon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xcd * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightblue {QColor::Rgb, 0xff * 0x101, 0xad * 0x101, 0xd8 * 0x101, 0xe6 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightcoral {QColor::Rgb, 0xff * 0x101, 0xf0 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightcyan {QColor::Rgb, 0xff * 0x101, 0xe0 * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightgoldenrodyellow {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101, 0xd2 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightgray {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightgreen {QColor::Rgb, 0xff * 0x101, 0x90 * 0x101, 0xee * 0x101, 0x90 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightgrey {QColor::Rgb, 0xff * 0x101, 0xd3 * 0x101, 0xd3 * 0x101, 0xd3 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightpink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xb6 * 0x101, 0xc1 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightsalmon {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa0 * 0x101, 0x7a * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightseagreen {QColor::Rgb, 0xff * 0x101, 0x20 * 0x101, 0xb2 * 0x101, 0xaa * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightskyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xfa * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightslategray {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightslategrey {QColor::Rgb, 0xff * 0x101, 0x77 * 0x101, 0x88 * 0x101, 0x99 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightsteelblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xc4 * 0x101, 0xde * 0x101};
+ constexpr Q_DECL_UNUSED QColor lightyellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xe0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor lime {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor limegreen {QColor::Rgb, 0xff * 0x101, 0x32 * 0x101, 0xcd * 0x101, 0x32 * 0x101};
+ constexpr Q_DECL_UNUSED QColor linen {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0xf0 * 0x101, 0xe6 * 0x101};
+ constexpr Q_DECL_UNUSED QColor magenta {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor maroon {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumaquamarine {QColor::Rgb, 0xff * 0x101, 0x66 * 0x101, 0xcd * 0x101, 0xaa * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumblue {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0xcd * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumorchid {QColor::Rgb, 0xff * 0x101, 0xba * 0x101, 0x55 * 0x101, 0xd3 * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumpurple {QColor::Rgb, 0xff * 0x101, 0x93 * 0x101, 0x70 * 0x101, 0xdb * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumseagreen {QColor::Rgb, 0xff * 0x101, 0x3c * 0x101, 0xb3 * 0x101, 0x71 * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumslateblue {QColor::Rgb, 0xff * 0x101, 0x7b * 0x101, 0x68 * 0x101, 0xee * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumspringgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xfa * 0x101, 0x9a * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumturquoise {QColor::Rgb, 0xff * 0x101, 0x48 * 0x101, 0xd1 * 0x101, 0xcc * 0x101};
+ constexpr Q_DECL_UNUSED QColor mediumvioletred {QColor::Rgb, 0xff * 0x101, 0xc7 * 0x101, 0x15 * 0x101, 0x85 * 0x101};
+ constexpr Q_DECL_UNUSED QColor midnightblue {QColor::Rgb, 0xff * 0x101, 0x19 * 0x101, 0x19 * 0x101, 0x70 * 0x101};
+ constexpr Q_DECL_UNUSED QColor mintcream {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xff * 0x101, 0xfa * 0x101};
+ constexpr Q_DECL_UNUSED QColor mistyrose {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xe1 * 0x101};
+ constexpr Q_DECL_UNUSED QColor moccasin {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xe4 * 0x101, 0xb5 * 0x101};
+ constexpr Q_DECL_UNUSED QColor navajowhite {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xde * 0x101, 0xad * 0x101};
+ constexpr Q_DECL_UNUSED QColor navy {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor oldlace {QColor::Rgb, 0xff * 0x101, 0xfd * 0x101, 0xf5 * 0x101, 0xe6 * 0x101};
+ constexpr Q_DECL_UNUSED QColor olive {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x80 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor olivedrab {QColor::Rgb, 0xff * 0x101, 0x6b * 0x101, 0x8e * 0x101, 0x23 * 0x101};
+ constexpr Q_DECL_UNUSED QColor orange {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xa5 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor orangered {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x45 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor orchid {QColor::Rgb, 0xff * 0x101, 0xda * 0x101, 0x70 * 0x101, 0xd6 * 0x101};
+ constexpr Q_DECL_UNUSED QColor palegoldenrod {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0xe8 * 0x101, 0xaa * 0x101};
+ constexpr Q_DECL_UNUSED QColor palegreen {QColor::Rgb, 0xff * 0x101, 0x98 * 0x101, 0xfb * 0x101, 0x98 * 0x101};
+ constexpr Q_DECL_UNUSED QColor paleturquoise {QColor::Rgb, 0xff * 0x101, 0xaf * 0x101, 0xee * 0x101, 0xee * 0x101};
+ constexpr Q_DECL_UNUSED QColor palevioletred {QColor::Rgb, 0xff * 0x101, 0xdb * 0x101, 0x70 * 0x101, 0x93 * 0x101};
+ constexpr Q_DECL_UNUSED QColor papayawhip {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xef * 0x101, 0xd5 * 0x101};
+ constexpr Q_DECL_UNUSED QColor peachpuff {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xda * 0x101, 0xb9 * 0x101};
+ constexpr Q_DECL_UNUSED QColor peru {QColor::Rgb, 0xff * 0x101, 0xcd * 0x101, 0x85 * 0x101, 0x3f * 0x101};
+ constexpr Q_DECL_UNUSED QColor pink {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xc0 * 0x101, 0xcb * 0x101};
+ constexpr Q_DECL_UNUSED QColor plum {QColor::Rgb, 0xff * 0x101, 0xdd * 0x101, 0xa0 * 0x101, 0xdd * 0x101};
+ constexpr Q_DECL_UNUSED QColor powderblue {QColor::Rgb, 0xff * 0x101, 0xb0 * 0x101, 0xe0 * 0x101, 0xe6 * 0x101};
+ constexpr Q_DECL_UNUSED QColor purple {QColor::Rgb, 0xff * 0x101, 0x80 * 0x101, 0x00 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor red {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor rosybrown {QColor::Rgb, 0xff * 0x101, 0xbc * 0x101, 0x8f * 0x101, 0x8f * 0x101};
+ constexpr Q_DECL_UNUSED QColor royalblue {QColor::Rgb, 0xff * 0x101, 0x41 * 0x101, 0x69 * 0x101, 0xe1 * 0x101};
+ constexpr Q_DECL_UNUSED QColor saddlebrown {QColor::Rgb, 0xff * 0x101, 0x8b * 0x101, 0x45 * 0x101, 0x13 * 0x101};
+ constexpr Q_DECL_UNUSED QColor salmon {QColor::Rgb, 0xff * 0x101, 0xfa * 0x101, 0x80 * 0x101, 0x72 * 0x101};
+ constexpr Q_DECL_UNUSED QColor sandybrown {QColor::Rgb, 0xff * 0x101, 0xf4 * 0x101, 0xa4 * 0x101, 0x60 * 0x101};
+ constexpr Q_DECL_UNUSED QColor seagreen {QColor::Rgb, 0xff * 0x101, 0x2e * 0x101, 0x8b * 0x101, 0x57 * 0x101};
+ constexpr Q_DECL_UNUSED QColor seashell {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xf5 * 0x101, 0xee * 0x101};
+ constexpr Q_DECL_UNUSED QColor sienna {QColor::Rgb, 0xff * 0x101, 0xa0 * 0x101, 0x52 * 0x101, 0x2d * 0x101};
+ constexpr Q_DECL_UNUSED QColor silver {QColor::Rgb, 0xff * 0x101, 0xc0 * 0x101, 0xc0 * 0x101, 0xc0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor skyblue {QColor::Rgb, 0xff * 0x101, 0x87 * 0x101, 0xce * 0x101, 0xeb * 0x101};
+ constexpr Q_DECL_UNUSED QColor slateblue {QColor::Rgb, 0xff * 0x101, 0x6a * 0x101, 0x5a * 0x101, 0xcd * 0x101};
+ constexpr Q_DECL_UNUSED QColor slategray {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101};
+ constexpr Q_DECL_UNUSED QColor slategrey {QColor::Rgb, 0xff * 0x101, 0x70 * 0x101, 0x80 * 0x101, 0x90 * 0x101};
+ constexpr Q_DECL_UNUSED QColor snow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xfa * 0x101, 0xfa * 0x101};
+ constexpr Q_DECL_UNUSED QColor springgreen {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0xff * 0x101, 0x7f * 0x101};
+ constexpr Q_DECL_UNUSED QColor steelblue {QColor::Rgb, 0xff * 0x101, 0x46 * 0x101, 0x82 * 0x101, 0xb4 * 0x101};
+ constexpr Q_DECL_UNUSED QColor tan {QColor::Rgb, 0xff * 0x101, 0xd2 * 0x101, 0xb4 * 0x101, 0x8c * 0x101};
+ constexpr Q_DECL_UNUSED QColor teal {QColor::Rgb, 0xff * 0x101, 0x00 * 0x101, 0x80 * 0x101, 0x80 * 0x101};
+ constexpr Q_DECL_UNUSED QColor thistle {QColor::Rgb, 0xff * 0x101, 0xd8 * 0x101, 0xbf * 0x101, 0xd8 * 0x101};
+ constexpr Q_DECL_UNUSED QColor tomato {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0x63 * 0x101, 0x47 * 0x101};
+ constexpr Q_DECL_UNUSED QColor turquoise {QColor::Rgb, 0xff * 0x101, 0x40 * 0x101, 0xe0 * 0x101, 0xd0 * 0x101};
+ constexpr Q_DECL_UNUSED QColor violet {QColor::Rgb, 0xff * 0x101, 0xee * 0x101, 0x82 * 0x101, 0xee * 0x101};
+ constexpr Q_DECL_UNUSED QColor wheat {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xde * 0x101, 0xb3 * 0x101};
+ constexpr Q_DECL_UNUSED QColor white {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101};
+ constexpr Q_DECL_UNUSED QColor whitesmoke {QColor::Rgb, 0xff * 0x101, 0xf5 * 0x101, 0xf5 * 0x101, 0xf5 * 0x101};
+ constexpr Q_DECL_UNUSED QColor yellow {QColor::Rgb, 0xff * 0x101, 0xff * 0x101, 0xff * 0x101, 0x00 * 0x101};
+ constexpr Q_DECL_UNUSED QColor yellowgreen {QColor::Rgb, 0xff * 0x101, 0x9a * 0x101, 0xcd * 0x101, 0x32 * 0x101};
+} // namespace Svg
+#endif // Q_COMPILER_CONSTEXPR && Q_COMPILER_UNIFORM_INIT
+} // namespace QColorLiterals
+
QT_END_NAMESPACE
#endif // QCOLOR_H
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 55d69221f5..c17bf2ddfd 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -88,6 +88,7 @@ template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB444>() { return 4; }
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB555>() { return 5; }
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB666>() { return 6; }
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_RGB888>() { return 8; }
+template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_BGR888>() { return 8; }
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
template<> Q_DECL_CONSTEXPR uint redWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
@@ -101,6 +102,7 @@ template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB444>() { return 8;
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB555>() { return 10; }
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB666>() { return 12; }
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_RGB888>() { return 16; }
+template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_BGR888>() { return 0; }
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB4444_Premultiplied>() { return 8; }
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8555_Premultiplied>() { return 18; }
template<> Q_DECL_CONSTEXPR uint redShift<QImage::Format_ARGB8565_Premultiplied>() { return 19; }
@@ -119,6 +121,7 @@ template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB444>() { return 4;
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB555>() { return 5; }
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB666>() { return 6; }
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_RGB888>() { return 8; }
+template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_BGR888>() { return 8; }
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
template<> Q_DECL_CONSTEXPR uint greenWidth<QImage::Format_ARGB8565_Premultiplied>() { return 6; }
@@ -132,6 +135,7 @@ template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB444>() { return 4;
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB555>() { return 5; }
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB666>() { return 6; }
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_RGB888>() { return 8; }
+template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_BGR888>() { return 8; }
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8555_Premultiplied>() { return 13; }
template<> Q_DECL_CONSTEXPR uint greenShift<QImage::Format_ARGB8565_Premultiplied>() { return 13; }
@@ -150,6 +154,7 @@ template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB444>() { return 4;
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB555>() { return 5; }
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB666>() { return 6; }
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_RGB888>() { return 8; }
+template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_BGR888>() { return 8; }
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8555_Premultiplied>() { return 5; }
template<> Q_DECL_CONSTEXPR uint blueWidth<QImage::Format_ARGB8565_Premultiplied>() { return 5; }
@@ -163,6 +168,7 @@ template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB444>() { return 0;
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB555>() { return 0; }
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB666>() { return 0; }
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_RGB888>() { return 0; }
+template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_BGR888>() { return 16; }
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB4444_Premultiplied>() { return 0; }
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
template<> Q_DECL_CONSTEXPR uint blueShift<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
@@ -181,6 +187,7 @@ template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB444>() { return 0;
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB555>() { return 0; }
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB666>() { return 0; }
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_RGB888>() { return 0; }
+template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_BGR888>() { return 0; }
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB4444_Premultiplied>() { return 4; }
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8555_Premultiplied>() { return 8; }
template<> Q_DECL_CONSTEXPR uint alphaWidth<QImage::Format_ARGB8565_Premultiplied>() { return 8; }
@@ -194,6 +201,7 @@ template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB444>() { return 0;
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB555>() { return 0; }
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB666>() { return 0; }
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_RGB888>() { return 0; }
+template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_BGR888>() { return 0; }
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB4444_Premultiplied>() { return 12; }
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8555_Premultiplied>() { return 0; }
template<> Q_DECL_CONSTEXPR uint alphaShift<QImage::Format_ARGB8565_Premultiplied>() { return 0; }
@@ -214,6 +222,7 @@ template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB444>() { r
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB555>() { return QPixelLayout::BPP16; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB666>() { return QPixelLayout::BPP24; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_RGB888>() { return QPixelLayout::BPP24; }
+template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_BGR888>() { return QPixelLayout::BPP24; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB4444_Premultiplied>() { return QPixelLayout::BPP16; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8555_Premultiplied>() { return QPixelLayout::BPP24; }
template<> constexpr QPixelLayout::BPP bitsPerPixel<QImage::Format_ARGB8565_Premultiplied>() { return QPixelLayout::BPP24; }
@@ -1528,7 +1537,8 @@ QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
{ false, false, QPixelLayout::BPP16, nullptr,
convertGrayscale16ToRGB32, convertGrayscale16ToRGBA64,
fetchGrayscale16ToRGB32, fetchGrayscale16ToRGBA64,
- storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 } // Format_Grayscale16
+ storeGrayscale16FromARGB32PM, storeGrayscale16FromRGB32 }, // Format_Grayscale16
+ pixelLayoutRGB<QImage::Format_BGR888>(),
};
Q_STATIC_ASSERT(sizeof(qPixelLayouts) / sizeof(*qPixelLayouts) == QImage::NImageFormats);
@@ -1643,7 +1653,8 @@ ConvertAndStorePixelsFunc64 qStoreFromRGBA64PM[QImage::NImageFormats] = {
storeRGBX64FromRGBA64PM,
storeRGBA64FromRGBA64PM,
storeRGBA64PMFromRGBA64PM,
- storeGray16FromRGBA64PM
+ storeGray16FromRGBA64PM,
+ storeGenericFromRGBA64PM<QImage::Format_BGR888>,
};
/*
@@ -1732,6 +1743,7 @@ static DestFetchProc destFetchProc[QImage::NImageFormats] =
destFetch, // Format_RGBA64
destFetch, // Format_RGBA64_Premultiplied
destFetch, // Format_Grayscale16
+ destFetch, // Format_BGR888
};
#if QT_CONFIG(raster_64bit)
@@ -1782,6 +1794,7 @@ static DestFetchProc64 destFetchProc64[QImage::NImageFormats] =
destFetch64, // Format_RGBA64
destFetchRGB64, // Format_RGBA64_Premultiplied
destFetch64, // Format_Grayscale16
+ destFetch64, // Format_BGR888
};
#endif
@@ -1922,6 +1935,7 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] =
destStore, // Format_RGBA64
destStore, // Format_RGBA64_Premultiplied
destStore, // Format_Grayscale16
+ destStore, // Format_BGR888
};
#if QT_CONFIG(raster_64bit)
@@ -1971,6 +1985,7 @@ static DestStoreProc64 destStoreProc64[QImage::NImageFormats] =
destStore64RGBA64, // Format_RGBA64
0, // Format_RGBA64_Premultiplied
destStore64, // Format_Grayscale16
+ destStore64, // Format_BGR888
};
#endif
@@ -3922,6 +3937,7 @@ static SourceFetchProc sourceFetchUntransformed[QImage::NImageFormats] = {
fetchUntransformed, // RGBA64
fetchUntransformed, // RGBA64_Premultiplied
fetchUntransformed, // Grayscale16
+ fetchUntransformed, // BGR888
};
static const SourceFetchProc sourceFetchGeneric[NBlendTypes] = {
@@ -6589,6 +6605,14 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
qt_alphargbblit_generic,
qt_rectfill_quint16
},
+ // Format_BGR888
+ {
+ blend_color_generic,
+ 0,
+ qt_alphamapblit_generic,
+ qt_alphargbblit_generic,
+ qt_rectfill_quint24
+ },
};
#if !defined(__SSE2__)
diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp
index b1d1f30800..1fb37ece56 100644
--- a/src/gui/painting/qpainterpath.cpp
+++ b/src/gui/painting/qpainterpath.cpp
@@ -1855,10 +1855,9 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt,
}
// split curve and try again...
- QBezier first_half, second_half;
- bezier.split(&first_half, &second_half);
- qt_painterpath_isect_curve(first_half, pt, winding, depth + 1);
- qt_painterpath_isect_curve(second_half, pt, winding, depth + 1);
+ const auto halves = bezier.split();
+ qt_painterpath_isect_curve(halves.first, pt, winding, depth + 1);
+ qt_painterpath_isect_curve(halves.second, pt, winding, depth + 1);
}
}
@@ -2013,10 +2012,9 @@ static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1,
if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
return true;
- QBezier first_half, second_half;
- bezier.split(&first_half, &second_half);
- if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1)
- || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1))
+ const auto halves = bezier.split();
+ if (qt_isect_curve_horizontal(halves.first, y, x1, x2, depth + 1)
+ || qt_isect_curve_horizontal(halves.second, y, x1, x2, depth + 1))
return true;
}
return false;
@@ -2032,10 +2030,9 @@ static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qr
if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound))
return true;
- QBezier first_half, second_half;
- bezier.split(&first_half, &second_half);
- if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1)
- || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1))
+ const auto halves = bezier.split();
+ if (qt_isect_curve_vertical(halves.first, x, y1, y2, depth + 1)
+ || qt_isect_curve_vertical(halves.second, x, y1, y2, depth + 1))
return true;
}
return false;
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
index 83f9415c69..85c894a74a 100644
--- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
+++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
@@ -164,6 +164,43 @@ void openFile(const std::string &accept,
openFiles(accept, FileSelectMode::SingleFile, fileDialogClosedWithInt, acceptFile, fileDataReady);
}
+void saveFile(const char *content, size_t size, const std::string &fileNameHint)
+{
+ // Save a file by creating programatically clicking a download
+ // link to an object url to a Blob containing the file content.
+ // File content is copied once, so that the passed in content
+ // buffer can be released as soon as this function returns - we
+ // don't know for how long the browser will retain the TypedArray
+ // view used to create the Blob.
+
+ emscripten::val document = emscripten::val::global("document");
+ emscripten::val window = emscripten::val::global("window");
+
+ emscripten::val fileContentView = emscripten::val(emscripten::typed_memory_view(size, content));
+ emscripten::val fileContentCopy = emscripten::val::global("ArrayBuffer").new_(size);
+ emscripten::val fileContentCopyView = emscripten::val::global("Uint8Array").new_(fileContentCopy);
+ fileContentCopyView.call<void>("set", fileContentView);
+
+ emscripten::val contentArray = emscripten::val::array();
+ contentArray.call<void>("push", fileContentCopyView);
+ emscripten::val type = emscripten::val::object();
+ type.set("type","application/octet-stream");
+ emscripten::val contentBlob = emscripten::val::global("Blob").new_(contentArray, type);
+
+ emscripten::val contentUrl = window["URL"].call<emscripten::val>("createObjectURL", contentBlob);
+ emscripten::val contentLink = document.call<emscripten::val>("createElement", std::string("a"));
+ contentLink.set("href", contentUrl);
+ contentLink.set("download", fileNameHint);
+ contentLink.set("style", "display:none");
+
+ emscripten::val body = document["body"];
+ body.call<void>("appendChild", contentLink);
+ contentLink.call<void>("click");
+ body.call<void>("removeChild", contentLink);
+
+ window["URL"].call<emscripten::val>("revokeObjectURL", contentUrl);
+}
+
} // namespace QWasmLocalFileAccess
QT_END_NAMESPACE
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
index 794db8d9b2..ccd88570c8 100644
--- a/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
+++ b/src/gui/platform/wasm/qwasmlocalfileaccess_p.h
@@ -71,6 +71,8 @@ void openFile(const std::string &accept,
const std::function<char *(uint64_t size, const std::string name)> &acceptFile,
const std::function<void()> &fileDataReady);
+void saveFile(const char *content, size_t size, const std::string &fileNameHint);
+
} // namespace QWasmLocalFileAccess
QT_END_NAMESPACE
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 45f1ca596e..ce7c7610c1 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -92,6 +92,7 @@ static const QCssKnownValue properties[NumProperties - 1] = {
{ "border-bottom-right-radius", BorderBottomRightRadius },
{ "border-bottom-style", BorderBottomStyle },
{ "border-bottom-width", BorderBottomWidth },
+ { "border-collapse", BorderCollapse },
{ "border-color", BorderColor },
{ "border-image", BorderImage },
{ "border-left", BorderLeft },
@@ -611,11 +612,7 @@ bool ValueExtractor::extractBorder(int *borders, QBrush *colors, BorderStyle *st
case BorderRightStyle: styles[RightEdge] = decl.styleValue(); break;
case BorderStyles: decl.styleValues(styles); break;
-#ifndef QT_OS_ANDROID_GCC_48_WORKAROUND
case BorderTopLeftRadius: radii[0] = sizeValue(decl); break;
-#else
- case BorderTopLeftRadius: new(radii)QSize(sizeValue(decl)); break;
-#endif
case BorderTopRightRadius: radii[1] = sizeValue(decl); break;
case BorderBottomLeftRadius: radii[2] = sizeValue(decl); break;
case BorderBottomRightRadius: radii[3] = sizeValue(decl); break;
@@ -1732,6 +1729,14 @@ void Declaration::borderImageValue(QString *image, int *cuts,
*h = *v;
}
+bool Declaration::borderCollapseValue() const
+{
+ if (d->values.count() != 1)
+ return false;
+ else
+ return d->values.at(0).toString() == QLatin1String("collapse");
+}
+
QIcon Declaration::iconValue() const
{
if (d->parsed.isValid())
diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h
index ddc46803ae..ab85e76cf3 100644
--- a/src/gui/text/qcssparser_p.h
+++ b/src/gui/text/qcssparser_p.h
@@ -122,6 +122,7 @@ enum Property {
BorderRight,
BorderTop,
BorderBottom,
+ BorderCollapse,
Padding,
PaddingLeft,
PaddingRight,
@@ -478,6 +479,7 @@ struct Q_GUI_EXPORT Declaration
QIcon iconValue() const;
void borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const;
+ bool borderCollapseValue() const;
};
QT_CSS_DECLARE_TYPEINFO(Declaration, Q_MOVABLE_TYPE)
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 97e73f0723..3c1a052f37 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -180,14 +180,14 @@ Q_GUI_EXPORT int qt_defaultDpi()
}
QFontPrivate::QFontPrivate()
- : engineData(0), dpi(qt_defaultDpi()), screen(0),
+ : engineData(0), dpi(qt_defaultDpi()),
underline(false), overline(false), strikeOut(false), kerning(true),
capital(0), letterSpacingIsAbsolute(false), scFont(0)
{
}
QFontPrivate::QFontPrivate(const QFontPrivate &other)
- : request(other.request), engineData(0), dpi(other.dpi), screen(other.screen),
+ : request(other.request), engineData(0), dpi(other.dpi),
underline(other.underline), overline(other.overline),
strikeOut(other.strikeOut), kerning(other.kerning),
capital(other.capital), letterSpacingIsAbsolute(other.letterSpacingIsAbsolute),
@@ -581,11 +581,9 @@ QFont::QFont(const QFont &font, const QPaintDevice *pd)
{
Q_ASSERT(pd);
const int dpi = pd->logicalDpiY();
- const int screen = 0;
- if (font.d->dpi != dpi || font.d->screen != screen ) {
+ if (font.d->dpi != dpi) {
d = new QFontPrivate(*font.d);
d->dpi = dpi;
- d->screen = screen;
} else {
d = font.d;
}
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index 466e19e9cc..adbb7a0121 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -185,7 +185,6 @@ public:
QFontDef request;
mutable QFontEngineData *engineData;
int dpi;
- int screen;
uint underline : 1;
uint overline : 1;
@@ -230,19 +229,17 @@ public:
void clear();
struct Key {
- Key() : script(0), multi(0), screen(0) { }
- Key(const QFontDef &d, uchar c, bool m = 0, uchar s = 0)
- : def(d), script(c), multi(m), screen(s) { }
+ Key() : script(0), multi(0) { }
+ Key(const QFontDef &d, uchar c, bool m = 0)
+ : def(d), script(c), multi(m) { }
QFontDef def;
uchar script;
uchar multi: 1;
- uchar screen: 7;
inline bool operator<(const Key &other) const
{
if (script != other.script) return script < other.script;
- if (screen != other.screen) return screen < other.screen;
if (multi != other.multi) return multi < other.multi;
if (multi && def.fallBackFamilies.size() != other.def.fallBackFamilies.size())
return def.fallBackFamilies.size() < other.def.fallBackFamilies.size();
@@ -251,7 +248,6 @@ public:
inline bool operator==(const Key &other) const
{
return script == other.script
- && screen == other.screen
&& multi == other.multi
&& (!multi || def.fallBackFamilies == other.def.fallBackFamilies)
&& def == other.def;
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index c85dd4e1e3..d3e4f11e8c 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -185,11 +185,9 @@ QFontMetrics::QFontMetrics(const QFont &font, const QPaintDevice *paintdevice)
#endif
{
const int dpi = paintdevice ? paintdevice->logicalDpiY() : qt_defaultDpi();
- const int screen = 0;
- if (font.d->dpi != dpi || font.d->screen != screen ) {
+ if (font.d->dpi != dpi) {
d = new QFontPrivate(*font.d);
d->dpi = dpi;
- d->screen = screen;
} else {
d = font.d;
}
@@ -1178,11 +1176,9 @@ QFontMetricsF::QFontMetricsF(const QFont &font, const QPaintDevice *paintdevice)
#endif
{
int dpi = paintdevice ? paintdevice->logicalDpiY() : qt_defaultDpi();
- const int screen = 0;
- if (font.d->dpi != dpi || font.d->screen != screen ) {
+ if (font.d->dpi != dpi) {
d = new QFontPrivate(*font.d);
d->dpi = dpi;
- d->screen = screen;
} else {
d = font.d;
}
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index dc34a96918..c80617f929 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -2593,51 +2593,43 @@ void QTextHtmlExporter::emitFloatStyle(QTextFrameFormat::Position pos, StyleMode
html += QLatin1Char('\"');
}
-void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style)
+static QLatin1String richtextBorderStyleToHtmlBorderStyle(QTextFrameFormat::BorderStyle style)
{
- Q_ASSERT(style <= QTextFrameFormat::BorderStyle_Outset);
-
- html += QLatin1String(" border-style:");
-
switch (style) {
case QTextFrameFormat::BorderStyle_None:
- html += QLatin1String("none");
- break;
+ return QLatin1String("none");
case QTextFrameFormat::BorderStyle_Dotted:
- html += QLatin1String("dotted");
- break;
+ return QLatin1String("dotted");
case QTextFrameFormat::BorderStyle_Dashed:
- html += QLatin1String("dashed");
- break;
+ return QLatin1String("dashed");
case QTextFrameFormat::BorderStyle_Solid:
- html += QLatin1String("solid");
- break;
+ return QLatin1String("solid");
case QTextFrameFormat::BorderStyle_Double:
- html += QLatin1String("double");
- break;
+ return QLatin1String("double");
case QTextFrameFormat::BorderStyle_DotDash:
- html += QLatin1String("dot-dash");
- break;
+ return QLatin1String("dot-dash");
case QTextFrameFormat::BorderStyle_DotDotDash:
- html += QLatin1String("dot-dot-dash");
- break;
+ return QLatin1String("dot-dot-dash");
case QTextFrameFormat::BorderStyle_Groove:
- html += QLatin1String("groove");
- break;
+ return QLatin1String("groove");
case QTextFrameFormat::BorderStyle_Ridge:
- html += QLatin1String("ridge");
- break;
+ return QLatin1String("ridge");
case QTextFrameFormat::BorderStyle_Inset:
- html += QLatin1String("inset");
- break;
+ return QLatin1String("inset");
case QTextFrameFormat::BorderStyle_Outset:
- html += QLatin1String("outset");
- break;
+ return QLatin1String("outset");
default:
- Q_ASSERT(false);
- break;
+ Q_UNREACHABLE();
};
+ return QLatin1String("");
+}
+
+void QTextHtmlExporter::emitBorderStyle(QTextFrameFormat::BorderStyle style)
+{
+ Q_ASSERT(style <= QTextFrameFormat::BorderStyle_Outset);
+ html += QLatin1String(" border-style:");
+ html += richtextBorderStyleToHtmlBorderStyle(style);
html += QLatin1Char(';');
}
@@ -3204,6 +3196,33 @@ void QTextHtmlExporter::emitTable(const QTextTable *table)
if (cellFormat.hasProperty(QTextFormat::TableCellBottomPadding))
styleString += QLatin1String(" padding-bottom:") + QString::number(cellFormat.bottomPadding()) + QLatin1Char(';');
+ if (cellFormat.hasProperty(QTextFormat::TableCellTopBorder))
+ styleString += QLatin1String(" border-top:") + QString::number(cellFormat.topBorder()) + QLatin1String("px;");
+ if (cellFormat.hasProperty(QTextFormat::TableCellRightBorder))
+ styleString += QLatin1String(" border-right:") + QString::number(cellFormat.rightBorder()) + QLatin1String("px;");
+ if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorder))
+ styleString += QLatin1String(" border-bottom:") + QString::number(cellFormat.bottomBorder()) + QLatin1String("px;");
+ if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorder))
+ styleString += QLatin1String(" border-left:") + QString::number(cellFormat.leftBorder()) + QLatin1String("px;");
+
+ if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderBrush))
+ styleString += QLatin1String(" border-top-color:") + cellFormat.topBorderBrush().color().name() + QLatin1Char(';');
+ if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderBrush))
+ styleString += QLatin1String(" border-right-color:") + cellFormat.rightBorderBrush().color().name() + QLatin1Char(';');
+ if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderBrush))
+ styleString += QLatin1String(" border-bottom-color:") + cellFormat.bottomBorderBrush().color().name() + QLatin1Char(';');
+ if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderBrush))
+ styleString += QLatin1String(" border-left-color:") + cellFormat.leftBorderBrush().color().name() + QLatin1Char(';');
+
+ if (cellFormat.hasProperty(QTextFormat::TableCellTopBorderStyle))
+ styleString += QLatin1String(" border-top-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.topBorderStyle()) + QLatin1Char(';');
+ if (cellFormat.hasProperty(QTextFormat::TableCellRightBorderStyle))
+ styleString += QLatin1String(" border-right-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.rightBorderStyle()) + QLatin1Char(';');
+ if (cellFormat.hasProperty(QTextFormat::TableCellBottomBorderStyle))
+ styleString += QLatin1String(" border-bottom-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.bottomBorderStyle()) + QLatin1Char(';');
+ if (cellFormat.hasProperty(QTextFormat::TableCellLeftBorderStyle))
+ styleString += QLatin1String(" border-left-style:") + richtextBorderStyleToHtmlBorderStyle(cellFormat.leftBorderStyle()) + QLatin1Char(';');
+
if (!styleString.isEmpty())
html += QLatin1String(" style=\"") + styleString + QLatin1Char('\"');
@@ -3310,6 +3329,9 @@ void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType
QString::number(format.leftMargin()),
QString::number(format.rightMargin()));
+ if (format.property(QTextFormat::TableBorderCollapse).toBool())
+ html += QLatin1String(" border-collapse:collapse;");
+
if (html.length() == originalHtmlLength) // nothing emitted?
html.chop(styleAttribute.size());
else
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index 34698b2fb0..723e5c907c 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -986,6 +986,7 @@ QTextHtmlImporter::Table QTextHtmlImporter::scanTable(int tableNodeIdx)
tableFmt.setColumns(table.columns);
tableFmt.setColumnWidthConstraints(columnWidths);
tableFmt.setHeaderRowCount(tableHeaderRowCount);
+ tableFmt.setBorderCollapse(node.borderCollapse);
fmt = tableFmt;
}
@@ -1061,6 +1062,31 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode()
fmt.setLeftPadding(leftPadding(currentNodeIdx));
if (rightPadding(currentNodeIdx) >= 0)
fmt.setRightPadding(rightPadding(currentNodeIdx));
+ if (tableCellBorder(currentNodeIdx, QCss::TopEdge) > 0)
+ fmt.setTopBorder(tableCellBorder(currentNodeIdx, QCss::TopEdge));
+ if (tableCellBorder(currentNodeIdx, QCss::RightEdge) > 0)
+ fmt.setRightBorder(tableCellBorder(currentNodeIdx, QCss::RightEdge));
+ if (tableCellBorder(currentNodeIdx, QCss::BottomEdge) > 0)
+ fmt.setBottomBorder(tableCellBorder(currentNodeIdx, QCss::BottomEdge));
+ if (tableCellBorder(currentNodeIdx, QCss::LeftEdge) > 0)
+ fmt.setLeftBorder(tableCellBorder(currentNodeIdx, QCss::LeftEdge));
+ if (tableCellBorderStyle(currentNodeIdx, QCss::TopEdge) != QTextFrameFormat::BorderStyle_None)
+ fmt.setTopBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::TopEdge));
+ if (tableCellBorderStyle(currentNodeIdx, QCss::RightEdge) != QTextFrameFormat::BorderStyle_None)
+ fmt.setRightBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::RightEdge));
+ if (tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge) != QTextFrameFormat::BorderStyle_None)
+ fmt.setBottomBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::BottomEdge));
+ if (tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge) != QTextFrameFormat::BorderStyle_None)
+ fmt.setLeftBorderStyle(tableCellBorderStyle(currentNodeIdx, QCss::LeftEdge));
+ if (tableCellBorderBrush(currentNodeIdx, QCss::TopEdge) != Qt::NoBrush)
+ fmt.setTopBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::TopEdge));
+ if (tableCellBorderBrush(currentNodeIdx, QCss::RightEdge) != Qt::NoBrush)
+ fmt.setRightBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::RightEdge));
+ if (tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge) != Qt::NoBrush)
+ fmt.setBottomBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::BottomEdge));
+ if (tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge) != Qt::NoBrush)
+ fmt.setLeftBorderBrush(tableCellBorderBrush(currentNodeIdx, QCss::LeftEdge));
+
cell.setFormat(fmt);
cursor.setPosition(cell.firstPosition());
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 43b32e7e2c..5d37982a8b 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -491,12 +491,19 @@ QTextHtmlParserNode::QTextHtmlParserNode()
listStyle(QTextListFormat::ListStyleUndefined), imageWidth(-1), imageHeight(-1), tableBorder(0),
tableCellRowSpan(1), tableCellColSpan(1), tableCellSpacing(2), tableCellPadding(0),
borderBrush(Qt::darkGray), borderStyle(QTextFrameFormat::BorderStyle_Outset),
+ borderCollapse(false),
userState(-1), cssListIndent(0), wsm(WhiteSpaceModeUndefined)
{
margin[QTextHtmlParser::MarginLeft] = 0;
margin[QTextHtmlParser::MarginRight] = 0;
margin[QTextHtmlParser::MarginTop] = 0;
margin[QTextHtmlParser::MarginBottom] = 0;
+
+ for (int i = 0; i < 4; ++i) {
+ tableCellBorderStyle[i] = QTextFrameFormat::BorderStyle_None;
+ tableCellBorder[i] = 0;
+ tableCellBorderBrush[i] = Qt::NoBrush;
+ }
}
void QTextHtmlParser::dumpHtml()
@@ -1169,6 +1176,25 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
QCss::ValueExtractor extractor(declarations);
extractor.extractBox(margin, padding);
+ if (id == Html_td || id == Html_th) {
+ QCss::BorderStyle cssStyles[4];
+ int cssBorder[4];
+ QSize cssRadii[4]; // unused
+ for (int i = 0; i < 4; ++i) {
+ cssStyles[i] = QCss::BorderStyle_None;
+ cssBorder[i] = 0;
+ }
+ // this will parse (and cache) "border-width" as a list so the
+ // QCss::BorderWidth parsing below which expects a single value
+ // will not work as expected - which in this case does not matter
+ // because tableBorder is not relevant for cells.
+ extractor.extractBorder(cssBorder, tableCellBorderBrush, cssStyles, cssRadii);
+ for (int i = 0; i < 4; ++i) {
+ tableCellBorderStyle[i] = static_cast<QTextFrameFormat::BorderStyle>(cssStyles[i] - 1);
+ tableCellBorder[i] = static_cast<qreal>(cssBorder[i]);
+ }
+ }
+
for (int i = 0; i < declarations.count(); ++i) {
const QCss::Declaration &decl = declarations.at(i);
if (decl.d->values.isEmpty()) continue;
@@ -1186,6 +1212,9 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
case QCss::BorderWidth:
tableBorder = extractor.lengthValue(decl);
break;
+ case QCss::BorderCollapse:
+ borderCollapse = decl.borderCollapseValue();
+ break;
case QCss::Color: charFormat.setForeground(decl.colorValue()); break;
case QCss::Float:
cssFloat = QTextFrameFormat::InFlow;
@@ -1654,6 +1683,11 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
if (!c.isValid())
qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
node->charFormat.setBackground(c);
+ } else if (key == QLatin1String("bordercolor")) {
+ QColor c; c.setNamedColor(value);
+ if (!c.isValid())
+ qWarning("QTextHtmlParser::applyAttributes: Unknown color name '%s'",value.toLatin1().constData());
+ node->borderBrush = c;
} else if (key == QLatin1String("background")) {
node->applyBackgroundImage(value, resourceProvider);
} else if (key == QLatin1String("cellspacing")) {
diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h
index ff5f5b4c35..31f558709f 100644
--- a/src/gui/text/qtexthtmlparser_p.h
+++ b/src/gui/text/qtexthtmlparser_p.h
@@ -195,8 +195,12 @@ struct QTextHtmlParserNode {
int tableCellColSpan;
qreal tableCellSpacing;
qreal tableCellPadding;
+ qreal tableCellBorder[4];
+ QBrush tableCellBorderBrush[4];
+ QTextFrameFormat::BorderStyle tableCellBorderStyle[4];
QBrush borderBrush;
QTextFrameFormat::BorderStyle borderStyle;
+ bool borderCollapse;
int userState;
int cssListIndent;
@@ -290,6 +294,10 @@ public:
inline int leftPadding(int i) const { return at(i).padding[MarginLeft]; }
inline int rightPadding(int i) const { return at(i).padding[MarginRight]; }
+ inline qreal tableCellBorder(int i, int edge) const { return at(i).tableCellBorder[edge]; }
+ inline QTextFrameFormat::BorderStyle tableCellBorderStyle(int i, int edge) const { return at(i).tableCellBorderStyle[edge]; }
+ inline QBrush tableCellBorderBrush(int i, int edge) const { return at(i).tableCellBorderBrush[edge]; }
+
void dumpHtml();
void parse(const QString &text, const QTextDocument *resourceProvider);
diff --git a/src/network/access/access.pri b/src/network/access/access.pri
index 8a92308f12..cfb20dcd71 100644
--- a/src/network/access/access.pri
+++ b/src/network/access/access.pri
@@ -97,7 +97,8 @@ qtConfig(http) {
access/qhttpnetworkrequest.cpp \
access/qhttpprotocolhandler.cpp \
access/qhttpthreaddelegate.cpp \
- access/qnetworkreplyhttpimpl.cpp
+ access/qnetworkreplyhttpimpl.cpp \
+ access/qhttp2configuration.cpp
HEADERS += \
access/qabstractprotocolhandler_p.h \
@@ -111,7 +112,8 @@ qtConfig(http) {
access/qhttpnetworkrequest_p.h \
access/qhttpprotocolhandler_p.h \
access/qhttpthreaddelegate_p.h \
- access/qnetworkreplyhttpimpl_p.h
+ access/qnetworkreplyhttpimpl_p.h \
+ access/qhttp2configuration.h
qtConfig(ssl) {
SOURCES += \
diff --git a/src/network/access/http2/hpack.cpp b/src/network/access/http2/hpack.cpp
index 2d324d5092..b40cc29e1a 100644
--- a/src/network/access/http2/hpack.cpp
+++ b/src/network/access/http2/hpack.cpp
@@ -208,6 +208,11 @@ void Encoder::setMaxDynamicTableSize(quint32 size)
lookupTable.setMaxDynamicTableSize(size);
}
+void Encoder::setCompressStrings(bool compress)
+{
+ compressStrings = compress;
+}
+
bool Encoder::encodeRequestPseudoHeaders(BitOStream &outputStream,
const HttpHeader &header)
{
diff --git a/src/network/access/http2/hpack_p.h b/src/network/access/http2/hpack_p.h
index 6a1d30d87b..8c2701e7af 100644
--- a/src/network/access/http2/hpack_p.h
+++ b/src/network/access/http2/hpack_p.h
@@ -83,6 +83,7 @@ public:
quint32 newSize);
void setMaxDynamicTableSize(quint32 size);
+ void setCompressStrings(bool compress);
private:
bool encodeRequestPseudoHeaders(BitOStream &outputStream,
diff --git a/src/network/access/http2/http2frames.cpp b/src/network/access/http2/http2frames.cpp
index e695b4dd9e..ce33505683 100644
--- a/src/network/access/http2/http2frames.cpp
+++ b/src/network/access/http2/http2frames.cpp
@@ -305,7 +305,7 @@ FrameStatus FrameReader::read(QAbstractSocket &socket)
return status;
}
- if (Http2PredefinedParameters::maxFrameSize < frame.payloadSize())
+ if (Http2PredefinedParameters::maxPayloadSize < frame.payloadSize())
return FrameStatus::sizeError;
frame.buffer.resize(frame.payloadSize() + frameHeaderSize);
@@ -388,7 +388,7 @@ void FrameWriter::setPayloadSize(quint32 size)
auto &buffer = frame.buffer;
Q_ASSERT(buffer.size() >= frameHeaderSize);
- Q_ASSERT(size < maxPayloadSize);
+ Q_ASSERT(size <= maxPayloadSize);
buffer[0] = size >> 16;
buffer[1] = size >> 8;
diff --git a/src/network/access/http2/http2protocol.cpp b/src/network/access/http2/http2protocol.cpp
index 0be72042c6..31da6fd616 100644
--- a/src/network/access/http2/http2protocol.cpp
+++ b/src/network/access/http2/http2protocol.cpp
@@ -43,6 +43,8 @@
#include "private/qhttpnetworkrequest_p.h"
#include "private/qhttpnetworkreply_p.h"
+#include <access/qhttp2configuration.h>
+
#include <QtCore/qbytearray.h>
#include <QtCore/qstring.h>
@@ -62,88 +64,29 @@ const char Http2clientPreface[clientPrefaceLength] =
0x2e, 0x30, 0x0d, 0x0a, 0x0d, 0x0a,
0x53, 0x4d, 0x0d, 0x0a, 0x0d, 0x0a};
-// TODO: (in 5.11) - remove it!
-const char *http2ParametersPropertyName = "QT_HTTP2_PARAMETERS_PROPERTY";
-
-ProtocolParameters::ProtocolParameters()
-{
- settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID] = qtDefaultStreamReceiveWindowSize;
- settingsFrameData[Settings::ENABLE_PUSH_ID] = 0;
-}
-
-bool ProtocolParameters::validate() const
+Frame configurationToSettingsFrame(const QHttp2Configuration &config)
{
- // 0. Huffman/indexing: any values are valid and allowed.
-
- // 1. Session receive window size (client side): HTTP/2 starts from the
- // default value of 64Kb, if a client code tries to set lesser value,
- // the delta would become negative, but this is not allowed.
- if (maxSessionReceiveWindowSize < qint32(defaultSessionWindowSize)) {
- qCWarning(QT_HTTP2, "Session receive window must be at least 65535 bytes");
- return false;
- }
-
- // 2. HEADER_TABLE_SIZE: we do not validate HEADER_TABLE_SIZE, considering
- // all values as valid. RFC 7540 and 7541 do not provide any lower/upper
- // limits. If it's 0 - we do not index anything, if it's too huge - a user
- // who provided such a value can potentially have a huge memory footprint,
- // up to them to decide.
-
- // 3. SETTINGS_ENABLE_PUSH: RFC 7540, 6.5.2, a value other than 0 or 1 will
- // be treated by our peer as a PROTOCOL_ERROR.
- if (settingsFrameData.contains(Settings::ENABLE_PUSH_ID)
- && settingsFrameData[Settings::ENABLE_PUSH_ID] > 1) {
- qCWarning(QT_HTTP2, "SETTINGS_ENABLE_PUSH can be only 0 or 1");
- return false;
- }
-
- // 4. SETTINGS_MAX_CONCURRENT_STREAMS : RFC 7540 recommends 100 as the lower
- // limit, says nothing about the upper limit. The RFC allows 0, but this makes
- // no sense to us at all: there is no way a user can change this later and
- // we'll not be able to get any responses on such a connection.
- if (settingsFrameData.contains(Settings::MAX_CONCURRENT_STREAMS_ID)
- && !settingsFrameData[Settings::MAX_CONCURRENT_STREAMS_ID]) {
- qCWarning(QT_HTTP2, "MAX_CONCURRENT_STREAMS must be a positive number");
- return false;
- }
-
- // 5. SETTINGS_INITIAL_WINDOW_SIZE.
- if (settingsFrameData.contains(Settings::INITIAL_WINDOW_SIZE_ID)) {
- const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID];
- // RFC 7540, 6.5.2 (the upper limit). The lower limit is our own - we send
- // SETTINGS frame only once and will not be able to change this 0, thus
- // we'll suspend all streams.
- if (!value || value > quint32(maxSessionReceiveWindowSize)) {
- qCWarning(QT_HTTP2, "INITIAL_WINDOW_SIZE must be in the range "
- "(0, 2^31-1]");
- return false;
- }
- }
-
- // 6. SETTINGS_MAX_FRAME_SIZE: RFC 7540, 6.5.2, a value outside of the range
- // [2^14-1, 2^24-1] will be treated by our peer as a PROTOCOL_ERROR.
- if (settingsFrameData.contains(Settings::MAX_FRAME_SIZE_ID)) {
- const quint32 value = settingsFrameData[Settings::INITIAL_WINDOW_SIZE_ID];
- if (value < maxFrameSize || value > maxPayloadSize) {
- qCWarning(QT_HTTP2, "MAX_FRAME_SIZE must be in the range [2^14, 2^24-1]");
- return false;
- }
+ // 6.5 SETTINGS
+ FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
+ // Server push:
+ builder.append(Settings::ENABLE_PUSH_ID);
+ builder.append(int(config.serverPushEnabled()));
+ // Stream receive window size:
+ builder.append(Settings::INITIAL_WINDOW_SIZE_ID);
+ builder.append(config.streamReceiveWindowSize());
+
+ if (config.maxFrameSize() != minPayloadLimit) {
+ builder.append(Settings::MAX_FRAME_SIZE_ID);
+ builder.append(config.maxFrameSize());
}
-
- // For SETTINGS_MAX_HEADER_LIST_SIZE RFC 7540 does not provide any specific
- // numbers. It's clear, if a value is too small, no header can ever be sent
- // by our peer at all. The default value is unlimited and we normally do not
- // change this.
- //
- // Note: the size is calculated as the length of uncompressed (no HPACK)
- // name + value + 32 bytes.
-
- return true;
+ // TODO: In future, if the need is proven, we can
+ // also send decoding table size and header list size.
+ // For now, defaults suffice.
+ return builder.outboundFrame();
}
-QByteArray ProtocolParameters::settingsFrameToBase64() const
+QByteArray settingsFrameToBase64(const Frame &frame)
{
- Frame frame(settingsFrame());
// SETTINGS frame's payload consists of pairs:
// 2-byte-identifier | 4-byte-value == multiple of 6.
Q_ASSERT(frame.payloadSize() && !(frame.payloadSize() % 6));
@@ -157,20 +100,7 @@ QByteArray ProtocolParameters::settingsFrameToBase64() const
return wrapper.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
}
-Frame ProtocolParameters::settingsFrame() const
-{
- // 6.5 SETTINGS
- FrameWriter builder(FrameType::SETTINGS, FrameFlag::EMPTY, connectionStreamID);
- for (auto it = settingsFrameData.cbegin(), end = settingsFrameData.cend();
- it != end; ++it) {
- builder.append(it.key());
- builder.append(it.value());
- }
-
- return builder.outboundFrame();
-}
-
-void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request) const
+void appendProtocolUpgradeHeaders(const QHttp2Configuration &config, QHttpNetworkRequest *request)
{
Q_ASSERT(request);
// RFC 2616, 14.10
@@ -184,8 +114,10 @@ void ProtocolParameters::addProtocolUpgradeHeaders(QHttpNetworkRequest *request)
request->setHeaderField("Connection", value);
// This we just (re)write.
request->setHeaderField("Upgrade", "h2c");
+
+ const Frame frame(configurationToSettingsFrame(config));
// This we just (re)write.
- request->setHeaderField("HTTP2-Settings", settingsFrameToBase64());
+ request->setHeaderField("HTTP2-Settings", settingsFrameToBase64(frame));
}
void qt_error(quint32 errorCode, QNetworkReply::NetworkError &error,
diff --git a/src/network/access/http2/http2protocol_p.h b/src/network/access/http2/http2protocol_p.h
index 7142d6f1fa..b0af5aa919 100644
--- a/src/network/access/http2/http2protocol_p.h
+++ b/src/network/access/http2/http2protocol_p.h
@@ -55,12 +55,14 @@
#include <QtCore/qloggingcategory.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qglobal.h>
+#include <QtCore/qmap.h>
// Different HTTP/2 constants/values as defined by RFC 7540.
QT_BEGIN_NAMESPACE
class QHttpNetworkRequest;
+class QHttp2Configuration;
class QHttpNetworkReply;
class QByteArray;
class QString;
@@ -118,13 +120,19 @@ enum Http2PredefinedParameters
connectionStreamID = 0, // HTTP/2, 5.1.1
frameHeaderSize = 9, // HTTP/2, 4.1
- // It's our max frame size we send in SETTINGS frame,
- // it's also the default one and we also use it to later
- // validate incoming frames:
- maxFrameSize = 16384, // HTTP/2 6.5.2
+ // The initial allowed payload size. We would use it as an
+ // upper limit for a frame payload we send, until our peer
+ // updates us with a larger SETTINGS_MAX_FRAME_SIZE.
- defaultSessionWindowSize = 65535, // HTTP/2 6.5.2
+ // The initial maximum payload size that an HTTP/2 frame
+ // can contain is 16384. It's also the minimal size that
+ // can be advertised via 'SETTINGS' frames. A real frame
+ // can have a payload smaller than 16384.
+ minPayloadLimit = 16384, // HTTP/2 6.5.2
+ // The maximum allowed payload size.
maxPayloadSize = (1 << 24) - 1, // HTTP/2 6.5.2
+
+ defaultSessionWindowSize = 65535, // HTTP/2 6.5.2
// Using 1000 (rather arbitrarily), just to
// impose *some* upper limit:
maxPeerConcurrentStreams = 1000,
@@ -145,48 +153,9 @@ const quint32 lastValidStreamID((quint32(1) << 31) - 1); // HTTP/2, 5.1.1
const qint32 maxSessionReceiveWindowSize((quint32(1) << 31) - 1);
const qint32 qtDefaultStreamReceiveWindowSize = maxSessionReceiveWindowSize / maxConcurrentStreams;
-// The class ProtocolParameters allows client code to customize HTTP/2 protocol
-// handler, if needed. Normally, we use our own default parameters (see below).
-// In 5.10 we can also use setProperty/property on a QNAM object to pass the
-// non-default values to the protocol handler. In 5.11 this will probably become
-// a public API.
-
-using RawSettings = QMap<Settings, quint32>;
-
-struct Q_AUTOTEST_EXPORT ProtocolParameters
-{
- ProtocolParameters();
-
- bool validate() const;
- QByteArray settingsFrameToBase64() const;
- struct Frame settingsFrame() const;
- void addProtocolUpgradeHeaders(QHttpNetworkRequest *request) const;
-
- // HPACK:
- // TODO: for now we ignore them (fix it for 5.11, would require changes in HPACK)
- bool useHuffman = true;
- bool indexStrings = true;
-
- // This parameter is not negotiated via SETTINGS frames, so we have it
- // as a member and will convey it to our peer as a WINDOW_UPDATE frame.
- // Note, some servers do not accept our WINDOW_UPDATE from the default
- // 64 KB to the possible maximum. Let's use a half of it:
- qint32 maxSessionReceiveWindowSize = Http2::maxSessionReceiveWindowSize / 2;
-
- // This is our default SETTINGS frame:
- //
- // SETTINGS_INITIAL_WINDOW_SIZE: (2^31 - 1) / 100
- // SETTINGS_ENABLE_PUSH: 0.
- //
- // Note, whenever we skip some value in our SETTINGS frame, our peer
- // will assume the defaults recommended by RFC 7540, which in general
- // are good enough, although we (and most browsers) prefer to work
- // with larger window sizes.
- RawSettings settingsFrameData;
-};
-
-// TODO: remove in 5.11
-extern const Q_AUTOTEST_EXPORT char *http2ParametersPropertyName;
+struct Frame configurationToSettingsFrame(const QHttp2Configuration &configuration);
+QByteArray settingsFrameToBase64(const Frame &settingsFrame);
+void appendProtocolUpgradeHeaders(const QHttp2Configuration &configuration, QHttpNetworkRequest *request);
extern const Q_AUTOTEST_EXPORT char Http2clientPreface[clientPrefaceLength];
@@ -235,6 +204,5 @@ Q_DECLARE_LOGGING_CATEGORY(QT_HTTP2)
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Http2::Settings)
-Q_DECLARE_METATYPE(Http2::ProtocolParameters)
#endif
diff --git a/src/network/access/qhttp2configuration.cpp b/src/network/access/qhttp2configuration.cpp
new file mode 100644
index 0000000000..a32bccfd09
--- /dev/null
+++ b/src/network/access/qhttp2configuration.cpp
@@ -0,0 +1,312 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qhttp2configuration.h"
+
+#include "private/http2protocol_p.h"
+#include "private/hpack_p.h"
+
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QHttp2Configuration
+ \brief The QHttp2Configuration class controls HTTP/2 parameters and settings
+ \since 5.14
+
+ \reentrant
+ \inmodule QtNetwork
+ \ingroup network
+ \ingroup shared
+
+ QHttp2Configuration controls HTTP/2 parameters and settings that
+ QNetworkAccessManager will use to send requests and process responses
+ when the HTTP/2 protocol is enabled.
+
+ The HTTP/2 parameters that QHttp2Configuration currently supports include:
+
+ \list
+ \li The session window size for connection-level flow control.
+ Will be sent to a remote peer when needed as 'WINDOW_UPDATE'
+ frames on the stream with an identifier 0.
+ \li The stream receiving window size for stream-level flow control.
+ Sent as 'SETTINGS_INITIAL_WINDOW_SIZE' parameter in the initial
+ SETTINGS frame and, when needed, 'WINDOW_UPDATE' frames will be
+ sent on streams that QNetworkAccessManager opens.
+ \li The maximum frame size. This parameter limits the maximum payload
+ a frame coming from the remote peer can have. Sent by QNetworkAccessManager
+ as 'SETTINGS_MAX_FRAME_SIZE' parameter in the initial 'SETTINGS'
+ frame.
+ \li The server push. Allows to enable or disable server push. Sent
+ as 'SETTINGS_ENABLE_PUSH' parameter in the initial 'SETTINGS'
+ frame.
+ \endlist
+
+ The QHttp2Configuration class also controls if the header compression
+ algorithm (HPACK) is additionally using Huffman coding for string
+ compression.
+
+ \note The configuration must be set before the first request
+ was sent to a given host (and thus an HTTP/2 session established).
+
+ \note Details about flow control, server push and 'SETTINGS'
+ can be found in \l {https://httpwg.org/specs/rfc7540.html}{RFC 7540}.
+ Different modes and parameters of the HPACK compression algorithm
+ are described in \l {https://httpwg.org/specs/rfc7541.html}{RFC 7541}.
+
+ \sa QNetworkRequest::setHttp2Configuration(), QNetworkRequest::http2Configuration(), QNetworkAccessManager
+*/
+
+class QHttp2ConfigurationPrivate : public QSharedData
+{
+public:
+ unsigned sessionWindowSize = Http2::defaultSessionWindowSize;
+ // The size below is quite a limiting default value, QNetworkRequest
+ // by default sets a larger number, an application can change this using
+ // QNetworkRequest::setHttp2Configuration.
+ unsigned streamWindowSize = Http2::defaultSessionWindowSize;
+
+ unsigned maxFrameSize = Http2::minPayloadLimit; // Initial (default) value of 16Kb.
+
+ bool pushEnabled = false;
+ // TODO: for now those two below are noop.
+ bool huffmanCompressionEnabled = true;
+};
+
+/*!
+ Default constructs a QHttp2Configuration object.
+
+ Such a configuration has the following values:
+ \list
+ \li Server push is disabled
+ \li Huffman string compression is enabled
+ \li Window size for connection-level flow control is 65535 octets
+ \li Window size for stream-level flow control is 65535 octets
+ \li Frame size is 16384 octets
+ \endlist
+*/
+QHttp2Configuration::QHttp2Configuration()
+ : d(new QHttp2ConfigurationPrivate)
+{
+}
+
+/*!
+ Copy-constructs this QHttp2Configuration.
+*/
+QHttp2Configuration::QHttp2Configuration(const QHttp2Configuration &) = default;
+
+/*!
+ Move-constructs this QHttp2Configuration from \a other
+*/
+QHttp2Configuration::QHttp2Configuration(QHttp2Configuration &&other) noexcept
+{
+ swap(other);
+}
+
+/*!
+ Copy-assigns to this QHttp2Configuration.
+*/
+QHttp2Configuration &QHttp2Configuration::operator=(const QHttp2Configuration &) = default;
+
+/*!
+ Move-assigns to this QHttp2Configuration.
+*/
+QHttp2Configuration &QHttp2Configuration::operator=(QHttp2Configuration &&) noexcept = default;
+
+/*!
+ Destructor.
+*/
+QHttp2Configuration::~QHttp2Configuration()
+{
+}
+
+/*!
+ If \a enable is \c true, a remote server can potentially
+ use server push to send reponses in advance.
+
+ \sa serverPushEnabled
+*/
+void QHttp2Configuration::setServerPushEnabled(bool enable)
+{
+ d->pushEnabled = enable;
+}
+
+/*!
+ Returns true if server push was enabled.
+
+ \note By default, QNetworkAccessManager disables server
+ push via the 'SETTINGS' frame.
+
+ \sa setServerPushEnabled
+*/
+bool QHttp2Configuration::serverPushEnabled() const
+{
+ return d->pushEnabled;
+}
+
+/*!
+ If \a enable is \c true, HPACK compression will additionally
+ compress string using the Huffman coding. Enabled by default.
+
+ \note This parameter only affects 'HEADERS' frames that
+ QNetworkAccessManager is sending.
+
+ \sa huffmanCompressionEnabled
+*/
+void QHttp2Configuration::setHuffmanCompressionEnabled(bool enable)
+{
+ d->huffmanCompressionEnabled = enable;
+}
+
+/*!
+ Returns \c true if the Huffman coding in HPACK is enabled.
+
+ \sa setHuffmanCompressionEnabled
+*/
+bool QHttp2Configuration::huffmanCompressionEnabled() const
+{
+ return d->huffmanCompressionEnabled;
+}
+
+/*!
+ Sets the window size for connection-level flow control.
+ \a size cannot be 0 and must not exceed 2147483647 octets.
+
+ \sa sessionReceiveWindowSize
+*/
+bool QHttp2Configuration::setSessionReceiveWindowSize(unsigned size)
+{
+ if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9
+ qCWarning(QT_HTTP2) << "Invalid session window size";
+ return false;
+ }
+
+ d->sessionWindowSize = size;
+ return true;
+}
+
+/*!
+ Returns the window size for connection-level flow control.
+ The default value QNetworkAccessManager will be using is
+ 2147483647 octets.
+*/
+unsigned QHttp2Configuration::sessionReceiveWindowSize() const
+{
+ return d->sessionWindowSize;
+}
+
+/*!
+ Sets the window size for stream-level flow control.
+ \a size cannot be 0 and must not exceed 2147483647 octets.
+
+ \sa streamReceiveWindowSize
+ */
+bool QHttp2Configuration::setStreamReceiveWindowSize(unsigned size)
+{
+ if (!size || size > Http2::maxSessionReceiveWindowSize) { // RFC-7540, 6.9
+ qCWarning(QT_HTTP2) << "Invalid stream window size";
+ return false;
+ }
+
+ d->streamWindowSize = size;
+ return true;
+}
+
+/*!
+ Returns the window size for stream-level flow control.
+ The default value QNetworkAccessManager will be using is
+ 21474836 octets.
+*/
+unsigned QHttp2Configuration::streamReceiveWindowSize() const
+{
+ return d->streamWindowSize;
+}
+
+/*!
+ Sets the maximum frame size that QNetworkAccessManager
+ will advertise to the server when sending its initial SETTINGS frame.
+ \note While this \a size is required to be within a range between
+ 16384 and 16777215 inclusive, the actual payload size in frames
+ that carry payload maybe be less than 16384.
+*/
+bool QHttp2Configuration::setMaxFrameSize(unsigned size)
+{
+ if (size < Http2::minPayloadLimit || size > Http2::maxPayloadSize) {
+ qCWarning(QT_HTTP2) << "Maximum frame size to advertise is invalid";
+ return false;
+ }
+
+ d->maxFrameSize = size;
+ return true;
+}
+
+/*!
+ The maximum payload size that HTTP/2 frames can
+ have. The default (initial) value is 16384 octets.
+*/
+unsigned QHttp2Configuration::maxFrameSize() const
+{
+ return d->maxFrameSize;
+}
+
+/*!
+ Swaps this configuration with the \a other configuration.
+*/
+void QHttp2Configuration::swap(QHttp2Configuration &other) noexcept
+{
+ d.swap(other.d);
+}
+
+/*!
+ Returns \c true if \a lhs and \a rhs have the same set of HTTP/2
+ parameters.
+*/
+bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs)
+{
+ if (lhs.d == rhs.d)
+ return true;
+
+ return lhs.d->pushEnabled == rhs.d->pushEnabled
+ && lhs.d->huffmanCompressionEnabled == rhs.d->huffmanCompressionEnabled
+ && lhs.d->sessionWindowSize == rhs.d->sessionWindowSize
+ && lhs.d->streamWindowSize == rhs.d->streamWindowSize;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/access/qhttp2configuration.h b/src/network/access/qhttp2configuration.h
new file mode 100644
index 0000000000..e5c235e2be
--- /dev/null
+++ b/src/network/access/qhttp2configuration.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QHTTP2CONFIGURATION_H
+#define QHTTP2CONFIGURATION_H
+
+#include <QtNetwork/qtnetworkglobal.h>
+
+#include <QtCore/qshareddata.h>
+
+#ifndef Q_CLANG_QDOC
+QT_REQUIRE_CONFIG(http);
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QHttp2ConfigurationPrivate;
+class Q_NETWORK_EXPORT QHttp2Configuration
+{
+ friend Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs);
+
+public:
+ QHttp2Configuration();
+ QHttp2Configuration(const QHttp2Configuration &other);
+ QHttp2Configuration(QHttp2Configuration &&other) noexcept;
+ QHttp2Configuration &operator = (const QHttp2Configuration &other);
+ QHttp2Configuration &operator = (QHttp2Configuration &&other) noexcept;
+
+ ~QHttp2Configuration();
+
+ void setServerPushEnabled(bool enable);
+ bool serverPushEnabled() const;
+
+ void setHuffmanCompressionEnabled(bool enable);
+ bool huffmanCompressionEnabled() const;
+
+ bool setSessionReceiveWindowSize(unsigned size);
+ unsigned sessionReceiveWindowSize() const;
+
+ bool setStreamReceiveWindowSize(unsigned size);
+ unsigned streamReceiveWindowSize() const;
+
+ bool setMaxFrameSize(unsigned size);
+ unsigned maxFrameSize() const;
+
+ void swap(QHttp2Configuration &other) noexcept;
+
+private:
+
+ QSharedDataPointer<QHttp2ConfigurationPrivate> d;
+};
+
+Q_DECLARE_SHARED(QHttp2Configuration)
+
+Q_NETWORK_EXPORT bool operator==(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs);
+
+inline bool operator!=(const QHttp2Configuration &lhs, const QHttp2Configuration &rhs)
+{
+ return !(lhs == rhs);
+}
+
+QT_END_NAMESPACE
+
+#endif // QHTTP2CONFIGURATION_H
diff --git a/src/network/access/qhttp2protocolhandler.cpp b/src/network/access/qhttp2protocolhandler.cpp
index 0ece5b7179..c1053882af 100644
--- a/src/network/access/qhttp2protocolhandler.cpp
+++ b/src/network/access/qhttp2protocolhandler.cpp
@@ -40,6 +40,7 @@
#include "qhttpnetworkconnection_p.h"
#include "qhttp2protocolhandler_p.h"
+#include "http2/http2frames_p.h"
#include "http2/bitstreams_p.h"
#include <private/qnoncontiguousbytedevice_p.h>
@@ -51,6 +52,8 @@
#include <QtCore/qlist.h>
#include <QtCore/qurl.h>
+#include <qhttp2configuration.h>
+
#ifndef QT_NO_NETWORKPROXY
#include <QtNetwork/qnetworkproxy.h>
#endif
@@ -172,30 +175,11 @@ QHttp2ProtocolHandler::QHttp2ProtocolHandler(QHttpNetworkConnectionChannel *chan
Q_ASSERT(channel && m_connection);
continuedFrames.reserve(20);
- const ProtocolParameters params(m_connection->http2Parameters());
- Q_ASSERT(params.validate());
-
- maxSessionReceiveWindowSize = params.maxSessionReceiveWindowSize;
-
- const RawSettings &data = params.settingsFrameData;
- for (auto param = data.cbegin(), end = data.cend(); param != end; ++param) {
- switch (param.key()) {
- case Settings::INITIAL_WINDOW_SIZE_ID:
- streamInitialReceiveWindowSize = param.value();
- break;
- case Settings::ENABLE_PUSH_ID:
- pushPromiseEnabled = param.value();
- break;
- case Settings::HEADER_TABLE_SIZE_ID:
- case Settings::MAX_CONCURRENT_STREAMS_ID:
- case Settings::MAX_FRAME_SIZE_ID:
- case Settings::MAX_HEADER_LIST_SIZE_ID:
- // These other settings are just recommendations to our peer. We
- // only check they are not crazy in ProtocolParameters::validate().
- default:
- break;
- }
- }
+ const auto h2Config = m_connection->http2Parameters();
+ maxSessionReceiveWindowSize = h2Config.sessionReceiveWindowSize();
+ pushPromiseEnabled = h2Config.serverPushEnabled();
+ streamInitialReceiveWindowSize = h2Config.streamReceiveWindowSize();
+ encoder.setCompressStrings(h2Config.huffmanCompressionEnabled());
if (!channel->ssl && m_connection->connectionType() != QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
// We upgraded from HTTP/1.1 to HTTP/2. channel->request was already sent
@@ -422,20 +406,17 @@ bool QHttp2ProtocolHandler::sendClientPreface()
return false;
// 6.5 SETTINGS
- const ProtocolParameters params(m_connection->http2Parameters());
- Q_ASSERT(params.validate());
- frameWriter.setOutboundFrame(params.settingsFrame());
+ frameWriter.setOutboundFrame(Http2::configurationToSettingsFrame(m_connection->http2Parameters()));
Q_ASSERT(frameWriter.outboundFrame().payloadSize());
if (!frameWriter.write(*m_socket))
return false;
sessionReceiveWindowSize = maxSessionReceiveWindowSize;
- // ProtocolParameters::validate does not allow maxSessionReceiveWindowSize
- // to be smaller than defaultSessionWindowSize, so everything is OK here with
- // 'delta':
+ // We only send WINDOW_UPDATE for the connection if the size differs from the
+ // default 64 KB:
const auto delta = maxSessionReceiveWindowSize - Http2::defaultSessionWindowSize;
- if (!sendWINDOW_UPDATE(Http2::connectionStreamID, delta))
+ if (delta && !sendWINDOW_UPDATE(Http2::connectionStreamID, delta))
return false;
prefaceSent = true;
@@ -1069,7 +1050,7 @@ bool QHttp2ProtocolHandler::acceptSetting(Http2::Settings identifier, quint32 ne
}
if (identifier == Settings::MAX_FRAME_SIZE_ID) {
- if (newValue < Http2::maxFrameSize || newValue > Http2::maxPayloadSize) {
+ if (newValue < Http2::minPayloadLimit || newValue > Http2::maxPayloadSize) {
connectionError(PROTOCOL_ERROR, "SETTGINGS max frame size is out of range");
return false;
}
diff --git a/src/network/access/qhttp2protocolhandler_p.h b/src/network/access/qhttp2protocolhandler_p.h
index b582123961..1943827e23 100644
--- a/src/network/access/qhttp2protocolhandler_p.h
+++ b/src/network/access/qhttp2protocolhandler_p.h
@@ -55,6 +55,8 @@
#include <private/qabstractprotocolhandler_p.h>
#include <private/qhttpnetworkrequest_p.h>
+#include <access/qhttp2configuration.h>
+
#include <private/http2protocol_p.h>
#include <private/http2streams_p.h>
#include <private/http2frames_p.h>
@@ -163,8 +165,9 @@ private:
static const std::deque<quint32>::size_type maxRecycledStreams;
std::deque<quint32> recycledStreams;
- // Peer's max frame size.
- quint32 maxFrameSize = Http2::maxFrameSize;
+ // Peer's max frame size (this min is the default value
+ // we start with, that can be updated by SETTINGS frame):
+ quint32 maxFrameSize = Http2::minPayloadLimit;
Http2::FrameReader frameReader;
Http2::Frame inboundFrame;
@@ -176,28 +179,28 @@ private:
// Control flow:
- // This is how many concurrent streams our peer expects from us:
- // 100 is the default value, can be updated by the server's SETTINGS
- // frame(s):
+ // This is how many concurrent streams our peer allows us, 100 is the
+ // initial value, can be updated by the server's SETTINGS frame(s):
quint32 maxConcurrentStreams = Http2::maxConcurrentStreams;
// While we allow sending SETTTINGS_MAX_CONCURRENT_STREAMS to limit our peer,
// it's just a hint and we do not actually enforce it (and we can continue
// sending requests and creating streams while maxConcurrentStreams allows).
- // This is the max value, we set it in a ctor from Http2::ProtocolParameters,
- // it does not change after that.
+ // This is our (client-side) maximum possible receive window size, we set
+ // it in a ctor from QHttp2Configuration, it does not change after that.
+ // The default is 64Kb:
qint32 maxSessionReceiveWindowSize = Http2::defaultSessionWindowSize;
- // Our session receive window size, default is 64Kb. We'll update it from QNAM's
- // Http2::ProtocolParameters. Signed integer since it can become negative
+ // Our session current receive window size, updated in a ctor from
+ // QHttp2Configuration. Signed integer since it can become negative
// (it's still a valid window size).
qint32 sessionReceiveWindowSize = Http2::defaultSessionWindowSize;
// Our per-stream receive window size, default is 64 Kb, will be updated
- // from QNAM's Http2::ProtocolParameters. Again, signed - can become negative.
+ // from QHttp2Configuration. Again, signed - can become negative.
qint32 streamInitialReceiveWindowSize = Http2::defaultSessionWindowSize;
// These are our peer's receive window sizes, they will be updated by the
- // peer's SETTINGS and WINDOW_UPDATE frames.
+ // peer's SETTINGS and WINDOW_UPDATE frames, defaults presumed to be 64Kb.
qint32 sessionSendWindowSize = Http2::defaultSessionWindowSize;
qint32 streamInitialSendWindowSize = Http2::defaultSessionWindowSize;
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 1f1de478ea..13be1aa6b5 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -1456,21 +1456,16 @@ void QHttpNetworkConnection::setConnectionType(ConnectionType type)
d->connectionType = type;
}
-Http2::ProtocolParameters QHttpNetworkConnection::http2Parameters() const
+QHttp2Configuration QHttpNetworkConnection::http2Parameters() const
{
Q_D(const QHttpNetworkConnection);
return d->http2Parameters;
}
-void QHttpNetworkConnection::setHttp2Parameters(const Http2::ProtocolParameters &params)
+void QHttpNetworkConnection::setHttp2Parameters(const QHttp2Configuration &params)
{
Q_D(QHttpNetworkConnection);
- if (params.validate()) {
- d->http2Parameters = params;
- } else {
- qCWarning(QT_HTTP2)
- << "invalid HTTP/2 parameters, falling back to defaults instead";
- }
+ d->http2Parameters = params;
}
// SSL support below
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 85d89f20c2..6808a0c0ac 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -57,6 +57,8 @@
#include <QtNetwork/qabstractsocket.h>
#include <QtNetwork/qnetworksession.h>
+#include <qhttp2configuration.h>
+
#include <private/qobject_p.h>
#include <qauthenticator.h>
#include <qnetworkproxy.h>
@@ -142,8 +144,8 @@ public:
ConnectionType connectionType();
void setConnectionType(ConnectionType type);
- Http2::ProtocolParameters http2Parameters() const;
- void setHttp2Parameters(const Http2::ProtocolParameters &params);
+ QHttp2Configuration http2Parameters() const;
+ void setHttp2Parameters(const QHttp2Configuration &params);
#ifndef QT_NO_SSL
void setSslConfiguration(const QSslConfiguration &config);
@@ -294,7 +296,7 @@ public:
QSharedPointer<QNetworkSession> networkSession;
#endif
- Http2::ProtocolParameters http2Parameters;
+ QHttp2Configuration http2Parameters;
QString peerVerifyName;
// If network status monitoring is enabled, we activate connectionMonitor
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 3c9d53c5b5..716ea6c8b2 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -40,6 +40,7 @@
#include "qhttpnetworkconnectionchannel_p.h"
#include "qhttpnetworkconnection_p.h"
+#include "qhttp2configuration.h"
#include "private/qnoncontiguousbytedevice_p.h"
#include <qpair.h>
@@ -48,6 +49,7 @@
#include <private/qhttp2protocolhandler_p.h>
#include <private/qhttpprotocolhandler_p.h>
#include <private/qspdyprotocolhandler_p.h>
+#include <private/http2protocol_p.h>
#ifndef QT_NO_SSL
# include <private/qsslsocket_p.h>
@@ -947,9 +949,7 @@ void QHttpNetworkConnectionChannel::_q_connected()
if (tryProtocolUpgrade) {
// Let's augment our request with some magic headers and try to
// switch to HTTP/2.
- const Http2::ProtocolParameters params(connection->http2Parameters());
- Q_ASSERT(params.validate());
- params.addProtocolUpgradeHeaders(&request);
+ Http2::appendProtocolUpgradeHeaders(connection->http2Parameters(), &request);
}
sendRequest();
}
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index acc551a7c9..1900397eab 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -352,9 +352,9 @@ void QHttpThreadDelegate::startRequest()
networkSession);
#endif // QT_NO_BEARERMANAGEMENT
if (connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2
- && http2Parameters.validate()) {
+ || connectionType == QHttpNetworkConnection::ConnectionTypeHTTP2Direct) {
httpConnection->setHttp2Parameters(http2Parameters);
- } // else we ignore invalid parameters and use our own defaults.
+ }
#ifndef QT_NO_SSL
// Set the QSslConfiguration from this QNetworkRequest.
if (ssl)
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index 6184b39b30..355d1afc30 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -62,6 +62,7 @@
#include <QNetworkReply>
#include "qhttpnetworkrequest_p.h"
#include "qhttpnetworkconnection_p.h"
+#include "qhttp2configuration.h"
#include <QSharedPointer>
#include <QScopedPointer>
#include "private/qnoncontiguousbytedevice_p.h"
@@ -116,7 +117,7 @@ public:
qint64 removedContentLength;
QNetworkReply::NetworkError incomingErrorCode;
QString incomingErrorDetail;
- Http2::ProtocolParameters http2Parameters;
+ QHttp2Configuration http2Parameters;
#ifndef QT_NO_BEARERMANAGEMENT
QSharedPointer<QNetworkSession> networkSession;
#endif
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 29192ae7b0..fdc3cd3b3a 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -70,6 +70,7 @@
#include "QtNetwork/private/qauthenticator_p.h"
#include "QtNetwork/qsslconfiguration.h"
#include "QtNetwork/qnetworkconfigmanager.h"
+#include "QtNetwork/private/http2protocol_p.h"
#if QT_CONFIG(http)
#include "qhttpmultipart.h"
@@ -489,6 +490,7 @@ QNetworkAccessManager::QNetworkAccessManager(QObject *parent)
qRegisterMetaType<QSharedPointer<char> >();
Q_D(QNetworkAccessManager);
+
if (QNetworkStatusMonitor::isEnabled()) {
connect(&d->statusMonitor, SIGNAL(onlineStateChanged(bool)),
SLOT(_q_onlineStateChanged(bool)));
@@ -1178,7 +1180,6 @@ QSharedPointer<QNetworkSession> QNetworkAccessManagerPrivate::getNetworkSession(
#endif // QT_NO_BEARERMANAGEMENT
-
#ifndef QT_NO_SSL
/*!
\since 5.2
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index b9651b35d2..b3dec282b0 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -797,10 +797,8 @@ void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpReq
// Create the HTTP thread delegate
QHttpThreadDelegate *delegate = new QHttpThreadDelegate;
- // Propagate Http/2 settings if any
- const QVariant blob(manager->property(Http2::http2ParametersPropertyName));
- if (blob.isValid() && blob.canConvert<Http2::ProtocolParameters>())
- delegate->http2Parameters = blob.value<Http2::ProtocolParameters>();
+ // Propagate Http/2 settings:
+ delegate->http2Parameters = request.http2Configuration();
#ifndef QT_NO_BEARERMANAGEMENT
if (!QNetworkStatusMonitor::isEnabled())
delegate->networkSession = managerPrivate->getNetworkSession();
@@ -1054,59 +1052,39 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d)
if (!q->isOpen())
return;
- int pendingSignals = (int)pendingDownloadDataEmissions->fetchAndAddAcquire(-1) - 1;
+ if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice)
+ initCacheSaveDevice();
+
+ // This is going to look a little strange. When downloading data while a
+ // HTTP redirect is happening (and enabled), we write the redirect
+ // response to the cache. However, we do not append it to our internal
+ // buffer as that will contain the response data only for the final
+ // response
+ if (cacheSaveDevice)
+ cacheSaveDevice->write(d);
+
+ if (!isHttpRedirectResponse()) {
+ buffer.append(d);
+ bytesDownloaded += d.size();
+ }
+ bytesBuffered += d.size();
+ int pendingSignals = pendingDownloadDataEmissions->fetchAndSubAcquire(1) - 1;
if (pendingSignals > 0) {
// Some more signal emissions to this slot are pending.
// Instead of writing the downstream data, we wait
// and do it in the next call we get
// (signal comppression)
- pendingDownloadData.append(d);
return;
}
- pendingDownloadData.append(d);
- d.clear();
- // We need to usa a copy for calling writeDownstreamData as we could
- // possibly recurse into this this function when we call
- // appendDownstreamDataSignalEmissions because the user might call
- // processEvents() or spin an event loop when this occur.
- QByteDataBuffer pendingDownloadDataCopy = pendingDownloadData;
- pendingDownloadData.clear();
-
- if (cacheEnabled && isCachingAllowed() && !cacheSaveDevice) {
- initCacheSaveDevice();
- }
-
- qint64 bytesWritten = 0;
- for (int i = 0; i < pendingDownloadDataCopy.bufferCount(); i++) {
- QByteArray const &item = pendingDownloadDataCopy[i];
-
- // This is going to look a little strange. When downloading data while a
- // HTTP redirect is happening (and enabled), we write the redirect
- // response to the cache. However, we do not append it to our internal
- // buffer as that will contain the response data only for the final
- // response
- if (cacheSaveDevice)
- cacheSaveDevice->write(item.constData(), item.size());
-
- if (!isHttpRedirectResponse())
- buffer.append(item);
-
- bytesWritten += item.size();
- }
- bytesBuffered += bytesWritten;
- pendingDownloadDataCopy.clear();
+ if (isHttpRedirectResponse())
+ return;
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
if (preMigrationDownloaded != Q_INT64_C(-1))
totalSize = totalSize.toLongLong() + preMigrationDownloaded;
- if (isHttpRedirectResponse())
- return;
-
- bytesDownloaded += bytesWritten;
-
emit q->readyRead();
// emit readyRead before downloadProgress incase this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index f5f01d0811..ef69ce0653 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -63,7 +63,6 @@
#include <QtNetwork/QNetworkCacheMetaData>
#include <private/qhttpnetworkrequest_p.h>
-#include <private/qbytedata_p.h>
#include <private/qnetworkreply_p.h>
#include <QtNetwork/QNetworkProxy>
#include <QtNetwork/QNetworkSession>
@@ -248,7 +247,6 @@ public:
quint64 resumeOffset;
qint64 preMigrationDownloaded;
- QByteDataBuffer pendingDownloadData; // For signal compression
qint64 bytesDownloaded;
qint64 bytesBuffered;
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index 37f64c3f52..118fb6b1fb 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -42,6 +42,10 @@
#include "qplatformdefs.h"
#include "qnetworkcookie.h"
#include "qsslconfiguration.h"
+#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+#include "qhttp2configuration.h"
+#include "private/http2protocol_p.h"
+#endif
#include "QtCore/qshareddata.h"
#include "QtCore/qlocale.h"
#include "QtCore/qdatetime.h"
@@ -445,6 +449,9 @@ public:
sslConfiguration = new QSslConfiguration(*other.sslConfiguration);
#endif
peerVerifyName = other.peerVerifyName;
+#if QT_CONFIG(http)
+ h2Configuration = other.h2Configuration;
+#endif
}
inline bool operator==(const QNetworkRequestPrivate &other) const
@@ -454,7 +461,11 @@ public:
rawHeaders == other.rawHeaders &&
attributes == other.attributes &&
maxRedirectsAllowed == other.maxRedirectsAllowed &&
- peerVerifyName == other.peerVerifyName;
+ peerVerifyName == other.peerVerifyName
+#if QT_CONFIG(http)
+ && h2Configuration == other.h2Configuration
+#endif
+ ;
// don't compare cookedHeaders
}
@@ -465,6 +476,9 @@ public:
#endif
int maxRedirectsAllowed;
QString peerVerifyName;
+#if QT_CONFIG(http)
+ QHttp2Configuration h2Configuration;
+#endif
};
/*!
@@ -476,6 +490,15 @@ public:
QNetworkRequest::QNetworkRequest()
: d(new QNetworkRequestPrivate)
{
+#if QT_CONFIG(http)
+ // Initial values proposed by RFC 7540 are quite draconian,
+ // so unless an application will set its own parameters, we
+ // make stream window size larger and increase (via WINDOW_UPDATE)
+ // the session window size. These are our 'defaults':
+ d->h2Configuration.setStreamReceiveWindowSize(Http2::qtDefaultStreamReceiveWindowSize);
+ d->h2Configuration.setSessionReceiveWindowSize(Http2::maxSessionReceiveWindowSize);
+ d->h2Configuration.setServerPushEnabled(false);
+#endif // QT_CONFIG(http)
}
/*!
@@ -835,6 +858,52 @@ void QNetworkRequest::setPeerVerifyName(const QString &peerName)
d->peerVerifyName = peerName;
}
+#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+/*!
+ \since 5.14
+
+ Returns the current parameters that QNetworkAccessManager is
+ using for this request and its underlying HTTP/2 connection.
+ This is either a configuration previously set by an application
+ or a default configuration.
+
+ The default values that QNetworkAccessManager is using are:
+
+ \list
+ \li Window size for connection-level flowcontrol is 2147483647 octets
+ \li Window size for stream-level flowcontrol is 21474836 octets
+ \li Max frame size is 16384
+ \endlist
+
+ By default, server push is disabled, Huffman compression and
+ string indexing are enabled.
+
+ \sa setHttp2Configuration
+*/
+QHttp2Configuration QNetworkRequest::http2Configuration() const
+{
+ return d->h2Configuration;
+}
+
+/*!
+ \since 5.14
+
+ Sets request's HTTP/2 parameters from \a configuration.
+
+ \note The configuration must be set prior to making a request.
+ \note HTTP/2 multiplexes several streams in a single HTTP/2
+ connection. This implies that QNetworkAccessManager will use
+ the configuration found in the first request from a series
+ of requests sent to the same host.
+
+ \sa http2Configuration, QNetworkAccessManager, QHttp2Configuration
+*/
+void QNetworkRequest::setHttp2Configuration(const QHttp2Configuration &configuration)
+{
+ d->h2Configuration = configuration;
+}
+#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
{
switch (header) {
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index 8ad4ab41c0..e09ff8aaae 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -49,6 +49,7 @@
QT_BEGIN_NAMESPACE
class QSslConfiguration;
+class QHttp2Configuration;
class QNetworkRequestPrivate;
class Q_NETWORK_EXPORT QNetworkRequest
@@ -175,6 +176,10 @@ public:
QString peerVerifyName() const;
void setPeerVerifyName(const QString &peerName);
+#if QT_CONFIG(http) || defined(Q_CLANG_QDOC)
+ QHttp2Configuration http2Configuration() const;
+ void setHttp2Configuration(const QHttp2Configuration &configuration);
+#endif // QT_CONFIG(http) || defined(Q_CLANG_QDOC)
private:
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice.cpp b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
index 07ef60c5ff..d9d76c1146 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice.cpp
+++ b/src/platformsupport/kmsconvenience/qkmsdevice.cpp
@@ -854,6 +854,8 @@ void QKmsDevice::discoverPlanes()
plane.crtcYPropertyId = prop->prop_id;
} else if (!strcasecmp(prop->name, "zpos")) {
plane.zposPropertyId = prop->prop_id;
+ } else if (!strcasecmp(prop->name, "blend_op")) {
+ plane.blendOpPropertyId = prop->prop_id;
}
});
diff --git a/src/platformsupport/kmsconvenience/qkmsdevice_p.h b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
index 403972fbb8..77070c293d 100644
--- a/src/platformsupport/kmsconvenience/qkmsdevice_p.h
+++ b/src/platformsupport/kmsconvenience/qkmsdevice_p.h
@@ -178,6 +178,7 @@ struct QKmsPlane
uint32_t crtcwidthPropertyId = 0;
uint32_t crtcheightPropertyId = 0;
uint32_t zposPropertyId = 0;
+ uint32_t blendOpPropertyId = 0;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QKmsPlane::Rotations)
diff --git a/src/plugins/bearer/android/jar/jar.pro b/src/plugins/bearer/android/jar/jar.pro
index f988019dac..8277a8abc1 100644
--- a/src/plugins/bearer/android/jar/jar.pro
+++ b/src/plugins/bearer/android/jar/jar.pro
@@ -1,3 +1,5 @@
+CONFIG += single_arch
+
TARGET = QtAndroidBearer
load(qt_build_paths)
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
index 0fb21df1d3..1f1675e490 100644
--- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp
@@ -492,6 +492,8 @@ inline my_jpeg_destination_mgr::my_jpeg_destination_mgr(QIODevice *device)
free_in_buffer = max_buf;
}
+static constexpr int maxMarkerSize = 65533;
+
static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QString &description)
{
const QMap<QString, QString> text = qt_getImageText(image, description);
@@ -500,12 +502,33 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt
if (!comment.isEmpty())
comment += ": ";
comment += it.value().toUtf8();
- if (comment.length() > 65530)
- comment.truncate(65530);
+ if (comment.length() > maxMarkerSize)
+ comment.truncate(maxMarkerSize);
jpeg_write_marker(cinfo, JPEG_COM, (const JOCTET *)comment.constData(), comment.size());
}
}
+static inline void write_icc_profile(const QImage &image, j_compress_ptr cinfo)
+{
+ const QByteArray iccProfile = image.colorSpace().iccProfile();
+ if (iccProfile.isEmpty())
+ return;
+
+ const QByteArray iccSignature("ICC_PROFILE", 12);
+ constexpr int maxIccMarkerSize = maxMarkerSize - (12 + 2);
+ int index = 0;
+ const int markers = (iccProfile.size() + (maxIccMarkerSize - 1)) / maxIccMarkerSize;
+ Q_ASSERT(markers < 256);
+ for (int marker = 1; marker <= markers; ++marker) {
+ const int len = std::min(iccProfile.size() - index, maxIccMarkerSize);
+ const QByteArray block = iccSignature
+ + QByteArray(1, char(marker)) + QByteArray(1, char(markers))
+ + iccProfile.mid(index, len);
+ jpeg_write_marker(cinfo, JPEG_APP0 + 2, reinterpret_cast<const JOCTET *>(block.constData()), block.size());
+ index += len;
+ }
+}
+
static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description, bool optimize, bool progressive)
{
bool success = false;
@@ -586,6 +609,8 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in
jpeg_start_compress(&cinfo, TRUE);
set_text(image, &cinfo, description);
+ if (cinfo.in_color_space == JCS_RGB)
+ write_icc_profile(image, &cinfo);
row_pointer[0] = new uchar[cinfo.image_width*cinfo.input_components];
int w = cinfo.image_width;
diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
index 09a10bcc9c..2034632fb3 100644
--- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
+++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmscreen.cpp
@@ -331,6 +331,9 @@ void QEglFSKmsGbmScreen::flip()
static int zpos = qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_ZPOS");
if (zpos)
drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->zposPropertyId, zpos);
+ static uint blendOp = uint(qEnvironmentVariableIntValue("QT_QPA_EGLFS_KMS_BLEND_OP"));
+ if (blendOp)
+ drmModeAtomicAddProperty(request, op.eglfs_plane->id, op.eglfs_plane->blendOpPropertyId, blendOp);
}
#endif
} else {
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
index dc7ea08dc5..cb8962d4b8 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
@@ -188,7 +188,7 @@ static QImage::Format determineFormat(const fb_var_screeninfo &info, int depth)
if (memcmp(rgba, rgb888, 3 * sizeof(fb_bitfield)) == 0) {
format = QImage::Format_RGB888;
} else if (memcmp(rgba, bgr888, 3 * sizeof(fb_bitfield)) == 0) {
- format = QImage::Format_RGB888;
+ format = QImage::Format_BGR888;
// pixeltype = BGRPixel;
}
break;
diff --git a/src/plugins/printsupport/cups/qppdprintdevice.cpp b/src/plugins/printsupport/cups/qppdprintdevice.cpp
index ea6336c4d1..90411f2a2c 100644
--- a/src/plugins/printsupport/cups/qppdprintdevice.cpp
+++ b/src/plugins/printsupport/cups/qppdprintdevice.cpp
@@ -41,7 +41,9 @@
#include "qcupsprintersupport_p.h"
+#if QT_CONFIG(mimetype)
#include <QtCore/QMimeDatabase>
+#endif
#include <qdebug.h>
#include "private/qcups_p.h" // Only needed for PDPK_*
diff --git a/src/tools/androiddeployqt/main.cpp b/src/tools/androiddeployqt/main.cpp
index 10bbd59bfb..4c7b8a6917 100644
--- a/src/tools/androiddeployqt/main.cpp
+++ b/src/tools/androiddeployqt/main.cpp
@@ -91,7 +91,7 @@ FILE *openProcess(const QString &command)
#if defined(Q_OS_WIN32)
QString processedCommand = QLatin1Char('\"') + command + QLatin1Char('\"');
#else
- QString processedCommand = command;
+ const QString& processedCommand = command;
#endif
return popen(processedCommand.toLocal8Bit().constData(), QT_POPEN_READ);
@@ -99,7 +99,7 @@ FILE *openProcess(const QString &command)
struct QtDependency
{
- QtDependency(QString rpath, QString apath) : relativePath(rpath), absolutePath(apath) {}
+ QtDependency(const QString &rpath, const QString &apath) : relativePath(rpath), absolutePath(apath) {}
bool operator==(const QtDependency &other) const
{
@@ -127,7 +127,6 @@ struct Options
, sectionsOnly(false)
, protectedAuthenticationPath(false)
, jarSigner(false)
- , gdbServer(Auto)
, installApk(false)
, uninstallApk(false)
{}
@@ -150,7 +149,6 @@ struct Options
bool generateAssetsFileList;
bool build;
bool auxMode;
- bool stripLibraries = true;
ActionTimer timer;
// External tools
@@ -175,22 +173,22 @@ struct Options
// lib c++ path
QString stdCppPath;
- QString stdCppName = QStringLiteral("gnustl_shared");
+ QString stdCppName = QStringLiteral("c++_shared");
// Build information
QString androidPlatform;
- QString architecture;
- QString toolchainVersion;
+ QHash<QString, QString> architectures;
+ QString currentArchitecture;
QString toolchainPrefix;
- QString toolPrefix;
- bool useLLVM = false;
QString ndkHost;
// Package information
DeploymentMechanism deploymentMechanism;
QString packageName;
QStringList extraLibs;
+ QHash<QString, QStringList> archExtraLibs;
QStringList extraPlugins;
+ QHash<QString, QStringList> archExtraPlugins;
// Signing information
bool releasePackage;
@@ -211,25 +209,36 @@ struct Options
bool jarSigner;
QString apkPath;
- // Gdbserver
- TriState gdbServer;
-
// Installation information
bool installApk;
bool uninstallApk;
QString installLocation;
- // Collected information
+ // Per architecture collected information
+ void clear(const QString &arch)
+ {
+ currentArchitecture = arch;
+ }
typedef QPair<QString, QString> BundledFile;
- QList<BundledFile> bundledFiles;
- QList<QtDependency> qtDependencies;
- QStringList localLibs;
+ QHash<QString, QList<BundledFile>> bundledFiles;
+ QHash<QString, QList<QtDependency>> qtDependencies;
+ QHash<QString, QStringList> localLibs;
+ bool usesOpenGL = false;
+
+ // Per package collected information
QStringList localJars;
QStringList initClasses;
QStringList permissions;
QStringList features;
};
+static const QHash<QByteArray, QByteArray> elfArchitecures = {
+ {"aarch64", "arm64-v8a"},
+ {"arm", "armeabi-v7a"},
+ {"i386", "x86"},
+ {"x86_64", "x86_64"}
+};
+
// Copy-pasted from qmake/library/ioutil.cpp
inline static bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
{
@@ -301,6 +310,59 @@ static QString shellQuote(const QString &arg)
return shellQuoteUnix(arg);
}
+QString architecureFromName(const QString &name)
+{
+ QRegExp architecture(QStringLiteral(".*_(.*)\\.so"));
+ if (!architecture.exactMatch(name))
+ return {};
+ return architecture.capturedTexts().last();
+}
+
+QString fileArchitecture(const Options &options, const QString &path)
+{
+ auto arch = architecureFromName(path);
+ if (!arch.isEmpty())
+ return arch;
+
+ QString readElf = QStringLiteral("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath,
+ options.toolchainPrefix,
+ options.ndkHost);
+#if defined(Q_OS_WIN32)
+ readElf += QStringLiteral(".exe");
+#endif
+
+ if (!QFile::exists(readElf)) {
+ fprintf(stderr, "Command does not exist: %s\n", qPrintable(readElf));
+ return {};
+ }
+
+ readElf = QStringLiteral("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(path));
+
+ FILE *readElfCommand = openProcess(readElf);
+ if (!readElfCommand) {
+ fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
+ return {};
+ }
+
+ char buffer[512];
+ while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) {
+ QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
+ QString library;
+ line = line.trimmed();
+ if (line.startsWith("Arch: ")) {
+ auto it = elfArchitecures.find(line.mid(6));
+ pclose(readElfCommand);
+ return it != elfArchitecures.constEnd() ? QString::fromLatin1(it.value()) : QString{};
+ }
+ }
+ pclose(readElfCommand);
+ return {};
+}
+
+bool checkArchitecture(const Options &options, const QString &fileName)
+{
+ return fileArchitecture(options, fileName) == options.currentArchitecture;
+}
void deleteMissingFiles(const Options &options, const QDir &srcDir, const QDir &dstDir)
{
@@ -388,10 +450,6 @@ Options parseOptions()
options.installLocation = arguments.at(++i);
} else if (argument.compare(QLatin1String("--release"), Qt::CaseInsensitive) == 0) {
options.releasePackage = true;
- } else if (argument.compare(QLatin1String("--gdbserver"), Qt::CaseInsensitive) == 0) {
- options.gdbServer = Options::True;
- } else if (argument.compare(QLatin1String("--no-gdbserver"), Qt::CaseInsensitive) == 0) {
- options.gdbServer = Options::False;
} else if (argument.compare(QLatin1String("--jdk"), Qt::CaseInsensitive) == 0) {
if (i + 1 == arguments.size())
options.helpRequested = true;
@@ -462,8 +520,6 @@ Options parseOptions()
options.generateAssetsFileList = false;
} else if (argument.compare(QLatin1String("--aux-mode"), Qt::CaseInsensitive) == 0) {
options.auxMode = true;
- } else if (argument.compare(QLatin1String("--no-strip"), Qt::CaseInsensitive) == 0) {
- options.stripLibraries = false;
}
}
@@ -533,10 +589,6 @@ void printHelp()
" --protected: Keystore has protected authentication path.\n"
" --jarsigner: Force jarsigner usage, otherwise apksigner will be\n"
" used if available.\n"
- " --gdbserver: Adds the gdbserver to the package. By default the gdbserver\n"
- " is bundled for debug pacakges.\n"
- " --no-gdbserver: Prevents the gdbserver from being added to the package\n"
- " By default the gdbserver is bundled for debug pacakges.\n"
" --jdk <path/to/jdk>: Used to find the jarsigner tool when used\n"
" in combination with the --release argument. By default,\n"
" an attempt is made to detect the tool using the JAVA_HOME and\n"
@@ -549,7 +601,6 @@ void printHelp()
" --aux-mode: Operate in auxiliary mode. This will only copy the\n"
" dependencies into the build directory and update the XML templates.\n"
" The project will not be built or installed.\n"
- " --no-strip: Do not strip debug symbols from libraries.\n"
" --apk <path/where/to/copy/the/apk>: Path where to copy the built apk.\n"
" --help: Displays this information.\n\n",
qPrintable(QCoreApplication::arguments().at(0))
@@ -580,9 +631,10 @@ bool alwaysOverwritableFile(const QString &fileName)
|| fileName.endsWith(QLatin1String("/src/org/qtproject/qt5/android/bindings/QtActivity.java")));
}
+
bool copyFileIfNewer(const QString &sourceFileName,
const QString &destinationFileName,
- bool verbose,
+ const Options &options,
bool forceOverwrite = false)
{
if (QFile::exists(destinationFileName)) {
@@ -592,7 +644,7 @@ bool copyFileIfNewer(const QString &sourceFileName,
if (!forceOverwrite
&& sourceFileInfo.lastModified() <= destinationFileInfo.lastModified()
&& !alwaysOverwritableFile(destinationFileName)) {
- if (verbose)
+ if (options.verbose)
fprintf(stdout, " -- Skipping file %s. Same or newer file already in place.\n", qPrintable(sourceFileName));
return true;
} else {
@@ -611,11 +663,10 @@ bool copyFileIfNewer(const QString &sourceFileName,
if (!QFile::exists(destinationFileName) && !QFile::copy(sourceFileName, destinationFileName)) {
fprintf(stderr, "Failed to copy %s to %s.\n", qPrintable(sourceFileName), qPrintable(destinationFileName));
return false;
- } else if (verbose) {
+ } else if (options.verbose) {
fprintf(stdout, " -- Copied %s\n", qPrintable(destinationFileName));
fflush(stdout);
}
-
return true;
}
@@ -666,7 +717,7 @@ QString cleanPackageName(QString packageName)
}
}
if (keywords.contains(word)) {
- packageName.insert(next, QLatin1String("_"));
+ packageName.insert(next, QStringLiteral("_"));
index = next + 1;
} else {
index = next;
@@ -678,7 +729,7 @@ QString cleanPackageName(QString packageName)
QString detectLatestAndroidPlatform(const QString &sdkPath)
{
- QDir dir(sdkPath + QLatin1String("/platforms"));
+ QDir dir(sdkPath + QStringLiteral("/platforms"));
if (!dir.exists()) {
fprintf(stderr, "Directory %s does not exist\n", qPrintable(dir.absolutePath()));
return QString();
@@ -795,53 +846,22 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary"));
- if (applicationBinary.isUndefined()) {
- fprintf(stderr, "No application binary defined in json file.\n");
- return false;
- }
- options->applicationBinary = applicationBinary.toString();
-
- if (!QFile::exists(options->applicationBinary)) {
- fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary));
+ const QJsonObject targetArchitectures = jsonObject.value(QStringLiteral("architectures")).toObject();
+ if (targetArchitectures.isEmpty()) {
+ fprintf(stderr, "No target architecture defined in json file.\n");
return false;
}
- }
-
- {
- const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies"));
- if (!deploymentDependencies.isUndefined()) {
- QString deploymentDependenciesString = deploymentDependencies.toString();
- const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(','));
- for (const QStringRef &dependency : dependencies) {
- QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency;
- if (QFileInfo(path).isDir()) {
- QDirIterator iterator(path, QDirIterator::Subdirectories);
- while (iterator.hasNext()) {
- iterator.next();
- if (iterator.fileInfo().isFile()) {
- QString subPath = iterator.filePath();
- options->qtDependencies.append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1),
- subPath));
- }
- }
- } else {
- options->qtDependencies.append(QtDependency(dependency.toString(), path));
- }
+ for (auto it = targetArchitectures.constBegin(); it != targetArchitectures.constEnd(); ++it) {
+ if (it.value().isUndefined()) {
+ fprintf(stderr, "Invalid architecure.\n");
+ return false;
}
+ if (it.value().isNull())
+ continue;
+ options->architectures.insert(it.key(), it.value().toString());
}
}
-
- {
- const QJsonValue targetArchitecture = jsonObject.value(QStringLiteral("target-architecture"));
- if (targetArchitecture.isUndefined()) {
- fprintf(stderr, "No target architecture defined in json file.\n");
- return false;
- }
- options->architecture = targetArchitecture.toString();
- }
-
{
const QJsonValue ndk = jsonObject.value(QStringLiteral("ndk"));
if (ndk.isUndefined()) {
@@ -852,11 +872,6 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue value = jsonObject.value(QStringLiteral("useLLVM"));
- options->useLLVM = value.toBool(false);
- }
-
- {
const QJsonValue toolchainPrefix = jsonObject.value(QStringLiteral("toolchain-prefix"));
if (toolchainPrefix.isUndefined()) {
fprintf(stderr, "No toolchain prefix defined in json file.\n");
@@ -866,25 +881,6 @@ bool readInputFile(Options *options)
}
{
- const QJsonValue toolPrefix = jsonObject.value(QStringLiteral("tool-prefix"));
- if (toolPrefix.isUndefined()) {
- fprintf(stderr, "Warning: No tool prefix defined in json file.\n");
- options->toolPrefix = options->toolchainPrefix;
- } else {
- options->toolPrefix = toolPrefix.toString();
- }
- }
-
- if (!options->useLLVM) {
- const QJsonValue toolchainVersion = jsonObject.value(QStringLiteral("toolchain-version"));
- if (toolchainVersion.isUndefined()) {
- fprintf(stderr, "No toolchain version defined in json file.\n");
- return false;
- }
- options->toolchainVersion = toolchainVersion.toString();
- }
-
- {
const QJsonValue ndkHost = jsonObject.value(QStringLiteral("ndk-host"));
if (ndkHost.isUndefined()) {
fprintf(stderr, "No NDK host defined in json file.\n");
@@ -893,10 +889,6 @@ bool readInputFile(Options *options)
options->ndkHost = ndkHost.toString();
}
- options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QLatin1String("/AndroidManifest.xml"));
- if (options->packageName.isEmpty())
- options->packageName = cleanPackageName(QString::fromLatin1("org.qtproject.example.%1").arg(QFileInfo(options->applicationBinary).baseName().mid(sizeof("lib") - 1)));
-
{
const QJsonValue extraLibs = jsonObject.value(QStringLiteral("android-extra-libs"));
if (!extraLibs.isUndefined())
@@ -916,12 +908,6 @@ bool readInputFile(Options *options)
return false;
}
options->stdCppPath = stdcppPath.toString();
- auto name = QFileInfo(options->stdCppPath).baseName();
- if (!name.startsWith(QLatin1String("lib"))) {
- fprintf(stderr, "Invalid STD C++ library name.\n");
- return false;
- }
- options->stdCppName = name.mid(3);
}
{
@@ -935,10 +921,68 @@ bool readInputFile(Options *options)
if (!qmlImportPaths.isUndefined())
options->qmlImportPaths = qmlImportPaths.toString().split(QLatin1Char(','));
}
+
+ {
+ const QJsonValue applicationBinary = jsonObject.value(QStringLiteral("application-binary"));
+ if (applicationBinary.isUndefined()) {
+ fprintf(stderr, "No application binary defined in json file.\n");
+ return false;
+ }
+ options->applicationBinary = applicationBinary.toString();
+ if (options->build) {
+ for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) {
+ if (!QFile::exists(QStringLiteral("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, it.key(), options->applicationBinary))) {
+ fprintf(stderr, "Cannot find application binary %s.\n", qPrintable(options->applicationBinary));
+ return false;
+ }
+ }
+ }
+ }
+
+ {
+ const QJsonValue deploymentDependencies = jsonObject.value(QStringLiteral("deployment-dependencies"));
+ if (!deploymentDependencies.isUndefined()) {
+ QString deploymentDependenciesString = deploymentDependencies.toString();
+ const auto dependencies = deploymentDependenciesString.splitRef(QLatin1Char(','));
+ for (const QStringRef &dependency : dependencies) {
+ QString path = options->qtInstallDirectory + QLatin1Char('/') + dependency;
+ if (QFileInfo(path).isDir()) {
+ QDirIterator iterator(path, QDirIterator::Subdirectories);
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.fileInfo().isFile()) {
+ QString subPath = iterator.filePath();
+ auto arch = fileArchitecture(*options, subPath);
+ if (!arch.isEmpty()) {
+ options->qtDependencies[arch].append(QtDependency(subPath.mid(options->qtInstallDirectory.length() + 1),
+ subPath));
+ } else if (options->verbose) {
+ fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(subPath));
+ fflush(stderr);
+ }
+ }
+ }
+ } else {
+ auto arch = fileArchitecture(*options, path);
+ if (!arch.isEmpty()) {
+ options->qtDependencies[arch].append(QtDependency(dependency.toString(), path));
+ } else if (options->verbose) {
+ fprintf(stderr, "Skipping \"%s\", unknown architecture\n", qPrintable(path));
+ fflush(stderr);
+ }
+ }
+ }
+ }
+ }
+
+ options->packageName = packageNameFromAndroidManifest(options->androidSourceDirectory + QStringLiteral("/AndroidManifest.xml"));
+ if (options->packageName.isEmpty())
+ options->packageName = cleanPackageName(QStringLiteral("org.qtproject.example.%1").arg(options->applicationBinary));
+
return true;
}
-bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bool verbose, bool forceOverwrite = false)
+bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, const Options &options, bool forceOverwrite = false)
{
const QFileInfoList entries = sourceDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
for (const QFileInfo &entry : entries) {
@@ -949,11 +993,11 @@ bool copyFiles(const QDir &sourceDirectory, const QDir &destinationDirectory, bo
return false;
}
- if (!copyFiles(dir, QDir(destinationDirectory.path() + QLatin1String("/") + dir.dirName()), verbose, forceOverwrite))
+ if (!copyFiles(dir, QDir(destinationDirectory.path() + QStringLiteral("/") + dir.dirName()), options, forceOverwrite))
return false;
} else {
QString destination = destinationDirectory.absoluteFilePath(entry.fileName());
- if (!copyFileIfNewer(entry.absoluteFilePath(), destination, verbose, forceOverwrite))
+ if (!copyFileIfNewer(entry.absoluteFilePath(), destination, options, forceOverwrite))
return false;
}
}
@@ -993,7 +1037,7 @@ bool copyAndroidTemplate(const Options &options, const QString &androidTemplate,
return false;
}
- return copyFiles(sourceDirectory, QDir(outDir), options.verbose);
+ return copyFiles(sourceDirectory, QDir(outDir), options);
}
bool copyGradleTemplate(const Options &options)
@@ -1010,7 +1054,7 @@ bool copyGradleTemplate(const Options &options)
return false;
}
- return copyFiles(sourceDirectory, QDir(outDir), options.verbose);
+ return copyFiles(sourceDirectory, QDir(outDir), options);
}
bool copyAndroidTemplate(const Options &options)
@@ -1041,38 +1085,42 @@ bool copyAndroidSources(const Options &options)
return false;
}
- return copyFiles(sourceDirectory, QDir(options.outputDirectory), options.verbose, true);
+ return copyFiles(sourceDirectory, QDir(options.outputDirectory), options, true);
}
-bool copyAndroidExtraLibs(const Options &options)
+bool copyAndroidExtraLibs(Options *options)
{
- if (options.extraLibs.isEmpty())
+ if (options->extraLibs.isEmpty())
return true;
- if (options.verbose)
- fprintf(stdout, "Copying %d external libraries to package.\n", options.extraLibs.size());
+ if (options->verbose)
+ fprintf(stdout, "Copying %d external libraries to package.\n", options->extraLibs.size());
- for (const QString &extraLib : options.extraLibs) {
+ for (const QString &extraLib : options->extraLibs) {
QFileInfo extraLibInfo(extraLib);
if (!extraLibInfo.exists()) {
fprintf(stderr, "External library %s does not exist!\n", qPrintable(extraLib));
return false;
}
-
- if (!extraLibInfo.fileName().startsWith(QLatin1String("lib")) || extraLibInfo.suffix() != QLatin1String("so")) {
+ if (!checkArchitecture(*options, extraLibInfo.filePath())) {
+ if (options->verbose)
+ fprintf(stdout, "Skipping \"%s\", architecture mismatch.\n", qPrintable(extraLib));
+ continue;
+ }
+ if (!extraLibInfo.fileName().startsWith(QStringLiteral("lib")) || extraLibInfo.suffix() != QStringLiteral("so")) {
fprintf(stderr, "The file name of external library %s must begin with \"lib\" and end with the suffix \".so\".\n",
qPrintable(extraLib));
return false;
}
-
- QString destinationFile(options.outputDirectory
- + QLatin1String("/libs/")
- + options.architecture
+ QString destinationFile(options->outputDirectory
+ + QStringLiteral("/libs/")
+ + options->currentArchitecture
+ QLatin1Char('/')
+ extraLibInfo.fileName());
- if (!copyFileIfNewer(extraLib, destinationFile, options.verbose))
+ if (!copyFileIfNewer(extraLib, destinationFile, *options))
return false;
+ options->archExtraLibs[options->currentArchitecture] += extraLib;
}
return true;
@@ -1093,15 +1141,15 @@ QStringList allFilesInside(const QDir& current, const QDir& rootDir)
return result;
}
-bool copyAndroidExtraResources(const Options &options)
+bool copyAndroidExtraResources(Options *options)
{
- if (options.extraPlugins.isEmpty())
+ if (options->extraPlugins.isEmpty())
return true;
- if (options.verbose)
- fprintf(stdout, "Copying %d external resources to package.\n", options.extraPlugins.size());
+ if (options->verbose)
+ fprintf(stdout, "Copying %d external resources to package.\n", options->extraPlugins.size());
- for (const QString &extraResource : options.extraPlugins) {
+ for (const QString &extraResource : options->extraPlugins) {
QFileInfo extraResourceInfo(extraResource);
if (!extraResourceInfo.exists() || !extraResourceInfo.isDir()) {
fprintf(stderr, "External resource %s does not exist or not a correct directory!\n", qPrintable(extraResource));
@@ -1109,20 +1157,22 @@ bool copyAndroidExtraResources(const Options &options)
}
QDir resourceDir(extraResource);
- QString assetsDir = options.outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/');
- QString libsDir = options.outputDirectory + QStringLiteral("/libs/") + options.architecture + QLatin1Char('/');
+ QString assetsDir = options->outputDirectory + QStringLiteral("/assets/") + resourceDir.dirName() + QLatin1Char('/');
+ QString libsDir = options->outputDirectory + QStringLiteral("/libs/") + options->currentArchitecture + QLatin1Char('/');
const QStringList files = allFilesInside(resourceDir, resourceDir);
for (const QString &resourceFile : files) {
QString originFile(resourceDir.filePath(resourceFile));
QString destinationFile;
- if (!resourceFile.endsWith(QLatin1String(".so"))) {
+ if (!resourceFile.endsWith(QStringLiteral(".so"))) {
destinationFile = assetsDir + resourceFile;
} else {
+ if (!checkArchitecture(*options, originFile))
+ continue;
destinationFile = libsDir + QStringLiteral("/lib") + QString(resourceDir.dirName() + QLatin1Char('/') + resourceFile).replace(QLatin1Char('/'), QLatin1Char('_'));
+ options->archExtraPlugins[options->currentArchitecture] += resourceFile;
}
-
- if (!copyFileIfNewer(originFile, destinationFile, options.verbose))
+ if (!copyFileIfNewer(originFile, destinationFile, *options))
return false;
}
}
@@ -1174,75 +1224,118 @@ bool updateFile(const QString &fileName, const QHash<QString, QString> &replacem
}
-bool updateLibsXml(const Options &options)
+bool updateLibsXml(Options *options)
{
- if (options.verbose)
+ if (options->verbose)
fprintf(stdout, " -- res/values/libs.xml\n");
- QString fileName = options.outputDirectory + QLatin1String("/res/values/libs.xml");
+ QString fileName = options->outputDirectory + QStringLiteral("/res/values/libs.xml");
if (!QFile::exists(fileName)) {
fprintf(stderr, "Cannot find %s in prepared packaged. This file is required.\n", qPrintable(fileName));
return false;
}
- QString libsPath = QLatin1String("libs/") + options.architecture + QLatin1Char('/');
-
- QString qtLibs = QLatin1String("<item>") + options.stdCppName + QLatin1String("</item>\n");
+ QString qtLibs;
QString bundledInLibs;
QString bundledInAssets;
- for (const Options::BundledFile &bundledFile : options.bundledFiles) {
- if (bundledFile.second.startsWith(QLatin1String("lib/"))) {
- QString s = bundledFile.second.mid(sizeof("lib/lib") - 1);
- s.chop(sizeof(".so") - 1);
- qtLibs += QString::fromLatin1("<item>%1</item>\n").arg(s);
- } else if (bundledFile.first.startsWith(libsPath)) {
- QString s = bundledFile.first.mid(libsPath.length());
- bundledInLibs += QString::fromLatin1("<item>%1:%2</item>\n")
- .arg(s).arg(bundledFile.second);
- } else if (bundledFile.first.startsWith(QLatin1String("assets/"))) {
- QString s = bundledFile.first.mid(sizeof("assets/") - 1);
- bundledInAssets += QString::fromLatin1("<item>%1:%2</item>\n")
- .arg(s).arg(bundledFile.second);
+ QString allLocalLibs;
+ QString extraLibs;
+
+ for (auto it = options->architectures.constBegin(); it != options->architectures.constEnd(); ++it) {
+ QString libsPath = QStringLiteral("libs/") + it.key() + QLatin1Char('/');
+
+ qtLibs += QStringLiteral(" <item>%1;%2</item>\n").arg(it.key(), options->stdCppName);
+ for (const Options::BundledFile &bundledFile : options->bundledFiles[it.key()]) {
+ if (bundledFile.second.startsWith(QStringLiteral("lib/"))) {
+ QString s = bundledFile.second.mid(sizeof("lib/lib") - 1);
+ s.chop(sizeof(".so") - 1);
+ qtLibs += QStringLiteral(" <item>%1;%2</item>\n").arg(it.key(), s);
+ } else if (bundledFile.first.startsWith(libsPath)) {
+ QString s = bundledFile.first.mid(libsPath.length());
+ bundledInLibs += QString::fromLatin1(" <item>%1;%2:%3</item>\n")
+ .arg(it.key(), s, bundledFile.second);
+ } else if (bundledFile.first.startsWith(QStringLiteral("assets/"))) {
+ QString s = bundledFile.first.mid(sizeof("assets/") - 1);
+ bundledInAssets += QString::fromLatin1(" <item>%1:%2</item>\n")
+ .arg(s).arg(bundledFile.second);
+ }
}
- }
- if (!options.extraPlugins.isEmpty()) {
- for (const QString &extraRes : options.extraPlugins) {
- QDir resourceDir(extraRes);
- const QStringList files = allFilesInside(resourceDir, resourceDir);
- for (const QString &file : files) {
- QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file;
- if (!file.endsWith(QLatin1String(".so"))) {
- bundledInAssets += QStringLiteral("<item>%1:%1</item>\n")
- .arg(destinationPath);
- } else {
- bundledInLibs += QStringLiteral("<item>lib%1:%2</item>\n")
- .arg(QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')))
- .arg(destinationPath);
+ if (!options->archExtraPlugins[it.key()].isEmpty()) {
+ for (const QString &extraRes : options->archExtraPlugins[it.key()]) {
+ QDir resourceDir(extraRes);
+ const QStringList files = allFilesInside(resourceDir, resourceDir);
+ for (const QString &file : files) {
+ QString destinationPath = resourceDir.dirName() + QLatin1Char('/') + file;
+ if (!file.endsWith(QStringLiteral(".so"))) {
+ bundledInAssets += QStringLiteral(" <item>%1:%1</item>\n")
+ .arg(destinationPath);
+ } else {
+ bundledInLibs += QStringLiteral(" <item>%1;lib%2:%3</item>\n")
+ .arg(it.key(),
+ QString(destinationPath).replace(QLatin1Char('/'), QLatin1Char('_')),
+ destinationPath);
+ }
}
}
}
- }
- QHash<QString, QString> replacements;
- replacements[QLatin1String("<!-- %%INSERT_QT_LIBS%% -->")] = qtLibs;
+ if (!options->archExtraLibs[it.key()].isEmpty()) {
+ for (const QString &extraLib : options->archExtraLibs[it.key()]) {
+ QFileInfo extraLibInfo(extraLib);
+ QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1);
+ name.chop(sizeof(".so") - 1);
+ extraLibs += QStringLiteral(" <item>%1;%2").arg(it.key(), name);
+ }
+ }
- if (options.deploymentMechanism == Options::Bundled) {
- replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_LIB%% -->")] = bundledInLibs;
- replacements[QLatin1String("<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->")] = bundledInAssets;
- }
+ QStringList localLibs;
+ localLibs = options->localLibs[it.key()];
+ // If .pro file overrides dependency detection, we need to see which platform plugin they picked
+ if (localLibs.isEmpty()) {
+ QString plugin;
+ for (const QtDependency &qtDependency : options->qtDependencies[it.key()]) {
+ if (qtDependency.relativePath.endsWith(QStringLiteral("libqtforandroid.so"))
+ || qtDependency.relativePath.endsWith(QStringLiteral("libqtforandroidGL.so"))) {
+ if (!plugin.isEmpty() && plugin != qtDependency.relativePath) {
+ fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n");
+ return false;
+ }
- QString extraLibs;
- if (!options.extraLibs.isEmpty()) {
- for (const QString extraLib : options.extraLibs) {
- QFileInfo extraLibInfo(extraLib);
- QString name = extraLibInfo.fileName().mid(sizeof("lib") - 1);
- name.chop(sizeof(".so") - 1);
+ plugin = qtDependency.relativePath;
+ }
+ if (qtDependency.relativePath.contains(QStringLiteral("libQt5OpenGL"))
+ || qtDependency.relativePath.contains(QStringLiteral("libQt5Quick"))) {
+ options->usesOpenGL |= true;
+ break;
+ }
+ }
- extraLibs += QLatin1String("<item>") + name + QLatin1String("</item>\n");
+ if (plugin.isEmpty()) {
+ fflush(stdout);
+ fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n");
+ fflush(stderr);
+ return false;
+ }
+
+ localLibs.append(plugin);
+ if (options->verbose)
+ fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin));
}
+ allLocalLibs += QStringLiteral(" <item>%1;%2</item>\n").arg(it.key(), localLibs.join(QLatin1Char(':'))
+ .replace(QStringLiteral("lib/"), QString{})
+ .replace(QLatin1Char('/'), QLatin1Char('_')));
+ }
+
+ QHash<QString, QString> replacements;
+ replacements[QStringLiteral("<!-- %%INSERT_QT_LIBS%% -->")] += qtLibs.trimmed();
+ replacements[QStringLiteral("<!-- %%INSERT_LOCAL_LIBS%% -->")] = allLocalLibs.trimmed();
+ replacements[QStringLiteral("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs.trimmed();
+
+ if (options->deploymentMechanism == Options::Bundled) {
+ replacements[QStringLiteral("<!-- %%INSERT_BUNDLED_IN_LIB%% -->")] += bundledInLibs.trimmed();
+ replacements[QStringLiteral("<!-- %%INSERT_BUNDLED_IN_ASSETS%% -->")] += bundledInAssets.trimmed();
}
- replacements[QLatin1String("<!-- %%INSERT_EXTRA_LIBS%% -->")] = extraLibs;
if (!updateFile(fileName, replacements))
return false;
@@ -1256,9 +1349,9 @@ bool updateStringsXml(const Options &options)
fprintf(stdout, " -- res/values/strings.xml\n");
QHash<QString, QString> replacements;
- replacements[QStringLiteral("<!-- %%INSERT_APP_NAME%% -->")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
+ replacements[QStringLiteral("<!-- %%INSERT_APP_NAME%% -->")] = options.applicationBinary;
- QString fileName = options.outputDirectory + QLatin1String("/res/values/strings.xml");
+ QString fileName = options.outputDirectory + QStringLiteral("/res/values/strings.xml");
if (!QFile::exists(fileName)) {
if (options.verbose)
fprintf(stdout, " -- Create strings.xml since it's missing.\n");
@@ -1268,7 +1361,7 @@ bool updateStringsXml(const Options &options)
return false;
}
file.write(QByteArray("<?xml version='1.0' encoding='utf-8'?><resources><string name=\"app_name\" translatable=\"false\">")
- .append(QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1).toLatin1())
+ .append(options.applicationBinary.toLatin1())
.append("</string></resources>\n"));
return true;
}
@@ -1284,71 +1377,34 @@ bool updateAndroidManifest(Options &options)
if (options.verbose)
fprintf(stdout, " -- AndroidManifest.xml \n");
- QStringList localLibs = options.localLibs;
-
- // If .pro file overrides dependency detection, we need to see which platform plugin they picked
- if (localLibs.isEmpty()) {
- QString plugin;
- for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) {
- if (qtDependency.relativePath.endsWith(QLatin1String("libqtforandroid.so"))
- || qtDependency.relativePath.endsWith(QLatin1String("libqtforandroidGL.so"))) {
- if (!plugin.isEmpty() && plugin != qtDependency.relativePath) {
- fprintf(stderr, "Both platform plugins libqtforandroid.so and libqtforandroidGL.so included in package. Please include only one.\n");
- return false;
- }
-
- plugin = qtDependency.relativePath;
- }
- }
-
- if (plugin.isEmpty()) {
- fprintf(stderr, "No platform plugin, neither libqtforandroid.so or libqtforandroidGL.so, included in package. Please include one.\n");
- return false;
- }
-
- localLibs.append(plugin);
- if (options.verbose)
- fprintf(stdout, " -- Using platform plugin %s\n", qPrintable(plugin));
- }
-
- bool usesGL = false;
- for (const QtDependency &qtDependency : qAsConst(options.qtDependencies)) {
- if (qtDependency.relativePath.endsWith(QLatin1String("libQt5OpenGL.so"))
- || qtDependency.relativePath.endsWith(QLatin1String("libQt5Quick.so"))) {
- usesGL = true;
- break;
- }
- }
-
options.localJars.removeDuplicates();
options.initClasses.removeDuplicates();
QHash<QString, QString> replacements;
- replacements[QLatin1String("-- %%INSERT_APP_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
- replacements[QLatin1String("-- %%INSERT_APP_LIB_NAME%% --")] = QFileInfo(options.applicationBinary).baseName().mid(sizeof("lib") - 1);
- replacements[QLatin1String("-- %%INSERT_LOCAL_LIBS%% --")] = localLibs.join(QLatin1Char(':'));
- replacements[QLatin1String("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':'));
- replacements[QLatin1String("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':'));
- replacements[QLatin1String("-- %%INSERT_VERSION_NAME%% --")] = options.versionName;
- replacements[QLatin1String("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode;
- replacements[QLatin1String("package=\"org.qtproject.example\"")] = QString::fromLatin1("package=\"%1\"").arg(options.packageName);
- replacements[QLatin1String("-- %%BUNDLE_LOCAL_QT_LIBS%% --")]
- = (options.deploymentMechanism == Options::Bundled) ? QString::fromLatin1("1") : QString::fromLatin1("0");
- replacements[QLatin1String("-- %%USE_LOCAL_QT_LIBS%% --")]
- = (options.deploymentMechanism != Options::Ministro) ? QString::fromLatin1("1") : QString::fromLatin1("0");
+ replacements[QStringLiteral("-- %%INSERT_APP_NAME%% --")] = options.applicationBinary;
+ replacements[QStringLiteral("-- %%INSERT_APP_LIB_NAME%% --")] = options.applicationBinary;
+ replacements[QStringLiteral("-- %%INSERT_LOCAL_JARS%% --")] = options.localJars.join(QLatin1Char(':'));
+ replacements[QStringLiteral("-- %%INSERT_INIT_CLASSES%% --")] = options.initClasses.join(QLatin1Char(':'));
+ replacements[QStringLiteral("-- %%INSERT_VERSION_NAME%% --")] = options.versionName;
+ replacements[QStringLiteral("-- %%INSERT_VERSION_CODE%% --")] = options.versionCode;
+ replacements[QStringLiteral("package=\"org.qtproject.example\"")] = QStringLiteral("package=\"%1\"").arg(options.packageName);
+ replacements[QStringLiteral("-- %%BUNDLE_LOCAL_QT_LIBS%% --")]
+ = (options.deploymentMechanism == Options::Bundled) ? QStringLiteral("1") : QStringLiteral("0");
+ replacements[QStringLiteral("-- %%USE_LOCAL_QT_LIBS%% --")]
+ = (options.deploymentMechanism != Options::Ministro) ? QStringLiteral("1") : QStringLiteral("0");
QString permissions;
for (const QString &permission : qAsConst(options.permissions))
- permissions += QString::fromLatin1(" <uses-permission android:name=\"%1\" />\n").arg(permission);
- replacements[QLatin1String("<!-- %%INSERT_PERMISSIONS -->")] = permissions;
+ permissions += QStringLiteral(" <uses-permission android:name=\"%1\" />\n").arg(permission);
+ replacements[QStringLiteral("<!-- %%INSERT_PERMISSIONS -->")] = permissions.trimmed();
QString features;
for (const QString &feature : qAsConst(options.features))
features += QStringLiteral(" <uses-feature android:name=\"%1\" android:required=\"false\" />\n").arg(feature);
- if (usesGL)
+ if (options.usesOpenGL)
features += QStringLiteral(" <uses-feature android:glEsVersion=\"0x00020000\" android:required=\"true\" />");
- replacements[QLatin1String("<!-- %%INSERT_FEATURES -->")] = features;
+ replacements[QStringLiteral("<!-- %%INSERT_FEATURES -->")] = features.trimmed();
QString androidManifestPath = options.outputDirectory + QLatin1String("/AndroidManifest.xml");
if (!updateFile(androidManifestPath, replacements))
@@ -1409,7 +1465,7 @@ bool updateAndroidFiles(Options &options)
if (options.verbose)
fprintf(stdout, "Updating Android package files with project settings.\n");
- if (!updateLibsXml(options))
+ if (!updateLibsXml(&options))
return false;
if (!updateAndroidManifest(options))
@@ -1466,7 +1522,7 @@ bool readAndroidDependencyXml(Options *options,
QSet<QString> *usedDependencies,
QSet<QString> *remainingDependencies)
{
- QString androidDependencyName = absoluteFilePath(options, QString::fromLatin1("/lib/%1-android-dependencies.xml").arg(moduleName));
+ QString androidDependencyName = absoluteFilePath(options, QStringLiteral("/lib/%1-android-dependencies.xml").arg(moduleName));
QFile androidDependencyFile(androidDependencyName);
if (androidDependencyFile.exists()) {
@@ -1505,7 +1561,7 @@ bool readAndroidDependencyXml(Options *options,
if (options->verbose)
fprintf(stdout, "Appending dependency from xml: %s\n", qPrintable(fileName.relativePath));
- options->qtDependencies.append(fileName);
+ options->qtDependencies[options->currentArchitecture].append(fileName);
}
} else if (reader.name() == QLatin1String("jar")) {
int bundling = reader.attributes().value(QLatin1String("bundling")).toInt();
@@ -1513,7 +1569,7 @@ bool readAndroidDependencyXml(Options *options,
if (bundling == (options->deploymentMechanism == Options::Bundled)) {
QtDependency dependency(fileName, absoluteFilePath(options, fileName));
if (!usedDependencies->contains(dependency.absolutePath)) {
- options->qtDependencies.append(dependency);
+ options->qtDependencies[options->currentArchitecture].append(dependency);
usedDependencies->insert(dependency.absolutePath);
}
}
@@ -1529,15 +1585,15 @@ bool readAndroidDependencyXml(Options *options,
if (reader.attributes().hasAttribute(QLatin1String("replaces"))) {
QString replaces = reader.attributes().value(QLatin1String("replaces")).toString();
for (int i=0; i<options->localLibs.size(); ++i) {
- if (options->localLibs.at(i) == replaces) {
- options->localLibs[i] = fileName;
+ if (options->localLibs[options->currentArchitecture].at(i) == replaces) {
+ options->localLibs[options->currentArchitecture][i] = fileName;
break;
}
}
} else if (!fileName.isEmpty()) {
- options->localLibs.append(fileName);
+ options->localLibs[options->currentArchitecture].append(fileName);
}
- if (fileName.endsWith(QLatin1String(".so"))) {
+ if (fileName.endsWith(QStringLiteral(".so")) && checkArchitecture(*options, fileName)) {
remainingDependencies->insert(fileName);
}
} else if (reader.name() == QLatin1String("permission")) {
@@ -1557,26 +1613,19 @@ bool readAndroidDependencyXml(Options *options,
} else if (options->verbose) {
fprintf(stdout, "No android dependencies for %s\n", qPrintable(moduleName));
}
+ options->permissions.removeDuplicates();
+ options->features.removeDuplicates();
return true;
}
QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
{
- QString readElf = options.ndkPath
- + QLatin1String("/toolchains/")
- + options.toolchainPrefix;
-
- if (!options.useLLVM)
- readElf += QLatin1Char('-') + options.toolchainVersion;
-
- readElf += QLatin1String("/prebuilt/")
- + options.ndkHost
- + QLatin1String("/bin/")
- + options.toolPrefix +
- (options.useLLVM ? QLatin1String("-readobj") : QLatin1String("-readelf"));
+ QString readElf = QStringLiteral("%1/toolchains/%2/prebuilt/%3/bin/llvm-readobj").arg(options.ndkPath,
+ options.toolchainPrefix,
+ options.ndkHost);
#if defined(Q_OS_WIN32)
- readElf += QLatin1String(".exe");
+ readElf += QStringLiteral(".exe");
#endif
if (!QFile::exists(readElf)) {
@@ -1584,14 +1633,11 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
return QStringList();
}
- if (options.useLLVM)
- readElf = QString::fromLatin1("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName));
- else
- readElf = QString::fromLatin1("%1 -d -W %2").arg(shellQuote(readElf), shellQuote(fileName));
+ readElf = QStringLiteral("%1 -needed-libs %2").arg(shellQuote(readElf), shellQuote(fileName));
FILE *readElfCommand = openProcess(readElf);
if (!readElfCommand) {
- fprintf(stderr, "Cannot execute command %s", qPrintable(readElf));
+ fprintf(stderr, "Cannot execute command %s\n", qPrintable(readElf));
return QStringList();
}
@@ -1599,23 +1645,26 @@ QStringList getQtLibsFromElf(const Options &options, const QString &fileName)
bool readLibs = false;
char buffer[512];
- while (fgets(buffer, sizeof(buffer), readElfCommand) != 0) {
+ while (fgets(buffer, sizeof(buffer), readElfCommand) != nullptr) {
QByteArray line = QByteArray::fromRawData(buffer, qstrlen(buffer));
QString library;
- if (options.useLLVM) {
- line = line.trimmed();
- if (!readLibs) {
- readLibs = line.startsWith("NeededLibraries");
- continue;
+ line = line.trimmed();
+ if (!readLibs) {
+ if (line.startsWith("Arch: ")) {
+ auto it = elfArchitecures.find(line.mid(6));
+ if (it == elfArchitecures.constEnd() || *it != options.currentArchitecture.toLatin1()) {
+ if (options.verbose)
+ fprintf(stdout, "Skipping \"%s\", architecture mismatch\n", qPrintable(fileName));
+ return {};
+ }
}
- if (!line.startsWith("lib"))
- continue;
- library = QString::fromLatin1(line);
- } else if (line.contains("(NEEDED)") && line.contains("Shared library:")) {
- const int pos = line.lastIndexOf('[') + 1;
- library = QString::fromLatin1(line.mid(pos, line.length() - pos - 2));
+ readLibs = line.startsWith("NeededLibraries");
+ continue;
}
- QString libraryName = QLatin1String("lib/") + library;
+ if (!line.startsWith("lib"))
+ continue;
+ library = QString::fromLatin1(line);
+ QString libraryName = QStringLiteral("lib/") + library;
if (QFile::exists(absoluteFilePath(&options, libraryName)))
ret += libraryName;
}
@@ -1653,7 +1702,7 @@ bool readDependenciesFromElf(Options *options,
return false;
}
- options->qtDependencies.append(QtDependency(dependency, absoluteDependencyPath));
+ options->qtDependencies[options->currentArchitecture].append(QtDependency(dependency, absoluteDependencyPath));
if (options->verbose)
fprintf(stdout, "Appending dependency: %s\n", qPrintable(dependency));
dependenciesToCheck.append(dependency);
@@ -1797,10 +1846,10 @@ bool scanImports(Options *options, QSet<QString> *usedDependencies)
fprintf(stdout, " -- Appending dependency found by qmlimportscanner: %s\n", qPrintable(fileName.absolutePath));
// Put all imports in default import path in assets
- fileName.relativePath.prepend(QLatin1String("qml/"));
- options->qtDependencies.append(fileName);
+ fileName.relativePath.prepend(QStringLiteral("qml/"));
+ options->qtDependencies[options->currentArchitecture].append(fileName);
- if (fileName.absolutePath.endsWith(QLatin1String(".so"))) {
+ if (fileName.absolutePath.endsWith(QStringLiteral(".so")) && checkArchitecture(*options, fileName.absolutePath)) {
QSet<QString> remainingDependencies;
if (!readDependenciesFromElf(options, fileName.absolutePath, usedDependencies, &remainingDependencies))
return false;
@@ -1819,7 +1868,7 @@ bool readDependencies(Options *options)
fprintf(stdout, "Detecting dependencies of application.\n");
// Override set in .pro file
- if (!options->qtDependencies.isEmpty()) {
+ if (!options->qtDependencies[options->currentArchitecture].isEmpty()) {
if (options->verbose)
fprintf(stdout, "\tDependencies explicitly overridden in .pro file. No detection needed.\n");
return true;
@@ -1829,11 +1878,7 @@ bool readDependencies(Options *options)
QSet<QString> remainingDependencies;
// Add dependencies of application binary first
- if (!readDependenciesFromElf(options, options->applicationBinary, &usedDependencies, &remainingDependencies))
- return false;
-
- // Jam in the dependencies of the platform plugin, since the application will crash without it
- if (!readDependenciesFromElf(options, options->qtInstallDirectory + QLatin1String("/plugins/platforms/android/libqtforandroid.so"), &usedDependencies, &remainingDependencies))
+ if (!readDependenciesFromElf(options, QStringLiteral("%1/libs/%2/lib%3_%2.so").arg(options->outputDirectory, options->currentArchitecture, options->applicationBinary), &usedDependencies, &remainingDependencies))
return false;
while (!remainingDependencies.isEmpty()) {
@@ -1853,14 +1898,14 @@ bool readDependencies(Options *options)
}
}
- QStringList::iterator it = options->localLibs.begin();
- while (it != options->localLibs.end()) {
+ QStringList::iterator it = options->localLibs[options->currentArchitecture].begin();
+ while (it != options->localLibs[options->currentArchitecture].end()) {
QStringList unmetDependencies;
if (!goodToCopy(options, absoluteFilePath(options, *it), &unmetDependencies)) {
fprintf(stdout, "Skipping %s due to unmet dependencies: %s\n",
qPrintable(*it),
qPrintable(unmetDependencies.join(QLatin1Char(','))));
- it = options->localLibs.erase(it);
+ it = options->localLibs[options->currentArchitecture].erase(it);
} else {
++it;
}
@@ -1872,94 +1917,33 @@ bool readDependencies(Options *options)
return true;
}
-bool stripFile(const Options &options, const QString &fileName)
-{
- QString strip = options.ndkPath
- + QLatin1String("/toolchains/")
- + options.toolchainPrefix;
-
- if (!options.useLLVM)
- strip += QLatin1Char('-') + options.toolchainVersion;
-
- strip += QLatin1String("/prebuilt/")
- + options.ndkHost
- + QLatin1String("/bin/")
- + options.toolPrefix
- + QLatin1String("-strip");
-#if defined(Q_OS_WIN32)
- strip += QLatin1String(".exe");
-#endif
-
- if (!QFile::exists(strip)) {
- fprintf(stderr, "Command does not exist: %s\n", qPrintable(strip));
- return false;
- }
-
- if (options.useLLVM)
- strip = QString::fromLatin1("%1 -strip-all %2").arg(shellQuote(strip), shellQuote(fileName));
- else
- strip = QString::fromLatin1("%1 %2").arg(shellQuote(strip), shellQuote(fileName));
-
- FILE *stripCommand = openProcess(strip);
- if (stripCommand == 0) {
- fprintf(stderr, "Cannot execute command %s", qPrintable(strip));
- return false;
- }
-
- pclose(stripCommand);
-
- return true;
-}
-
-bool stripLibraries(const Options &options)
+bool containsApplicationBinary(Options *options)
{
- if (!options.stripLibraries)
+ if (!options->build)
return true;
- if (options.verbose)
- fprintf(stdout, "Stripping libraries to minimize size.\n");
-
-
- QString libraryPath = options.outputDirectory
- + QLatin1String("/libs/")
- + options.architecture;
- const QStringList libraries = QDir(libraryPath).entryList(QDir::Files);
- for (const QString &library : libraries) {
- if (library.endsWith(QLatin1String(".so"))) {
- if (!stripFile(options, libraryPath + QLatin1Char('/') + library))
- return false;
- }
- }
-
- return true;
-}
-
-bool containsApplicationBinary(const Options &options)
-{
- if (options.verbose)
+ if (options->verbose)
fprintf(stdout, "Checking if application binary is in package.\n");
- QFileInfo applicationBinary(options.applicationBinary);
- QString destinationFileName = options.outputDirectory
- + QLatin1String("/libs/")
- + options.architecture
- + QLatin1Char('/')
- + applicationBinary.fileName();
+ QFileInfo applicationBinary(options->applicationBinary);
+ QString applicationFileName = QStringLiteral("lib%1_%2.so").arg(options->applicationBinary,
+ options->currentArchitecture);
- if (!QFile::exists(destinationFileName)) {
+ QString applicationPath = QStringLiteral("%1/libs/%2/%3").arg(options->outputDirectory,
+ options->currentArchitecture,
+ applicationFileName);
+ if (!QFile::exists(applicationPath)) {
#if defined(Q_OS_WIN32)
QLatin1String makeTool("mingw32-make"); // Only Mingw host builds supported on Windows currently
#else
QLatin1String makeTool("make");
#endif
-
fprintf(stderr, "Application binary is not in output directory: %s. Please run '%s install INSTALL_ROOT=%s' first.\n",
- qPrintable(destinationFileName),
+ qPrintable(applicationFileName),
qPrintable(makeTool),
- qPrintable(options.outputDirectory));
+ qPrintable(options->outputDirectory));
return false;
}
-
return true;
}
@@ -1997,10 +1981,13 @@ bool goodToCopy(const Options *options, const QString &file, QStringList *unmetD
if (!file.endsWith(QLatin1String(".so")))
return true;
+ if (!checkArchitecture(*options, file))
+ return false;
+
bool ret = true;
const auto libs = getQtLibsFromElf(*options, file);
for (const QString &lib : libs) {
- if (!options->qtDependencies.contains(QtDependency(lib, absoluteFilePath(options, lib)))) {
+ if (!options->qtDependencies[options->currentArchitecture].contains(QtDependency(lib, absoluteFilePath(options, lib)))) {
ret = false;
unmetDependencies->append(lib);
}
@@ -2027,25 +2014,22 @@ bool copyQtFiles(Options *options)
QString libsDirectory = QLatin1String("libs/");
+
// Copy other Qt dependencies
- QString libDestinationDirectory = libsDirectory + options->architecture + QLatin1Char('/');
- QString assetsDestinationDirectory = QLatin1String("assets/--Added-by-androiddeployqt--/");
- for (const QtDependency &qtDependency : qAsConst(options->qtDependencies)) {
+ QString assetsDestinationDirectory = QStringLiteral("assets/--Added-by-androiddeployqt--/");
+ for (const QtDependency &qtDependency : qAsConst(options->qtDependencies[options->currentArchitecture])) {
QString sourceFileName = qtDependency.absolutePath;
QString destinationFileName;
- if (qtDependency.relativePath.endsWith(QLatin1String(".so"))) {
+ if (qtDependency.relativePath.endsWith(QStringLiteral(".so"))) {
QString garbledFileName;
- if (qtDependency.relativePath.startsWith(QLatin1String("lib/"))) {
+ if (qtDependency.relativePath.startsWith(QStringLiteral("lib/"))) {
garbledFileName = qtDependency.relativePath.mid(sizeof("lib/") - 1);
} else {
- garbledFileName = QLatin1String("lib")
- + QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_'));
-
+ garbledFileName = QString(qtDependency.relativePath).replace(QLatin1Char('/'), QLatin1Char('_'));
}
- destinationFileName = libDestinationDirectory + garbledFileName;
-
- } else if (qtDependency.relativePath.startsWith(QLatin1String("jar/"))) {
+ destinationFileName = libsDirectory + options->currentArchitecture + QLatin1Char('/') + garbledFileName;
+ } else if (qtDependency.relativePath.startsWith(QStringLiteral("jar/"))) {
destinationFileName = libsDirectory + qtDependency.relativePath.mid(sizeof("jar/") - 1);
} else {
destinationFileName = assetsDestinationDirectory + qtDependency.relativePath;
@@ -2058,20 +2042,34 @@ bool copyQtFiles(Options *options)
QStringList unmetDependencies;
if (!goodToCopy(options, sourceFileName, &unmetDependencies)) {
- fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n",
- qPrintable(sourceFileName),
- qPrintable(unmetDependencies.join(QLatin1Char(','))));
+ if (unmetDependencies.isEmpty()) {
+ if (options->verbose) {
+ fprintf(stdout, " -- Skipping %s, architecture mismatch.\n",
+ qPrintable(sourceFileName));
+ }
+ } else {
+ if (unmetDependencies.isEmpty()) {
+ if (options->verbose) {
+ fprintf(stdout, " -- Skipping %s, architecture mismatch.\n",
+ qPrintable(sourceFileName));
+ }
+ } else {
+ fprintf(stdout, " -- Skipping %s. It has unmet dependencies: %s.\n",
+ qPrintable(sourceFileName),
+ qPrintable(unmetDependencies.join(QLatin1Char(','))));
+ }
+ }
continue;
}
if (options->deploymentMechanism == Options::Bundled
&& !copyFileIfNewer(sourceFileName,
options->outputDirectory + QLatin1Char('/') + destinationFileName,
- options->verbose)) {
+ *options)) {
return false;
}
- options->bundledFiles += qMakePair(destinationFileName, qtDependency.relativePath);
+ options->bundledFiles[options->currentArchitecture] += qMakePair(destinationFileName, qtDependency.relativePath);
}
return true;
@@ -2409,21 +2407,18 @@ bool copyStdCpp(Options *options)
if (options->verbose)
fprintf(stdout, "Copying STL library\n");
- if (!QFile::exists(options->stdCppPath)) {
- fprintf(stderr, "STL library does not exist at %s\n", qPrintable(options->stdCppPath));
- return false;
- }
-
- const QString destinationDirectory = options->outputDirectory
- + QLatin1String("/libs/") + options->architecture;
-
- if (!copyFileIfNewer(options->stdCppPath, destinationDirectory + QLatin1String("/lib")
- + options->stdCppName + QLatin1String(".so"),
- options->verbose)) {
+ QString stdCppPath = QStringLiteral("%1/%2/lib%3.so").arg(options->stdCppPath, options->architectures[options->currentArchitecture], options->stdCppName);
+ if (!QFile::exists(stdCppPath)) {
+ fprintf(stderr, "STL library does not exist at %s\n", qPrintable(stdCppPath));
+ fflush(stdout);
+ fflush(stderr);
return false;
}
- return true;
+ const QString destinationFile = QStringLiteral("%1/libs/%2/lib%3.so").arg(options->outputDirectory,
+ options->currentArchitecture,
+ options->stdCppName);
+ return copyFileIfNewer(stdCppPath, destinationFile, *options);
}
bool jarSignerSignPackage(const Options &options)
@@ -2654,55 +2649,6 @@ bool signPackage(const Options &options)
return apkSignerRunner() && QFile::remove(apkPath(options, UnsignedAPK));
}
-bool copyGdbServer(const Options &options)
-{
- if (options.verbose)
- fprintf(stdout, "Copying gdbserver into package.\n");
-
- QString architectureSubDirectory;
- if (options.architecture == QLatin1String("arm64-v8a"))
- architectureSubDirectory = QLatin1String("android-arm64");
- else if (options.architecture.startsWith(QLatin1String("arm")))
- architectureSubDirectory = QLatin1String("android-arm");
- else
- architectureSubDirectory = QLatin1String("android-") + options.architecture;
-
- QString gdbServerBinary = options.ndkPath
- + QLatin1String("/prebuilt/")
- + architectureSubDirectory
- + QLatin1String("/gdbserver/gdbserver");
- if (!QFile::exists(gdbServerBinary)) {
- fprintf(stderr, "Cannot find gdbserver at %s.\n", qPrintable(gdbServerBinary));
- return false;
- }
-
- QString gdbServerTarget = options.outputDirectory + QLatin1String("/libs/") + options.architecture;
-
- if (!copyFileIfNewer(gdbServerBinary,
- gdbServerTarget + QLatin1String("/gdbserver"),
- options.verbose)
- || !copyFileIfNewer(gdbServerBinary,
- gdbServerTarget + QLatin1String("/libgdbserver.so"),
- options.verbose)) {
- return false;
- }
-
- QString addedByAndroidDeployQtPath = options.outputDirectory + QLatin1String("/assets/--Added-by-androiddeployqt--/");
- if (!QDir().mkpath(addedByAndroidDeployQtPath)) {
- fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath));
- return false;
- }
- QFile f(addedByAndroidDeployQtPath + QLatin1String("debugger.command"));
- if (!f.open(QIODevice::WriteOnly)) {
- fprintf(stderr, "Failed to create directory '%s'", qPrintable(addedByAndroidDeployQtPath));
- return false;
- }
- f.write("lib/libgdbserver.so --multi +");
- f.close();
-
- return true;
-}
-
bool generateAssetsFileList(const Options &options)
{
if (options.verbose)
@@ -2764,8 +2710,6 @@ enum ErrorCode
CannotCopyGnuStl = 5,
CannotCopyQtFiles = 6,
CannotFindApplicationBinary = 7,
- CannotCopyGdbServer = 8,
- CannotStripLibraries = 9,
CannotCopyAndroidExtraLibs = 10,
CannotCopyAndroidSources = 11,
CannotUpdateAndroidFiles = 12,
@@ -2813,25 +2757,7 @@ int main(int argc, char *argv[])
: "No"
);
- if (options.auxMode) {
- if (!readDependencies(&options))
- return CannotReadDependencies;
- if (!copyQtFiles(&options))
- return CannotCopyQtFiles;
- if (!copyAndroidExtraResources(options))
- return CannotCopyAndroidExtraResources;
- if (!copyAndroidExtraLibs(options))
- return CannotCopyAndroidExtraLibs;
- if (!stripLibraries(options))
- return CannotStripLibraries;
- if (!updateAndroidFiles(options))
- return CannotUpdateAndroidFiles;
- if (options.generateAssetsFileList && !generateAssetsFileList(options))
- return CannotGenerateAssetsFileList;
- return 0;
- }
-
- if (options.build) {
+ if (options.build && !options.auxMode) {
cleanAndroidFiles(options);
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %d ms: Cleaned Android file\n", options.timer.elapsed());
@@ -2843,60 +2769,68 @@ int main(int argc, char *argv[])
fprintf(stdout, "[TIMING] %d ms: Copied Android template\n", options.timer.elapsed());
}
- if (!readDependencies(&options))
- return CannotReadDependencies;
-
- if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed());
+ for (auto it = options.architectures.constBegin(); it != options.architectures.constEnd(); ++it) {
+ options.clear(it.key());
- if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options))
- return CannotCopyGnuStl;
+ if (!readDependencies(&options))
+ return CannotReadDependencies;
- if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed());
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Read dependencies\n", options.timer.elapsed());
- if (!copyQtFiles(&options))
- return CannotCopyQtFiles;
+ if (!copyQtFiles(&options))
+ return CannotCopyQtFiles;
- if (options.build) {
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %d ms: Copied Qt files\n", options.timer.elapsed());
- if (!containsApplicationBinary(options))
- return CannotFindApplicationBinary;
+ if (!copyAndroidExtraLibs(&options))
+ return CannotCopyAndroidExtraLibs;
if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed());
+ fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed());
- bool needToCopyGdbServer = options.gdbServer == Options::True
- || (options.gdbServer == Options::Auto && !options.releasePackage);
- if (needToCopyGdbServer && !copyGdbServer(options))
- return CannotCopyGdbServer;
+ if (!copyAndroidExtraResources(&options))
+ return CannotCopyAndroidExtraResources;
if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Copied GDB server\n", options.timer.elapsed());
+ fprintf(stdout, "[TIMING] %d ms: Copied extra resources\n", options.timer.elapsed());
- if (!copyAndroidExtraLibs(options))
- return CannotCopyAndroidExtraLibs;
+ if (!options.auxMode) {
+ if (options.deploymentMechanism != Options::Ministro && !copyStdCpp(&options))
+ return CannotCopyGnuStl;
+
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Copied GNU STL\n", options.timer.elapsed());
+ }
+
+ if (!containsApplicationBinary(&options))
+ return CannotFindApplicationBinary;
if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Copied extra libs\n", options.timer.elapsed());
+ fprintf(stdout, "[TIMING] %d ms: Checked for application binary\n", options.timer.elapsed());
- if (!copyAndroidExtraResources(options))
- return CannotCopyAndroidExtraResources;
+ if (options.deploymentMechanism != Options::Ministro) {
+ if (Q_UNLIKELY(options.timing))
+ fprintf(stdout, "[TIMING] %d ms: Bundled Qt libs\n", options.timer.elapsed());
+ }
+ }
+ if (options.auxMode) {
+ if (!updateAndroidFiles(options))
+ return CannotUpdateAndroidFiles;
+ if (options.generateAssetsFileList && !generateAssetsFileList(options))
+ return CannotGenerateAssetsFileList;
+ return 0;
+ }
+
+ if (options.build) {
if (!copyAndroidSources(options))
return CannotCopyAndroidSources;
if (Q_UNLIKELY(options.timing))
fprintf(stdout, "[TIMING] %d ms: Copied android sources\n", options.timer.elapsed());
- if (!stripLibraries(options))
- return CannotStripLibraries;
-
- if (Q_UNLIKELY(options.timing))
- fprintf(stdout, "[TIMING] %d ms: Stripped libraries\n", options.timer.elapsed());
-
if (!updateAndroidFiles(options))
return CannotUpdateAndroidFiles;
diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp
index e6d6f72354..f61d407d4a 100644
--- a/src/tools/androidtestrunner/main.cpp
+++ b/src/tools/androidtestrunner/main.cpp
@@ -362,7 +362,7 @@ static bool parseTestArgs()
g_options.testArgs += QStringLiteral(" -o output.%1,%1").arg(format);
g_options.testArgs += unhandledArgs;
- g_options.testArgs = QStringLiteral("shell am start -e applicationArguments \"'%1'\" -n %2/%3").arg(shellQuote(g_options.testArgs.trimmed()),
+ g_options.testArgs = QStringLiteral("shell am start -e applicationArguments \\\"%1\\\" -n %2/%3").arg(shellQuote(g_options.testArgs.trimmed()),
g_options.package,
g_options.activity);
return true;
@@ -409,7 +409,7 @@ static bool pullFiles()
return false;
}
auto checkerIt = g_options.checkFiles.find(it.key());
- ret &= checkerIt != g_options.checkFiles.end() && checkerIt.value()(output);
+ ret = ret && checkerIt != g_options.checkFiles.end() && checkerIt.value()(output);
if (it.value() == QStringLiteral("-")){
fprintf(stdout, "%s", output.constData());
fflush(stdout);
diff --git a/src/widgets/dialogs/qfiledialog.cpp b/src/widgets/dialogs/qfiledialog.cpp
index a89192e76f..a1b9003c1c 100644
--- a/src/widgets/dialogs/qfiledialog.cpp
+++ b/src/widgets/dialogs/qfiledialog.cpp
@@ -2448,6 +2448,51 @@ void QFileDialog::getOpenFileContent(const QString &nameFilter, const std::funct
}
/*!
+ This is a convenience static function that saves \a fileContent to a file, using
+ a file name and location chosen by the user. \a fileNameHint can be provided to
+ suggest a file name to the user.
+
+ This function is used to save files to the local file system on Qt for WebAssembly, where
+ the web sandbox places restrictions on how such access may happen. Its implementation will
+ make the browser display a native file dialog, where the user makes the file selection.
+
+ It can also be used on other platforms, where it will fall back to using QFileDialog.
+
+ The function is asynchronous and returns immediately.
+
+ \snippet code/src_gui_dialogs_qfiledialog.cpp 16
+ \since 5.14
+*/
+void QFileDialog::saveFileContent(const QByteArray &fileContent, const QString &fileNameHint)
+{
+#ifdef Q_OS_WASM
+ QWasmLocalFileAccess::saveFile(fileContent.constData(), fileContent.size(), fileNameHint.toStdString());
+#else
+ QFileDialog *dialog = new QFileDialog();
+ dialog->setAcceptMode(QFileDialog::AcceptSave);
+ dialog->setFileMode(QFileDialog::AnyFile);
+ dialog->selectFile(fileNameHint);
+
+ auto fileSelected = [=](const QString &fileName) {
+ if (!fileName.isNull()) {
+ QFile selectedFile(fileName);
+ if (selectedFile.open(QIODevice::WriteOnly))
+ selectedFile.write(fileContent);
+ }
+ };
+
+ auto dialogClosed = [=](int code) {
+ Q_UNUSED(code);
+ delete dialog;
+ };
+
+ connect(dialog, &QFileDialog::fileSelected, fileSelected);
+ connect(dialog, &QFileDialog::finished, dialogClosed);
+ dialog->show();
+#endif
+}
+
+/*!
This is a convenience static function that will return a file name selected
by the user. The file does not have to exist.
diff --git a/src/widgets/dialogs/qfiledialog.h b/src/widgets/dialogs/qfiledialog.h
index 354a1f928b..790f52f2e7 100644
--- a/src/widgets/dialogs/qfiledialog.h
+++ b/src/widgets/dialogs/qfiledialog.h
@@ -284,6 +284,7 @@ public:
static void getOpenFileContent(const QString &nameFilter,
const std::function<void(const QString &, const QByteArray &)> &fileContentsReady);
+ static void saveFileContent(const QByteArray &fileContent, const QString &fileNameHint = QString());
protected:
QFileDialog(const QFileDialogArgs &args);
diff --git a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp
index 39aca459db..7ccd827a04 100644
--- a/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp
+++ b/src/widgets/doc/snippets/code/src_gui_dialogs_qfiledialog.cpp
@@ -155,3 +155,8 @@ auto fileOpenCompleted = [](const QString &fileName, const QByteArray &fileConte
}
QFileDialog::getOpenFileContent("Images (*.png *.xpm *.jpg)", fileContentReady);
//! [15]
+
+//! [16]
+QByteArray imageData; // obtained from e.g. QImage::save()
+QFileDialog::saveFile("myimage.png", imageData);
+//! [16]
diff --git a/src/widgets/graphicsview/qgraphicsproxywidget.cpp b/src/widgets/graphicsview/qgraphicsproxywidget.cpp
index 2b6712075f..7413a26261 100644
--- a/src/widgets/graphicsview/qgraphicsproxywidget.cpp
+++ b/src/widgets/graphicsview/qgraphicsproxywidget.cpp
@@ -404,7 +404,7 @@ void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot()
{
Q_Q(QGraphicsProxyWidget);
if (!widget.isNull()) {
- if (QWExtra *extra = widget->d_func()->extra)
+ if (const auto &extra = widget->d_func()->extra)
extra->proxyWidget = 0;
}
widget = 0;
@@ -477,8 +477,8 @@ void QGraphicsProxyWidgetPrivate::updateProxyInputMethodAcceptanceFromWidget()
*/
void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin)
{
- QWExtra *extra;
- if (!((extra = subWin->d_func()->extra) && extra->proxyWidget)) {
+ const auto &extra = subWin->d_func()->extra;
+ if (!extra || !extra->proxyWidget) {
QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func(), subWin->windowFlags());
subProxy->d_func()->setWidget_helper(subWin, false);
}
@@ -631,7 +631,7 @@ void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool auto
if (!newWidget)
return;
if (!newWidget->isWindow()) {
- QWExtra *extra = newWidget->parentWidget()->d_func()->extra;
+ const auto &extra = newWidget->parentWidget()->d_func()->extra;
if (!extra || !extra->proxyWidget) {
qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p "
"which is not a toplevel widget, and is not a child of an embedded widget", newWidget);
@@ -641,10 +641,10 @@ void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool auto
// Register this proxy within the widget's private.
// ### This is a bit backdoorish
- QWExtra *extra = newWidget->d_func()->extra;
+ QWExtra *extra = newWidget->d_func()->extra.get();
if (!extra) {
newWidget->d_func()->createExtra();
- extra = newWidget->d_func()->extra;
+ extra = newWidget->d_func()->extra.get();
}
QGraphicsProxyWidget **proxyWidget = &extra->proxyWidget;
if (*proxyWidget) {
diff --git a/src/widgets/kernel/qapplication.cpp b/src/widgets/kernel/qapplication.cpp
index 94b14ecb4f..629c696544 100644
--- a/src/widgets/kernel/qapplication.cpp
+++ b/src/widgets/kernel/qapplication.cpp
@@ -3388,7 +3388,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
#if QT_CONFIG(graphicsview)
// QGraphicsProxyWidget handles its own propagation,
// and we must not change QDragManagers currentTarget.
- QWExtra *extra = w->window()->d_func()->extra;
+ const auto &extra = w->window()->d_func()->extra;
if (extra && extra->proxyWidget) {
res = d->notify_helper(w, dragEvent);
break;
@@ -3416,7 +3416,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
#if QT_CONFIG(graphicsview)
// QGraphicsProxyWidget handles its own propagation,
// and we must not change QDragManagers currentTarget.
- QWExtra *extra = w->window()->d_func()->extra;
+ const auto &extra = w->window()->d_func()->extra;
bool isProxyWidget = extra && extra->proxyWidget;
if (!isProxyWidget)
#endif
diff --git a/src/widgets/kernel/qshortcut.cpp b/src/widgets/kernel/qshortcut.cpp
index a4ebcdfc84..39b08dbc1e 100644
--- a/src/widgets/kernel/qshortcut.cpp
+++ b/src/widgets/kernel/qshortcut.cpp
@@ -178,7 +178,7 @@ static bool correctWidgetContext(Qt::ShortcutContext context, QWidget *w, QWidge
// Below is Qt::WindowShortcut context
QWidget *tlw = w->window();
#if QT_CONFIG(graphicsview)
- if (auto topData = static_cast<QWidgetPrivate *>(QObjectPrivate::get(tlw))->extra) {
+ if (auto topData = static_cast<QWidgetPrivate *>(QObjectPrivate::get(tlw))->extra.get()) {
if (topData->proxyWidget) {
bool res = correctGraphicsWidgetContext(context, topData->proxyWidget, active_window);
return res;
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index c0c7f5cf3d..c024f7f1f3 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -130,7 +130,6 @@ extern QDesktopWidget *qt_desktopWidget; // qapplication.cpp
QWidgetPrivate::QWidgetPrivate(int version)
: QObjectPrivate(version)
- , extra(0)
, focus_next(0)
, focus_prev(0)
, focus_child(0)
@@ -1460,7 +1459,7 @@ QWidget::~QWidget()
while (w->d_func()->extra && w->d_func()->extra->focus_proxy)
w = w->d_func()->extra->focus_proxy;
QWidget *window = w->window();
- QWExtra *e = window ? window->d_func()->extra : 0;
+ QWExtra *e = window ? window->d_func()->extra.get() : nullptr ;
if (!e || !e->proxyWidget || (w->parentWidget() && w->parentWidget()->d_func()->focus_child == this))
#endif
clearFocus();
@@ -1618,7 +1617,7 @@ void QWidgetPrivate::createTLExtra()
void QWidgetPrivate::createExtra()
{
if (!extra) { // if not exists
- extra = new QWExtra;
+ extra = qt_make_unique<QWExtra>();
extra->glContext = 0;
#if QT_CONFIG(graphicsview)
extra->proxyWidget = 0;
@@ -1666,9 +1665,8 @@ void QWidgetPrivate::deleteExtra()
deleteTLSysExtra();
// extra->topextra->backingStore destroyed in QWidgetPrivate::deleteTLSysExtra()
}
- delete extra;
// extra->xic destroyed in QWidget::destroy()
- extra = 0;
+ extra.reset();
}
}
@@ -1739,7 +1737,7 @@ QRegion QWidgetPrivate::overlappedRegion(const QRect &rect, bool breakAfterFirst
const QRect siblingRect = sibling->d_func()->effectiveRectFor(sibling->data->crect);
if (qRectIntersects(siblingRect, r)) {
- const QWExtra *siblingExtra = sibling->d_func()->extra;
+ const auto &siblingExtra = sibling->d_func()->extra;
if (siblingExtra && siblingExtra->hasMask && !sibling->d_func()->graphicsEffect
&& !siblingExtra->mask.translated(sibling->data->crect.topLeft()).intersects(r)) {
continue;
@@ -3733,7 +3731,7 @@ QSize QWidget::sizeIncrement() const
QSize QWidget::baseSize() const
{
Q_D(const QWidget);
- return (d->extra != 0 && d->extra->topextra != 0)
+ return (d->extra && d->extra->topextra)
? QSize(d->extra->topextra->basew, d->extra->topextra->baseh)
: QSize(0, 0);
}
@@ -5694,7 +5692,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *
QGraphicsProxyWidget *QWidgetPrivate::nearestGraphicsProxyWidget(const QWidget *origin)
{
if (origin) {
- QWExtra *extra = origin->d_func()->extra;
+ const auto &extra = origin->d_func()->extra;
if (extra && extra->proxyWidget)
return extra->proxyWidget;
return nearestGraphicsProxyWidget(origin->parentWidget());
@@ -6240,7 +6238,7 @@ bool QWidget::hasFocus() const
w = w->d_func()->extra->focus_proxy;
#if QT_CONFIG(graphicsview)
if (QWidget *window = w->window()) {
- QWExtra *e = window->d_func()->extra;
+ const auto &e = window->d_func()->extra;
if (e && e->proxyWidget && e->proxyWidget->hasFocus() && window->focusWidget() == w)
return true;
}
@@ -6297,7 +6295,7 @@ void QWidget::setFocus(Qt::FocusReason reason)
#if QT_CONFIG(graphicsview)
QWidget *previousProxyFocus = 0;
- if (QWExtra *topData = window()->d_func()->extra) {
+ if (const auto &topData = window()->d_func()->extra) {
if (topData->proxyWidget && topData->proxyWidget->hasFocus()) {
previousProxyFocus = topData->proxyWidget->widget()->focusWidget();
if (previousProxyFocus && previousProxyFocus->focusProxy())
@@ -6310,7 +6308,7 @@ void QWidget::setFocus(Qt::FocusReason reason)
#if QT_CONFIG(graphicsview)
// Update proxy state
- if (QWExtra *topData = window()->d_func()->extra) {
+ if (const auto &topData = window()->d_func()->extra) {
if (topData->proxyWidget && !topData->proxyWidget->hasFocus()) {
f->d_func()->updateFocusChild();
topData->proxyWidget->d_func()->focusFromWidgetToProxy = 1;
@@ -6351,7 +6349,7 @@ void QWidget::setFocus(Qt::FocusReason reason)
}
#endif
#if QT_CONFIG(graphicsview)
- if (QWExtra *topData = window()->d_func()->extra) {
+ if (const auto &topData = window()->d_func()->extra) {
if (topData->proxyWidget) {
if (previousProxyFocus && previousProxyFocus != f) {
// Send event to self
@@ -6364,7 +6362,7 @@ void QWidget::setFocus(Qt::FocusReason reason)
if (!isHidden()) {
#if QT_CONFIG(graphicsview)
// Update proxy state
- if (QWExtra *topData = window()->d_func()->extra)
+ if (const auto &topData = window()->d_func()->extra)
if (topData->proxyWidget && topData->proxyWidget->hasFocus())
topData->proxyWidget->d_func()->updateProxyInputMethodAcceptanceFromWidget();
#endif
@@ -6501,7 +6499,7 @@ void QWidget::clearFocus()
}
#if QT_CONFIG(graphicsview)
- QWExtra *topData = d_func()->extra;
+ const auto &topData = d_func()->extra;
if (topData && topData->proxyWidget)
topData->proxyWidget->clearFocus();
#endif
@@ -6660,7 +6658,7 @@ bool QWidget::isActiveWindow() const
return true;
#if QT_CONFIG(graphicsview)
- if (QWExtra *tlwExtra = tlw->d_func()->extra) {
+ if (const auto &tlwExtra = tlw->d_func()->extra) {
if (isVisible() && tlwExtra->proxyWidget)
return tlwExtra->proxyWidget->isActiveWindow();
}
@@ -10050,7 +10048,7 @@ void QWidget::setSizePolicy(QSizePolicy policy)
d->size_policy = policy;
#if QT_CONFIG(graphicsview)
- if (QWExtra *extra = d->extra) {
+ if (const auto &extra = d->extra) {
if (extra->proxyWidget)
extra->proxyWidget->setSizePolicy(policy);
}
diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h
index cfb9a1ad8c..7d8a3ae737 100644
--- a/src/widgets/kernel/qwidget_p.h
+++ b/src/widgets/kernel/qwidget_p.h
@@ -626,7 +626,7 @@ public:
// Variables.
// Regular pointers (keep them together to avoid gaps on 64 bit architectures).
- QWExtra *extra;
+ std::unique_ptr<QWExtra> extra;
QWidget *focus_next;
QWidget *focus_prev;
QWidget *focus_child;
@@ -803,7 +803,7 @@ public:
inline QWExtra *QWidgetPrivate::extraData() const
{
- return extra;
+ return extra.get();
}
inline QTLWExtra *QWidgetPrivate::topData() const
diff --git a/src/widgets/widgets/qdockarealayout.cpp b/src/widgets/widgets/qdockarealayout.cpp
index 9be99c4723..5900326087 100644
--- a/src/widgets/widgets/qdockarealayout.cpp
+++ b/src/widgets/widgets/qdockarealayout.cpp
@@ -138,11 +138,8 @@ bool QDockAreaLayoutItem::skip() const
QSize QDockAreaLayoutItem::minimumSize() const
{
- if (widgetItem != 0) {
- int left, top, right, bottom;
- widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
- return widgetItem->minimumSize() + QSize(left+right, top+bottom);
- }
+ if (widgetItem)
+ return widgetItem->minimumSize().grownBy(widgetItem->widget()->contentsMargins());
if (subinfo != 0)
return subinfo->minimumSize();
return QSize(0, 0);
@@ -150,11 +147,8 @@ QSize QDockAreaLayoutItem::minimumSize() const
QSize QDockAreaLayoutItem::maximumSize() const
{
- if (widgetItem != 0) {
- int left, top, right, bottom;
- widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
- return widgetItem->maximumSize()+ QSize(left+right, top+bottom);
- }
+ if (widgetItem)
+ return widgetItem->maximumSize().grownBy(widgetItem->widget()->contentsMargins());
if (subinfo != 0)
return subinfo->maximumSize();
return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
@@ -180,11 +174,8 @@ QSize QDockAreaLayoutItem::sizeHint() const
{
if (placeHolderItem != 0)
return QSize(0, 0);
- if (widgetItem != 0) {
- int left, top, right, bottom;
- widgetItem->widget()->getContentsMargins(&left, &top, &right, &bottom);
- return widgetItem->sizeHint() + QSize(left+right, top+bottom);
- }
+ if (widgetItem)
+ return widgetItem->sizeHint().grownBy(widgetItem->widget()->contentsMargins());
if (subinfo != 0)
return subinfo->sizeHint();
return QSize(-1, -1);
diff --git a/src/widgets/widgets/qdockwidget.cpp b/src/widgets/widgets/qdockwidget.cpp
index 1ba34e0fed..05ec3aface 100644
--- a/src/widgets/widgets/qdockwidget.cpp
+++ b/src/widgets/widgets/qdockwidget.cpp
@@ -381,11 +381,10 @@ QSize QDockWidgetLayout::sizeFromContent(const QSize &content, bool floating) co
if (content.height() < 0)
result.setHeight(-1);
- int left, top, right, bottom;
- w->getContentsMargins(&left, &top, &right, &bottom);
+ const QMargins margins = w->contentsMargins();
//we need to subtract the contents margin (it will be added by the caller)
- QSize min = w->minimumSize() - QSize(left + right, top + bottom);
- QSize max = w->maximumSize() - QSize(left + right, top + bottom);
+ QSize min = w->minimumSize().shrunkBy(margins);
+ QSize max = w->maximumSize().shrunkBy(margins);
/* A floating dockwidget will automatically get its minimumSize set to the layout's
minimum size + deco. We're *not* interested in this, we only take minimumSize()