diff options
author | Liang Qi <liang.qi@qt.io> | 2016-06-13 09:01:02 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2016-06-13 12:46:46 +0200 |
commit | 511790fd1af1e2886a0e2e8dd4308099705cd815 (patch) | |
tree | b42aee537a6103cd064f9f41ae2889b09b79fd23 /src | |
parent | 1542d8881fc5ccbc5918cd4acbe4091ebbd24508 (diff) | |
parent | cbe332405aa22257d432f1797b325f5e57007c20 (diff) |
Merge remote-tracking branch 'origin/5.7' into dev
Conflicts:
config_help.txt
configure
mkspecs/features/uikit/sdk.prf
src/corelib/global/qhooks.cpp
src/corelib/io/qfilesystemwatcher.cpp
src/corelib/io/qlockfile_unix.cpp
src/corelib/tools/qalgorithms.h
src/gui/kernel/qwindowsysteminterface.h
src/gui/text/qtextdocument_p.cpp
src/network/access/access.pri
src/network/access/qnetworkaccessmanager.cpp
src/network/access/qnetworkreplynsurlconnectionimpl.mm
src/src.pro
src/testlib/qtestcase.cpp
src/widgets/kernel/qwidgetbackingstore_p.h
src/widgets/styles/qwindowscestyle.cpp
src/widgets/styles/qwindowsmobilestyle.cpp
tests/auto/corelib/io/qdiriterator/qdiriterator.pro
tests/auto/corelib/io/qfileinfo/qfileinfo.pro
tests/auto/gui/kernel/qwindow/BLACKLIST
tests/auto/widgets/dialogs/qfilesystemmodel/tst_qfilesystemmodel.cpp
tools/configure/configureapp.cpp
Change-Id: Ibf7fb9c8cf263a810ade82f821345d0725c57c67
Diffstat (limited to 'src')
167 files changed, 2499 insertions, 1904 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index ad05ab1a01..7b711e197b 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -30,6 +30,9 @@ #include "forkfd.h" #include <sys/types.h> +#if defined(__OpenBSD__) || defined(__NetBSD__) +# include <sys/param.h> +#endif #include <sys/time.h> #include <sys/resource.h> #include <sys/wait.h> @@ -65,7 +68,9 @@ # undef HAVE_WAITID #endif -#if defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1000032 +#if (defined(__FreeBSD__) && defined(__FreeBSD_version) && __FreeBSD_version >= 1000032) || \ + (defined(__OpenBSD__) && OpenBSD >= 201505) || \ + (defined(__NetBSD__) && __NetBSD_Version__ >= 600000000) # define HAVE_PIPE2 1 #endif #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) || \ @@ -410,6 +415,26 @@ chain_handler: old_sigaction.sa_handler(signum); } +static void ignore_sigpipe() +{ +#ifdef O_NOSIGPIPE + static ffd_atomic_int done = FFD_ATOMIC_INIT(0); + if (ffd_atomic_load(&done, FFD_ATOMIC_RELAXED)) + return; +#endif + + struct sigaction action; + memset(&action, 0, sizeof action); + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + action.sa_flags = 0; + sigaction(SIGPIPE, &action, NULL); + +#ifdef O_NOSIGPIPE + ffd_atomic_store(&done, 1, FFD_ATOMIC_RELAXED); +#endif +} + static void forkfd_initialize() { #if defined(HAVE_BROKEN_WAITID) @@ -446,6 +471,11 @@ static void forkfd_initialize() */ sigaction(SIGCHLD, &action, &old_sigaction); +#ifndef O_NOSIGPIPE + /* disable SIGPIPE too */ + ignore_sigpipe(); +#endif + #ifndef __GNUC__ atexit(cleanup); #endif @@ -486,13 +516,23 @@ static void cleanup() static int create_pipe(int filedes[], int flags) { - int ret; + int ret = -1; #ifdef HAVE_PIPE2 /* use pipe2(2) whenever possible, since it can thread-safely create a * cloexec pair of pipes. Without it, we have a race condition setting * FD_CLOEXEC */ - ret = pipe2(filedes, O_CLOEXEC); + +# ifdef O_NOSIGPIPE + /* try first with O_NOSIGPIPE */ + ret = pipe2(filedes, O_CLOEXEC | O_NOSIGPIPE); + if (ret == -1) { + /* O_NOSIGPIPE not supported, ignore SIGPIPE */ + ignore_sigpipe(); + } +# endif + if (ret == -1) + ret = pipe2(filedes, O_CLOEXEC); if (ret == -1) return ret; diff --git a/src/3rdparty/freetype/freetype.pro b/src/3rdparty/freetype/freetype.pro index e85ed1699b..41ca469576 100644 --- a/src/3rdparty/freetype/freetype.pro +++ b/src/3rdparty/freetype/freetype.pro @@ -68,12 +68,7 @@ DEFINES += FT2_BUILD_LIBRARY DEFINES += FT_CONFIG_OPTION_SYSTEM_ZLIB include(../zlib_dependency.pri) -contains(QT_CONFIG, system-png) { - DEFINES += FT_CONFIG_OPTION_USE_PNG - include($$PWD/../png_dependency.pri) -} else:!contains(QT_CONFIG, no-png):!win32 { - DEFINES += FT_CONFIG_OPTION_USE_PNG - include($$PWD/../libpng.pri) -} +DEFINES += FT_CONFIG_OPTION_USE_PNG +include($$PWD/../png_dependency.pri) DEFINES += TT_CONFIG_OPTION_SUBPIXEL_HINTING diff --git a/src/3rdparty/libpng.pri b/src/3rdparty/libpng.pri deleted file mode 100644 index a5fe32f867..0000000000 --- a/src/3rdparty/libpng.pri +++ /dev/null @@ -1,21 +0,0 @@ -DEFINES += PNG_ARM_NEON_OPT=0 -INCLUDEPATH += $$PWD/libpng -SOURCES += $$PWD/libpng/png.c \ - $$PWD/libpng/pngerror.c \ - $$PWD/libpng/pngget.c \ - $$PWD/libpng/pngmem.c \ - $$PWD/libpng/pngpread.c \ - $$PWD/libpng/pngread.c \ - $$PWD/libpng/pngrio.c \ - $$PWD/libpng/pngrtran.c \ - $$PWD/libpng/pngrutil.c \ - $$PWD/libpng/pngset.c \ - $$PWD/libpng/pngtrans.c \ - $$PWD/libpng/pngwio.c \ - $$PWD/libpng/pngwrite.c \ - $$PWD/libpng/pngwtran.c \ - $$PWD/libpng/pngwutil.c - -TR_EXCLUDE += $$PWD/* - -include($$PWD/zlib_dependency.pri) diff --git a/src/3rdparty/libpng/libpng.pro b/src/3rdparty/libpng/libpng.pro new file mode 100644 index 0000000000..ab6dd51e2b --- /dev/null +++ b/src/3rdparty/libpng/libpng.pro @@ -0,0 +1,31 @@ +TARGET = qtpng + +CONFIG += \ + static \ + hide_symbols \ + exceptions_off rtti_off warn_off \ + installed + +load(qt_helper_lib) + +DEFINES += PNG_ARM_NEON_OPT=0 +SOURCES += \ + png.c \ + pngerror.c \ + pngget.c \ + pngmem.c \ + pngpread.c \ + pngread.c \ + pngrio.c \ + pngrtran.c \ + pngrutil.c \ + pngset.c \ + pngtrans.c \ + pngwio.c \ + pngwrite.c \ + pngwtran.c \ + pngwutil.c + +TR_EXCLUDE += $$PWD/* + +include(../zlib_dependency.pri) diff --git a/src/3rdparty/png_dependency.pri b/src/3rdparty/png_dependency.pri index 78da861f77..eb32432b49 100644 --- a/src/3rdparty/png_dependency.pri +++ b/src/3rdparty/png_dependency.pri @@ -2,5 +2,6 @@ contains(QT_CONFIG, system-png) { unix|mingw: LIBS_PRIVATE += -lpng else: LIBS += libpng.lib } else: contains(QT_CONFIG, png) { - include($$PWD/libpng.pri) + INCLUDEPATH += $$PWD/libpng + LIBS_PRIVATE += -L$$QT_BUILD_TREE/lib -lqtpng$$qtPlatformTargetSuffix() } diff --git a/src/concurrent/qtconcurrentiteratekernel.cpp b/src/concurrent/qtconcurrentiteratekernel.cpp index a04f0d66cc..4b6ccc2810 100644 --- a/src/concurrent/qtconcurrentiteratekernel.cpp +++ b/src/concurrent/qtconcurrentiteratekernel.cpp @@ -77,7 +77,7 @@ static qint64 getticks() static qint64 getticks() { -#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) +#if (defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)) || defined(Q_OS_OPENBSD) clockid_t clockId; #ifndef _POSIX_THREAD_CPUTIME diff --git a/src/corelib/Qt5CoreConfigExtras.cmake.in b/src/corelib/Qt5CoreConfigExtras.cmake.in index a5ed8b2ea3..f492148a50 100644 --- a/src/corelib/Qt5CoreConfigExtras.cmake.in +++ b/src/corelib/Qt5CoreConfigExtras.cmake.in @@ -46,6 +46,21 @@ if (NOT TARGET Qt5::rcc) ) endif() +if (NOT TARGET Qt5::qdoc) + add_executable(Qt5::qdoc IMPORTED) + +!!IF isEmpty(CMAKE_BIN_DIR_IS_ABSOLUTE) + set(imported_location \"${_qt5Core_install_prefix}/$${CMAKE_BIN_DIR}qdoc$$CMAKE_BIN_SUFFIX\") +!!ELSE + set(imported_location \"$${CMAKE_BIN_DIR}qdoc$$CMAKE_BIN_SUFFIX\") +!!ENDIF + _qt5_Core_check_file_exists(${imported_location}) + + set_target_properties(Qt5::qdoc PROPERTIES + IMPORTED_LOCATION ${imported_location} + ) +endif() + set(Qt5Core_QMAKE_EXECUTABLE Qt5::qmake) set(Qt5Core_MOC_EXECUTABLE Qt5::moc) set(Qt5Core_RCC_EXECUTABLE Qt5::rcc) diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp index a783bcc31e..7117092c54 100644 --- a/src/corelib/animation/qvariantanimation.cpp +++ b/src/corelib/animation/qvariantanimation.cpp @@ -54,15 +54,13 @@ QT_BEGIN_NAMESPACE \class QVariantAnimation \inmodule QtCore \ingroup animation - \brief The QVariantAnimation class provides an abstract base class for animations. + \brief The QVariantAnimation class provides a base class for animations. \since 4.6 This class is part of \l{The Animation Framework}. It serves as a base class for property and item animations, with functions for shared functionality. - QVariantAnimation cannot be used directly as it is an abstract - class; it has a pure virtual method called updateCurrentValue(). The class performs interpolation over \l{QVariant}s, but leaves using the interpolated values to its subclasses. Currently, Qt provides QPropertyAnimation, which @@ -75,7 +73,7 @@ QT_BEGIN_NAMESPACE start the animation. QVariantAnimation will interpolate the property of the target object and emit valueChanged(). To react to a change in the current value you have to reimplement the - updateCurrentValue() virtual function. + updateCurrentValue() virtual function or connect to said signal. It is also possible to set values at specified steps situated between the start and end value. The interpolation will then diff --git a/src/corelib/doc/src/animation.qdoc b/src/corelib/doc/src/animation.qdoc index 02eb5a97c6..4e71ed4268 100644 --- a/src/corelib/doc/src/animation.qdoc +++ b/src/corelib/doc/src/animation.qdoc @@ -118,11 +118,12 @@ \section1 Animating Qt Properties - As mentioned in the previous section, the QPropertyAnimation class - can interpolate over Qt properties. It is this class that should - be used for animation of values; in fact, its superclass, - QVariantAnimation, is an abstract class, and cannot be used - directly. + As mentioned in the previous section, the QPropertyAnimation class can + interpolate over Qt properties. It is often this class that should be used + for animation of values; in fact, its superclass, QVariantAnimation, has an + empty implementation of \l{QAbstractAnimation::}{updateCurrentValue()}, and + does not change any value unless we change it ourselves on the + \l{QVariantAnimation::valueChanged()}{valueChanged signal}. A major reason we chose to animate Qt properties is that it presents us with freedom to animate already existing classes in diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index dd846955f6..6a8948822c 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -28,8 +28,9 @@ SOURCES += \ global/qmalloc.cpp \ global/qnumeric.cpp \ global/qlogging.cpp \ - global/qhooks.cpp \ - global/qversiontagging.cpp + global/qhooks.cpp + +VERSIONTAGGING_SOURCES = global/qversiontagging.cpp # qlibraryinfo.cpp includes qconfig.cpp INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global @@ -63,3 +64,21 @@ journald { syslog { DEFINES += QT_USE_SYSLOG } + +gcc:ltcg { + versiontagging_compiler.commands = $$QMAKE_CXX -c $(CXXFLAGS) $(INCPATH) + + # Disable LTO, as the symbols disappear somehow under GCC + versiontagging_compiler.commands += -fno-lto + + versiontagging_compiler.commands += -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} + versiontagging_compiler.dependency_type = TYPE_C + versiontagging_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} + versiontagging_compiler.input = VERSIONTAGGING_SOURCES + versiontagging_compiler.variable_out = OBJECTS + versiontagging_compiler.name = compiling[versiontagging] ${QMAKE_FILE_IN} + silent: versiontagging_compiler.commands = @echo compiling[versiontagging] ${QMAKE_FILE_IN} && $$versiontagging_compiler.commands + QMAKE_EXTRA_COMPILERS += versiontagging_compiler +} else { + SOURCES += $$VERSIONTAGGING_SOURCES +} diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index 1ebf37d610..c5424be035 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -748,7 +748,9 @@ # define Q_COMPILER_TEMPLATE_ALIAS # endif # if __has_feature(cxx_thread_local) -# define Q_COMPILER_THREAD_LOCAL +# if !defined(__FreeBSD__) /* FreeBSD clang fails on __cxa_thread_atexit */ +# define Q_COMPILER_THREAD_LOCAL +# endif # endif # if __has_feature(cxx_user_literals) # define Q_COMPILER_UDL @@ -1108,7 +1110,8 @@ # define Q_DECL_NOTHROW Q_DECL_NOEXCEPT #endif -#if defined(Q_COMPILER_ALIGNOF) && !defined(Q_ALIGNOF) +#if defined(Q_COMPILER_ALIGNOF) +# undef Q_ALIGNOF # define Q_ALIGNOF(x) alignof(x) #endif diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h index c5ff82c10a..34bb015a2f 100644 --- a/src/corelib/global/qendian.h +++ b/src/corelib/global/qendian.h @@ -49,6 +49,11 @@ QT_BEGIN_NAMESPACE +#ifdef __has_builtin +# define QT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define QT_HAS_BUILTIN(x) 0 +#endif /* * ENDIAN FUNCTIONS @@ -71,18 +76,29 @@ template <typename T> inline void qbswap(const T src, uchar *dest) // Used to implement a type-safe and alignment-safe copy operation // If you want to avoid the memcpy, you must write specializations for these functions -template <typename T> inline void qToUnaligned(const T src, uchar *dest) +template <typename T> Q_ALWAYS_INLINE void qToUnaligned(const T src, uchar *dest) { // Using sizeof(T) inside memcpy function produces internal compiler error with // MSVC2008/ARM in tst_endian -> use extra indirection to resolve size of T. const size_t size = sizeof(T); - memcpy(dest, &src, size); +#if QT_HAS_BUILTIN(__builtin_memcpy) + __builtin_memcpy +#else + memcpy +#endif + (dest, &src, size); } -template <typename T> inline T qFromUnaligned(const uchar *src) + +template <typename T> Q_ALWAYS_INLINE T qFromUnaligned(const uchar *src) { T dest; const size_t size = sizeof(T); - memcpy(&dest, src, size); +#if QT_HAS_BUILTIN(__builtin_memcpy) + __builtin_memcpy +#else + memcpy +#endif + (&dest, src, size); return dest; } diff --git a/src/corelib/global/qendian.qdoc b/src/corelib/global/qendian.qdoc index 63d924211f..3b22dcec87 100644 --- a/src/corelib/global/qendian.qdoc +++ b/src/corelib/global/qendian.qdoc @@ -34,6 +34,29 @@ */ /*! + \internal + \fn T qFromUnaligned(const uchar *ptr) + \since 5.5 + + Loads a \c{T} from address \a ptr, which may be misaligned. + + Use of this function avoids the undefined behavior that the C++ standard + otherwise attributes to unaligned loads. +*/ + +/*! + \internal + \fn void qToUnaligned(T t, uchar *ptr) + \since 4.5 + + Stores \a t to address \a ptr, which may be misaligned. + + Use of this function avoids the undefined behavior that the C++ standard + otherwise attributes to unaligned stores. +*/ + + +/*! \fn T qFromBigEndian(const uchar *src) \since 4.3 \relates <QtEndian> diff --git a/src/corelib/global/qhooks.cpp b/src/corelib/global/qhooks.cpp index 2ec1714cd2..7b9a3db30d 100644 --- a/src/corelib/global/qhooks.cpp +++ b/src/corelib/global/qhooks.cpp @@ -67,7 +67,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = { // The required sizes and offsets are tested in tests/auto/other/toolsupport. // When this fails and the change was intentional, adjust the test and // adjust this value here. - 14 + 15 }; Q_STATIC_ASSERT(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0])); diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index 10f9068d0a..ccf5851d18 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -66,6 +66,7 @@ NETBSD - NetBSD OPENBSD - OpenBSD BSDI - BSD/OS + INTERIX - Interix IRIX - SGI Irix OSF - HP Tru64 UNIX SCO - SCO OpenServer 5 @@ -172,6 +173,9 @@ #elif defined(__bsdi__) # define Q_OS_BSDI # define Q_OS_BSD4 +#elif defined(__INTERIX) +# define Q_OS_INTERIX +# define Q_OS_BSD4 #elif defined(__sgi) # define Q_OS_IRIX #elif defined(__osf__) diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index eb9471b502..ab345e9aae 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -144,7 +144,6 @@ win32 { !nacl:mac: { SOURCES += io/qsettings_mac.cpp } - freebsd: LIBS_PRIVATE += -lutil # qlockfile_unix.cpp requires this mac { SOURCES += io/qstorageinfo_mac.cpp OBJECTIVE_SOURCES += io/qstandardpaths_mac.mm diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp index 0d9fdb3453..fa919e9f10 100644 --- a/src/corelib/io/qdebug.cpp +++ b/src/corelib/io/qdebug.cpp @@ -166,16 +166,15 @@ void QDebug::putUcs4(uint ucs4) { maybeQuote('\''); if (ucs4 < 0x20) { - stream->ts << hex << "\\x" << ucs4 << reset; + stream->ts << "\\x" << hex << ucs4 << reset; } else if (ucs4 < 0x80) { stream->ts << char(ucs4); } else { - stream->ts << hex << qSetPadChar(QLatin1Char('0')); if (ucs4 < 0x10000) - stream->ts << qSetFieldWidth(4) << "\\u"; + stream->ts << "\\u" << qSetFieldWidth(4); else - stream->ts << qSetFieldWidth(8) << "\\U"; - stream->ts << ucs4 << reset; + stream->ts << "\\U" << qSetFieldWidth(8); + stream->ts << hex << qSetPadChar(QLatin1Char('0')) << ucs4 << reset; } maybeQuote('\''); } diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 76b56f4699..6366c5120c 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -820,7 +820,7 @@ QString QFileInfo::completeBaseName() const } /*! - Returns the complete suffix of the file. + Returns the complete suffix (extension) of the file. The complete suffix consists of all characters in the file after (but not including) the first '.'. @@ -839,7 +839,7 @@ QString QFileInfo::completeSuffix() const } /*! - Returns the suffix of the file. + Returns the suffix (extension) of the file. The suffix consists of all characters in the file after (but not including) the last '.'. diff --git a/src/corelib/io/qfilesystemwatcher.cpp b/src/corelib/io/qfilesystemwatcher.cpp index 1e22252217..55f4bddd17 100644 --- a/src/corelib/io/qfilesystemwatcher.cpp +++ b/src/corelib/io/qfilesystemwatcher.cpp @@ -58,7 +58,7 @@ # include "qfilesystemwatcher_win_p.h" #elif defined(USE_INOTIFY) # include "qfilesystemwatcher_inotify_p.h" -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(QT_PLATFORM_UIKIT) +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_OPENBSD) || defined(QT_PLATFORM_UIKIT) # include "qfilesystemwatcher_kqueue_p.h" #elif defined(Q_OS_OSX) # include "qfilesystemwatcher_fsevents_p.h" @@ -74,7 +74,7 @@ QFileSystemWatcherEngine *QFileSystemWatcherPrivate::createNativeEngine(QObject // there is a chance that inotify may fail on Linux pre-2.6.13 (August // 2005), so we can't just new inotify directly. return QInotifyFileSystemWatcherEngine::create(parent); -#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(QT_PLATFORM_UIKIT) +#elif defined(Q_OS_FREEBSD) || defined(Q_OS_NETBSD) || defined(Q_OS_OPENBSD) || defined(QT_PLATFORM_UIKIT) return QKqueueFileSystemWatcherEngine::create(parent); #elif defined(Q_OS_OSX) return QFseventsFileSystemWatcherEngine::create(parent); diff --git a/src/corelib/io/qfilesystemwatcher_kqueue.cpp b/src/corelib/io/qfilesystemwatcher_kqueue.cpp index 264973d556..4f6c83ebcf 100644 --- a/src/corelib/io/qfilesystemwatcher_kqueue.cpp +++ b/src/corelib/io/qfilesystemwatcher_kqueue.cpp @@ -172,7 +172,6 @@ QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths QStringList *files, QStringList *directories) { - bool isEmpty; QStringList p = paths; if (pathToID.isEmpty()) return p; @@ -193,7 +192,6 @@ QStringList QKqueueFileSystemWatcherEngine::removePaths(const QStringList &paths else files->removeAll(path); } - isEmpty = pathToID.isEmpty(); return p; } diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index ba59ea8341..79141d1e8f 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -71,14 +71,12 @@ #elif defined(Q_OS_HAIKU) # include <kernel/OS.h> #elif defined(Q_OS_BSD4) && !defined(QT_PLATFORM_UIKIT) +# if !defined(Q_OS_NETBSD) # include <sys/user.h> -# if defined(__GLIBC__) && defined(__FreeBSD_kernel__) +# endif # include <sys/cdefs.h> # include <sys/param.h> # include <sys/sysctl.h> -# else -# include <libutil.h> -# endif #endif QT_BEGIN_NAMESPACE @@ -286,30 +284,33 @@ QString QLockFilePrivate::processNameByPid(qint64 pid) return QString(); return QFile::decodeName(info.name); #elif defined(Q_OS_BSD4) && !defined(QT_PLATFORM_UIKIT) -# if defined(__GLIBC__) && defined(__FreeBSD_kernel__) - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; - size_t len = 0; - if (sysctl(mib, 4, NULL, &len, NULL, 0) < 0) - return QString(); - kinfo_proc *proc = static_cast<kinfo_proc *>(malloc(len)); +# if defined(Q_OS_NETBSD) + struct kinfo_proc2 kp; + int mib[6] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, (int)pid, sizeof(struct kinfo_proc2), 1 }; +# elif defined(Q_OS_OPENBSD) + struct kinfo_proc kp; + int mib[6] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid, sizeof(struct kinfo_proc), 1 }; # else - kinfo_proc *proc = kinfo_getproc(pid); + struct kinfo_proc kp; + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, (int)pid }; # endif - if (!proc) + size_t len = sizeof(kp); + u_int mib_len = sizeof(mib)/sizeof(u_int); + + if (sysctl(mib, mib_len, &kp, &len, NULL, 0) < 0) return QString(); -# if defined(__GLIBC__) && defined(__FreeBSD_kernel__) - if (sysctl(mib, 4, proc, &len, NULL, 0) < 0) { - free(proc); + +# if defined(Q_OS_OPENBSD) || defined(Q_OS_NETBSD) + if (kp.p_pid != pid) return QString(); - } - if (proc->ki_pid != pid) { - free(proc); + QString name = QFile::decodeName(kp.p_comm); +# else + if (kp.ki_pid != pid) return QString(); - } + QString name = QFile::decodeName(kp.ki_comm); # endif - QString name = QFile::decodeName(proc->ki_comm); - free(proc); return name; + #else Q_UNUSED(pid); return QString(); diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index ba4a091965..baaff8da17 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -143,9 +143,11 @@ bool QLockFilePrivate::isApparentlyStale() const if (!procHandle) return true; // We got a handle but check if process is still alive - DWORD dwR = ::WaitForSingleObject(procHandle, 0); + DWORD exitCode = 0; + if (!::GetExitCodeProcess(procHandle, &exitCode)) + exitCode = 0; ::CloseHandle(procHandle); - if (dwR == WAIT_TIMEOUT) + if (exitCode != STILL_ACTIVE) return true; const QString processName = processNameByPid(pid); if (!processName.isEmpty() && processName != appname) diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 227241b208..ebafd6b524 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -2087,10 +2087,7 @@ void QProcess::start(const QString &program, const QStringList &arguments, OpenM return; } if (program.isEmpty()) { - Q_D(QProcess); - d->processError = QProcess::FailedToStart; - setErrorString(tr("No program defined")); - emit error(d->processError); + d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined")); return; } @@ -2117,10 +2114,7 @@ void QProcess::start(OpenMode mode) return; } if (d->program.isEmpty()) { - Q_D(QProcess); - d->processError = QProcess::FailedToStart; - setErrorString(tr("No program defined")); - emit error(d->processError); + d->setErrorAndEmit(QProcess::FailedToStart, tr("No program defined")); return; } diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp index 3a9f74bf59..0daf041954 100644 --- a/src/corelib/io/qstorageinfo_unix.cpp +++ b/src/corelib/io/qstorageinfo_unix.cpp @@ -84,7 +84,7 @@ # if !defined(ST_RDONLY) # define ST_RDONLY MNT_RDONLY # endif -# if !defined(_STATFS_F_FLAGS) +# if !defined(_STATFS_F_FLAGS) && !defined(Q_OS_NETBSD) # define _STATFS_F_FLAGS 1 # endif #elif defined(Q_OS_ANDROID) diff --git a/src/corelib/io/qwindowspipewriter.cpp b/src/corelib/io/qwindowspipewriter.cpp index 64c9692e23..3ab2c70c75 100644 --- a/src/corelib/io/qwindowspipewriter.cpp +++ b/src/corelib/io/qwindowspipewriter.cpp @@ -205,6 +205,8 @@ bool QWindowsPipeWriter::write(const QByteArray &ba) void QWindowsPipeWriter::stop() { stopped = true; + bytesWrittenPending = false; + pendingBytesWrittenValue = 0; if (writeSequenceStarted) { if (!CancelIoEx(handle, &overlapped)) { const DWORD dwError = GetLastError(); diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h index d16b6e5b00..f2fcb767d5 100644 --- a/src/corelib/json/qjson_p.h +++ b/src/corelib/json/qjson_p.h @@ -410,7 +410,7 @@ public: // pack with itself, we'll discard the high part anyway chunk = _mm_packus_epi16(chunk, chunk); // unaligned 64-bit store - qUnalignedStore(l + i, _mm_cvtsi128_si64(chunk)); + qToUnaligned(_mm_cvtsi128_si64(chunk), l + i); i += 8; } # endif @@ -684,6 +684,8 @@ public: bool operator >=(const Entry &other) const; }; +inline bool operator!=(const Entry &lhs, const Entry &rhs) { return !(lhs == rhs); } + inline bool Entry::operator >=(const QString &key) const { if (value.latinKey) diff --git a/src/corelib/json/qjsonobject.cpp b/src/corelib/json/qjsonobject.cpp index b5b6f36bc6..fb651f0f24 100644 --- a/src/corelib/json/qjsonobject.cpp +++ b/src/corelib/json/qjsonobject.cpp @@ -599,8 +599,8 @@ bool QJsonObject::operator==(const QJsonObject &other) const for (uint i = 0; i < o->length; ++i) { QJsonPrivate::Entry *e = o->entryAt(i); - QJsonValue v(d, o, e->value); - if (other.value(e->key()) != v) + QJsonPrivate::Entry *oe = other.o->entryAt(i); + if (*e != *oe || QJsonValue(d, o, e->value) != QJsonValue(other.d, other.o, oe->value)) return false; } diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp index b21f59ae35..718dfa43b3 100644 --- a/src/corelib/json/qjsonvalue.cpp +++ b/src/corelib/json/qjsonvalue.cpp @@ -275,25 +275,11 @@ QJsonValue::QJsonValue(const QJsonValue &other) */ QJsonValue &QJsonValue::operator =(const QJsonValue &other) { - if (t == String && stringData && !stringData->ref.deref()) - free(stringData); - - t = other.t; - dbl = other.dbl; - - if (d != other.d) { - - if (d && !d->ref.deref()) - delete d; - d = other.d; - if (d) - d->ref.ref(); - - } - - if (t == String && stringData) - stringData->ref.ref(); - + QJsonValue copy(other); + // swap(copy); + qSwap(dbl, copy.dbl); + qSwap(d, copy.d); + qSwap(t, copy.t); return *this; } diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp index 93af957d95..2042964427 100644 --- a/src/corelib/kernel/qcore_unix.cpp +++ b/src/corelib/kernel/qcore_unix.cpp @@ -41,16 +41,6 @@ #include "qcore_unix_p.h" #include "qelapsedtimer.h" -#ifdef Q_OS_NACL -#elif !defined (Q_OS_VXWORKS) -# if !defined(Q_OS_HPUX) || defined(__ia64) -# include <sys/select.h> -# endif -# include <sys/time.h> -#else -# include <selectLib.h> -#endif - #include <stdlib.h> #ifdef Q_OS_MAC diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h index b08571223f..6ed316254b 100644 --- a/src/corelib/kernel/qcore_unix_p.h +++ b/src/corelib/kernel/qcore_unix_p.h @@ -65,6 +65,16 @@ #include <sys/stat.h> #include <unistd.h> +#ifdef Q_OS_NACL +#elif !defined (Q_OS_VXWORKS) +# if !defined(Q_OS_HPUX) || defined(__ia64) +# include <sys/select.h> +# endif +# include <sys/time.h> +#else +# include <selectLib.h> +#endif + #include <sys/wait.h> #include <errno.h> #include <fcntl.h> diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 9b421d6a78..ffb50ddac3 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4699,7 +4699,7 @@ QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int s QOrderedMutexLocker locker(signalSlotLock(sender), signalSlotLock(receiver)); - if (type & Qt::UniqueConnection) { + if (type & Qt::UniqueConnection && slot) { QObjectConnectionListVector *connectionLists = QObjectPrivate::get(s)->connectionLists; if (connectionLists && connectionLists->count() > signal_index) { const QObjectPrivate::Connection *c2 = diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h index 87d006bdc6..3cec9802dc 100644 --- a/src/corelib/kernel/qobject.h +++ b/src/corelib/kernel/qobject.h @@ -302,7 +302,6 @@ public: connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, const QObject *context, Func2 slot, Qt::ConnectionType type = Qt::AutoConnection) { -#if defined (Q_COMPILER_VARIADIC_TEMPLATES) typedef QtPrivate::FunctionPointer<Func1> SignalType; const int FunctorArgumentCount = QtPrivate::ComputeFunctorArgumentCount<Func2 , typename SignalType::Arguments>::Value; @@ -310,28 +309,6 @@ public: "Signal and slot arguments are not compatible."); const int SlotArgumentCount = (FunctorArgumentCount >= 0) ? FunctorArgumentCount : 0; typedef typename QtPrivate::FunctorReturnType<Func2, typename QtPrivate::List_Left<typename SignalType::Arguments, SlotArgumentCount>::Value>::Value SlotReturnType; -#else - // Without variadic template, we don't detect the best overload of operator(). We just - // assume there is only one simple operator() and connect to &Func2::operator() - - /* If you get an error such as: - couldn't deduce template parameter 'Func2Operator' - or - cannot resolve address of overloaded function - It means the functor does not have a single operator(). - Functors with overloaded or templated operator() are only supported if the compiler supports - C++11 variadic templates - */ - typedef QtPrivate::FunctionPointer<decltype(&Func2::operator())> SlotType ; - typedef QtPrivate::FunctionPointer<Func1> SignalType; - typedef typename SlotType::ReturnType SlotReturnType; - const int SlotArgumentCount = SlotType::ArgumentCount; - - Q_STATIC_ASSERT_X(int(SignalType::ArgumentCount) >= SlotArgumentCount, - "The slot requires more arguments than the signal provides."); - Q_STATIC_ASSERT_X((QtPrivate::CheckCompatibleArguments<typename SignalType::Arguments, typename SlotType::Arguments>::value), - "Signal and slot arguments are not compatible."); -#endif Q_STATIC_ASSERT_X((QtPrivate::AreArgumentsCompatible<SlotReturnType, typename SignalType::ReturnType>::value), "Return type of the slot is not compatible with the return type of the signal."); @@ -446,8 +423,7 @@ protected: QScopedPointer<QObjectData> d_ptr; static const QMetaObject staticQtMetaObject; - friend inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT - { return &staticQtMetaObject; } + friend inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT; friend struct QMetaObject; friend struct QMetaObjectPrivate; @@ -478,6 +454,9 @@ inline QMetaObject::Connection QObject::connect(const QObject *asender, const ch const char *amember, Qt::ConnectionType atype) const { return connect(asender, asignal, this, amember, atype); } +inline const QMetaObject *qt_getQtMetaObject() Q_DECL_NOEXCEPT +{ return &QObject::staticQtMetaObject; } + #ifndef QT_NO_USERDATA class Q_CORE_EXPORT QObjectUserData { public: diff --git a/src/corelib/kernel/qobject_impl.h b/src/corelib/kernel/qobject_impl.h index b4091a4f1c..d7ae63a98c 100644 --- a/src/corelib/kernel/qobject_impl.h +++ b/src/corelib/kernel/qobject_impl.h @@ -62,34 +62,6 @@ namespace QtPrivate { If one of the type is not declared, the function return 0 and the signal cannot be used in queued connection. */ -#ifndef Q_COMPILER_VARIADIC_TEMPLATES - template <typename ArgList> struct TypesAreDeclaredMetaType { enum { Value = false }; }; - template <> struct TypesAreDeclaredMetaType<void> { enum { Value = true }; }; - template <typename Arg, typename Tail> struct TypesAreDeclaredMetaType<List<Arg, Tail> > { enum { Value = QMetaTypeId2<Arg>::Defined && TypesAreDeclaredMetaType<Tail>::Value }; }; - - template <typename ArgList, bool Declared = TypesAreDeclaredMetaType<ArgList>::Value > struct ConnectionTypes - { static const int *types() { return 0; } }; - template <> struct ConnectionTypes<void, true> - { static const int *types() { static const int t[1] = { 0 }; return t; } }; - template <typename Arg1> struct ConnectionTypes<List<Arg1, void>, true> - { static const int *types() { static const int t[2] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), 0 }; return t; } }; - template <typename Arg1, typename Arg2> struct ConnectionTypes<List<Arg1, List<Arg2, void> >, true> - { static const int *types() { static const int t[3] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg2>::qt_metatype_id(), 0 }; return t; } }; - template <typename Arg1, typename Arg2, typename Arg3> struct ConnectionTypes<List<Arg1, List<Arg2, List<Arg3, void> > >, true> - { static const int *types() { static const int t[4] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg2>::qt_metatype_id(), - QtPrivate::QMetaTypeIdHelper<Arg3>::qt_metatype_id(), 0 }; return t; } }; - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct ConnectionTypes<List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > >, true> - { static const int *types() { static const int t[5] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg2>::qt_metatype_id(), - QtPrivate::QMetaTypeIdHelper<Arg3>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg4>::qt_metatype_id(), 0 }; return t; } }; - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct ConnectionTypes<List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, void> > > > >, true> - { static const int *types() { static const int t[6] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg2>::qt_metatype_id(), - QtPrivate::QMetaTypeIdHelper<Arg3>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg4>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg5>::qt_metatype_id(), 0 }; return t; } }; - template <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> - struct ConnectionTypes<List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > >, true> - { static const int *types() { static const int t[7] = { QtPrivate::QMetaTypeIdHelper<Arg1>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg2>::qt_metatype_id(), - QtPrivate::QMetaTypeIdHelper<Arg3>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg4>::qt_metatype_id(), QtPrivate::QMetaTypeIdHelper<Arg5>::qt_metatype_id(), - QtPrivate::QMetaTypeIdHelper<Arg6>::qt_metatype_id(), 0 }; return t; } }; -#else template <typename ArgList> struct TypesAreDeclaredMetaType { enum { Value = false }; }; template <> struct TypesAreDeclaredMetaType<List<>> { enum { Value = true }; }; template <typename Arg, typename... Tail> struct TypesAreDeclaredMetaType<List<Arg, Tail...> > @@ -101,7 +73,6 @@ namespace QtPrivate { { static const int *types() { return Q_NULLPTR; } }; template <typename... Args> struct ConnectionTypes<List<Args...>, true> { static const int *types() { static const int t[sizeof...(Args) + 1] = { (QtPrivate::QMetaTypeIdHelper<Args>::qt_metatype_id())..., 0 }; return t; } }; -#endif // internal base class (interface) containing functions required to call a slot managed by a pointer to function. class QSlotObjectBase { diff --git a/src/corelib/kernel/qobjectdefs_impl.h b/src/corelib/kernel/qobjectdefs_impl.h index 6ef83a6eb5..5eae70ecc5 100644 --- a/src/corelib/kernel/qobjectdefs_impl.h +++ b/src/corelib/kernel/qobjectdefs_impl.h @@ -65,11 +65,6 @@ namespace QtPrivate { List_Left<L,N> take a list and a number as a parameter and returns (via the Value typedef, the list composed of the first N element of the list */ -#ifndef Q_COMPILER_VARIADIC_TEMPLATES - template <typename Head, typename Tail> struct List { typedef Head Car; typedef Tail Cdr; }; - template <typename L, int N> struct List_Left { typedef List<typename L::Car, typename List_Left<typename L::Cdr, N - 1>::Value > Value; }; - template <typename L> struct List_Left<L,0> { typedef void Value; }; -#else // With variadic template, lists are represented using a variadic template argument instead of the lisp way template <typename...> struct List {}; template <typename Head, typename... Tail> struct List<Head, Tail...> { typedef Head Car; typedef List<Tail...> Cdr; }; @@ -79,7 +74,6 @@ namespace QtPrivate { typedef typename List_Append<List<typename L::Car>,typename List_Left<typename L::Cdr, N - 1>::Value>::Value Value; }; template <typename L> struct List_Left<L, 0> { typedef List<> Value; }; -#endif // List_Select<L,N> returns (via typedef Value) the Nth element of the list L template <typename L, int N> struct List_Select { typedef typename List_Select<typename L::Cdr, N - 1>::Value Value; }; template <typename L> struct List_Select<L,0> { typedef typename L::Car Value; }; @@ -100,13 +94,11 @@ namespace QtPrivate { if (container.data) *reinterpret_cast<U*>(container.data) = value; } -#ifdef Q_COMPILER_RVALUE_REFS template<typename T, typename U> void operator,(T &&value, const ApplyReturnValue<U> &container) { if (container.data) *reinterpret_cast<U*>(container.data) = value; } -#endif template<typename T> void operator,(T, const ApplyReturnValue<void> &) {} @@ -127,364 +119,6 @@ namespace QtPrivate { The Functor<Func,N> struct is the helper to call a functor of N argument. its call function is the same as the FunctionPointer::call function. */ -#ifndef Q_COMPILER_VARIADIC_TEMPLATES - template<typename Func> struct FunctionPointer { enum {ArgumentCount = -1, IsPointerToMemberFunction = false}; }; - //Pointers to member functions - template<class Obj, typename Ret> struct FunctionPointer<Ret (Obj::*) ()> - { - typedef Obj Object; - typedef void Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (); - enum {ArgumentCount = 0, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { (o->*f)(), ApplyReturnValue<R>(arg[0]); } - }; - template<class Obj, typename Ret, typename Arg1> struct FunctionPointer<Ret (Obj::*) (Arg1)> - { - typedef Obj Object; - typedef List<Arg1, void> Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1); - enum {ArgumentCount = 1, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)((*reinterpret_cast<typename RemoveRef<typename Args::Car>::Type *>(arg[1]))), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2)> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, void> > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2); - enum {ArgumentCount = 2, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3)> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3); - enum {ArgumentCount = 3, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3, Arg4)> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4); - enum {ArgumentCount = 4, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3, Arg4, Arg5)> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, void> > > > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5); - enum {ArgumentCount = 5, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> - struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); - enum {ArgumentCount = 6, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 5>::Value>::Type *>(arg[6])), ApplyReturnValue<R>(arg[0]); - } - }; - - //Pointers to const member functions - template<class Obj, typename Ret> struct FunctionPointer<Ret (Obj::*) () const> - { - typedef Obj Object; - typedef void Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) () const; - enum {ArgumentCount = 0, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { (o->*f)(), ApplyReturnValue<R>(arg[0]); } - }; - template<class Obj, typename Ret, typename Arg1> struct FunctionPointer<Ret (Obj::*) (Arg1) const> - { - typedef Obj Object; - typedef List<Arg1, void> Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1) const; - enum {ArgumentCount = 1, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)((*reinterpret_cast<typename RemoveRef<typename Args::Car>::Type *>(arg[1]))), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2) const> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, void> > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2) const; - enum {ArgumentCount = 2, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3) const> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3) const; - enum {ArgumentCount = 3, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3, Arg4) const> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4) const; - enum {ArgumentCount = 4, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3, Arg4, Arg5) const> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, void> > > > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5) const; - enum {ArgumentCount = 5, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5])), ApplyReturnValue<R>(arg[0]); - } - }; - template<class Obj, typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> - struct FunctionPointer<Ret (Obj::*) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const> - { - typedef Obj Object; - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments; - typedef Ret ReturnType; - typedef Ret (Obj::*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6) const; - enum {ArgumentCount = 6, IsPointerToMemberFunction = true}; - template <typename Args, typename R> - static void call(Function f, Obj *o, void **arg) { - (o->*f)( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 5>::Value>::Type *>(arg[6])), ApplyReturnValue<R>(arg[0]); - } - }; - - //Static functions - template<typename Ret> struct FunctionPointer<Ret (*) ()> - { - typedef void Arguments; - typedef Ret (*Function) (); - typedef Ret ReturnType; - enum {ArgumentCount = 0, IsPointerToMemberFunction = false}; - template <typename Args, typename R> - static void call(Function f, void *, void **arg) { f(), ApplyReturnValue<R>(arg[0]); } - }; - template<typename Ret, typename Arg1> struct FunctionPointer<Ret (*) (Arg1)> - { - typedef List<Arg1, void> Arguments; - typedef Ret ReturnType; - typedef Ret (*Function) (Arg1); - enum {ArgumentCount = 1, IsPointerToMemberFunction = false}; - template <typename Args, typename R> - static void call(Function f, void *, void **arg) - { f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1])), ApplyReturnValue<R>(arg[0]); } - }; - template<typename Ret, typename Arg1, typename Arg2> struct FunctionPointer<Ret (*) (Arg1, Arg2)> - { - typedef List<Arg1, List<Arg2, void> > Arguments; - typedef Ret ReturnType; - typedef Ret (*Function) (Arg1, Arg2); - enum {ArgumentCount = 2, IsPointerToMemberFunction = false}; - template <typename Args, typename R> - static void call(Function f, void *, void **arg) { - f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2])), ApplyReturnValue<R>(arg[0]); } - }; - template<typename Ret, typename Arg1, typename Arg2, typename Arg3> struct FunctionPointer<Ret (*) (Arg1, Arg2, Arg3)> - { - typedef List<Arg1, List<Arg2, List<Arg3, void> > > Arguments; - typedef Ret ReturnType; - typedef Ret (*Function) (Arg1, Arg2, Arg3); - enum {ArgumentCount = 3, IsPointerToMemberFunction = false}; - template <typename Args, typename R> - static void call(Function f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4> struct FunctionPointer<Ret (*) (Arg1, Arg2, Arg3, Arg4)> - { - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, void> > > > Arguments; - typedef Ret ReturnType; - typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4); - enum {ArgumentCount = 4, IsPointerToMemberFunction = false}; - template <typename Args, typename R> - static void call(Function f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> struct FunctionPointer<Ret (*) (Arg1, Arg2, Arg3, Arg4, Arg5)> - { - typedef List<Arg1, List<Arg2, List<Arg3, - List<Arg4, List<Arg5, void > > > > > Arguments; - typedef Ret ReturnType; - typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5); - enum {ArgumentCount = 5, IsPointerToMemberFunction = false}; - template <typename Args, typename R> - static void call(Function f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Ret, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6> struct FunctionPointer<Ret (*) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6)> - { - typedef List<Arg1, List<Arg2, List<Arg3, List<Arg4, List<Arg5, List<Arg6, void> > > > > > Arguments; - typedef Ret ReturnType; - typedef Ret (*Function) (Arg1, Arg2, Arg3, Arg4, Arg5, Arg6); - enum {ArgumentCount = 6, IsPointerToMemberFunction = false}; - template <typename Args, typename R> - static void call(Function f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 5>::Value>::Type *>(arg[6])), ApplyReturnValue<R>(arg[0]); - } - }; - - //Functors - template<typename F, int N> struct Functor; - template<typename Function> struct Functor<Function, 0> - { - template <typename Args, typename R> - static void call(Function &f, void *, void **arg) { f(), ApplyReturnValue<R>(arg[0]); } - }; - template<typename Function> struct Functor<Function, 1> - { - template <typename Args, typename R> - static void call(Function &f, void *, void **arg) { - f(*reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Function> struct Functor<Function, 2> - { - template <typename Args, typename R> - static void call(Function &f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Function> struct Functor<Function, 3> - { - template <typename Args, typename R> - static void call(Function &f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Function> struct Functor<Function, 4> - { - template <typename Args, typename R> - static void call(Function &f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Function> struct Functor<Function, 5> - { - template <typename Args, typename R> - static void call(Function &f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5])), ApplyReturnValue<R>(arg[0]); - } - }; - template<typename Function> struct Functor<Function, 6> - { - template <typename Args, typename R> - static void call(Function &f, void *, void **arg) { - f( *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 0>::Value>::Type *>(arg[1]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 1>::Value>::Type *>(arg[2]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 2>::Value>::Type *>(arg[3]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 3>::Value>::Type *>(arg[4]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 4>::Value>::Type *>(arg[5]), - *reinterpret_cast<typename RemoveRef<typename List_Select<Args, 5>::Value>::Type *>(arg[6])), ApplyReturnValue<R>(arg[0]); - } - }; -#else template <int...> struct IndexesList {}; template <typename IndexList, int Right> struct IndexesAppend; template <int... Left, int Right> struct IndexesAppend<IndexesList<Left...>, Right> @@ -558,7 +192,6 @@ namespace QtPrivate { FunctorCall<typename Indexes<N>::Value, SignalArgs, R, Function>::call(f, arg); } }; -#endif /* Logic that check if the arguments of the slot matches the argument of the signal. @@ -578,16 +211,6 @@ namespace QtPrivate { template<typename A> struct AreArgumentsCompatible<A, void> { enum { value = true }; }; template<> struct AreArgumentsCompatible<void, void> { enum { value = true }; }; -#ifndef Q_COMPILER_VARIADIC_TEMPLATES - template <typename List1, typename List2> struct CheckCompatibleArguments { enum { value = false }; }; - template <> struct CheckCompatibleArguments<void, void> { enum { value = true }; }; - template <typename List1> struct CheckCompatibleArguments<List1, void> { enum { value = true }; }; - template <typename Arg1, typename Arg2, typename Tail1, typename Tail2> struct CheckCompatibleArguments<List<Arg1, Tail1>, List<Arg2, Tail2> > - { - enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value - && CheckCompatibleArguments<Tail1, Tail2>::value }; - }; -#else template <typename List1, typename List2> struct CheckCompatibleArguments { enum { value = false }; }; template <> struct CheckCompatibleArguments<List<>, List<>> { enum { value = true }; }; template <typename List1> struct CheckCompatibleArguments<List1, List<>> { enum { value = true }; }; @@ -597,9 +220,7 @@ namespace QtPrivate { enum { value = AreArgumentsCompatible<typename RemoveConstRef<Arg1>::Type, typename RemoveConstRef<Arg2>::Type>::value && CheckCompatibleArguments<List<Tail1...>, List<Tail2...>>::value }; }; -#endif -#if defined(Q_COMPILER_VARIADIC_TEMPLATES) /* Find the maximum number of arguments a functor object can take and be still compatible with the arguments from the signal. @@ -631,8 +252,6 @@ namespace QtPrivate { template <typename D> static D dummy(); typedef decltype(dummy<Functor>().operator()((dummy<ArgList>())...)) Value; }; -#endif - } QT_END_NAMESPACE diff --git a/src/corelib/mimetypes/qmimemagicrule.cpp b/src/corelib/mimetypes/qmimemagicrule.cpp index 0db3407b7b..8461bf7130 100644 --- a/src/corelib/mimetypes/qmimemagicrule.cpp +++ b/src/corelib/mimetypes/qmimemagicrule.cpp @@ -48,7 +48,6 @@ #include <QtCore/QList> #include <QtCore/QDebug> #include <qendian.h> -#include <private/qsimd_p.h> // for qUnalignedLoad QT_BEGIN_NAMESPACE @@ -164,7 +163,7 @@ bool QMimeMagicRule::matchNumber(const QByteArray &data) const const char *p = data.constData() + m_startPos; const char *e = data.constData() + qMin(data.size() - int(sizeof(T)), m_endPos + 1); for ( ; p <= e; ++p) { - if ((qUnalignedLoad<T>(p) & mask) == (value & mask)) + if ((qFromUnaligned<T>(reinterpret_cast<const uchar *>(p)) & mask) == (value & mask)) return true; } diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp index 25444ffff6..17072f44d4 100644 --- a/src/corelib/thread/qmutex_linux.cpp +++ b/src/corelib/thread/qmutex_linux.cpp @@ -57,7 +57,7 @@ #endif #ifndef FUTEX_PRIVATE_FLAG -# define FUTEX_PRIVATE_FLAG 128 +# define FUTEX_PRIVATE_FLAG 0 #endif diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp index 36f1997a6c..55af7256be 100644 --- a/src/corelib/tools/qarraydata.cpp +++ b/src/corelib/tools/qarraydata.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -87,29 +88,20 @@ QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment, if (!(options & RawData)) headerSize += (alignment - Q_ALIGNOF(QArrayData)); - // Allocate additional space if array is growing - if (options & Grow) { - - // Guard against integer overflow when multiplying. - if (capacity > std::numeric_limits<size_t>::max() / objectSize) - return 0; - - size_t alloc; - if (mul_overflow(objectSize, capacity, &alloc)) - return 0; - - // Make sure qAllocMore won't overflow qAllocMore. - if (headerSize > size_t(MaxAllocSize) || alloc > size_t(MaxAllocSize) - headerSize) - return 0; - - capacity = qAllocMore(int(alloc), int(headerSize)) / int(objectSize); - } + if (headerSize > size_t(MaxAllocSize)) + return 0; + // Calculate the byte size + // allocSize = objectSize * capacity + headerSize, but checked for overflow + // plus padded to grow in size size_t allocSize; - if (mul_overflow(objectSize, capacity, &allocSize)) - return 0; - if (add_overflow(allocSize, headerSize, &allocSize)) - return 0; + if (options & Grow) { + auto r = qCalculateGrowingBlockSize(capacity, objectSize, headerSize); + capacity = r.elementCount; + allocSize = r.size; + } else { + allocSize = qCalculateBlockSize(capacity, objectSize, headerSize); + } QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize)); if (header) { diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp index 446e09b1c0..12e4687b3c 100644 --- a/src/corelib/tools/qbitarray.cpp +++ b/src/corelib/tools/qbitarray.cpp @@ -42,6 +42,7 @@ #include <qalgorithms.h> #include <qdatastream.h> #include <qdebug.h> +#include <qendian.h> #include <string.h> QT_BEGIN_NAMESPACE @@ -169,25 +170,6 @@ QBitArray::QBitArray(int size, bool value) Same as size(). */ -template <typename T> T qUnalignedLoad(const uchar *ptr) -{ - /* - * Testing with different compilers shows that they all optimize the memcpy - * call away and replace with direct loads whenever possible. On x86 and PPC, - * GCC does direct unaligned loads; on MIPS, it generates a pair of load-left - * and load-right instructions. ICC and Clang do the same on x86. This is both - * 32- and 64-bit. - * - * On ARM cores without unaligned loads, the compiler leaves a call to - * memcpy. - */ - - T u; - memcpy(&u, ptr, sizeof(u)); - return u; -} - - /*! If \a on is true, this function returns the number of 1-bits stored in the bit array; otherwise the number @@ -203,17 +185,17 @@ int QBitArray::count(bool on) const const quint8 *const end = reinterpret_cast<const quint8 *>(d.end()); while (bits + 7 <= end) { - quint64 v = qUnalignedLoad<quint64>(bits); + quint64 v = qFromUnaligned<quint64>(bits); bits += 8; numBits += int(qPopulationCount(v)); } if (bits + 3 <= end) { - quint32 v = qUnalignedLoad<quint32>(bits); + quint32 v = qFromUnaligned<quint32>(bits); bits += 4; numBits += int(qPopulationCount(v)); } if (bits + 1 < end) { - quint16 v = qUnalignedLoad<quint16>(bits); + quint16 v = qFromUnaligned<quint16>(bits); bits += 2; numBits += int(qPopulationCount(v)); } diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index a256b44b1f..266c2e9b57 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -46,6 +46,7 @@ #include "qlocale.h" #include "qlocale_p.h" #include "qlocale_tools_p.h" +#include "private/qnumeric_p.h" #include "qstringalgorithms_p.h" #include "qscopedpointer.h" #include "qbytearray_p.h" @@ -128,17 +129,104 @@ int qFindByteArray( const char *haystack0, int haystackLen, int from, const char *needle0, int needleLen); +/* + * This pair of functions is declared in qtools_p.h and is used by the Qt + * containers to allocate memory and grow the memory block during append + * operations. + * + * They take size_t parameters and return size_t so they will change sizes + * according to the pointer width. However, knowing Qt containers store the + * container size and element indexes in ints, these functions never return a + * size larger than INT_MAX. This is done by casting the element count and + * memory block size to int in several comparisons: the check for negative is + * very fast on most platforms as the code only needs to check the sign bit. + * + * These functions return SIZE_MAX on overflow, which can be passed to malloc() + * and will surely cause a NULL return (there's no way you can allocate a + * memory block the size of your entire VM space). + */ + +/*! + \internal + \since 5.7 -int qAllocMore(int alloc, int extra) Q_DECL_NOTHROW + Returns the memory block size for a container containing \a elementCount + elements, each of \a elementSize bytes, plus a header of \a headerSize + bytes. That is, this function returns \c + {elementCount * elementSize + headerSize} + + but unlike the simple calculation, it checks for overflows during the + multiplication and the addition. + + Both \a elementCount and \a headerSize can be zero, but \a elementSize + cannot. + + This function returns SIZE_MAX (~0) on overflow or if the memory block size + would not fit an int. +*/ +size_t qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t headerSize) Q_DECL_NOTHROW { - Q_ASSERT(alloc >= 0 && extra >= 0 && extra <= MaxAllocSize); - Q_ASSERT_X(alloc <= MaxAllocSize - extra, "qAllocMore", "Requested size is too large!"); + unsigned count = unsigned(elementCount); + unsigned size = unsigned(elementSize); + unsigned header = unsigned(headerSize); + Q_ASSERT(elementSize); + Q_ASSERT(size == elementSize); + Q_ASSERT(header == headerSize); + + if (Q_UNLIKELY(count != elementCount)) + return std::numeric_limits<size_t>::max(); + + unsigned bytes; + if (Q_UNLIKELY(mul_overflow(size, count, &bytes)) || + Q_UNLIKELY(add_overflow(bytes, header, &bytes))) + return std::numeric_limits<size_t>::max(); + if (Q_UNLIKELY(int(bytes) < 0)) // catches bytes >= 2GB + return std::numeric_limits<size_t>::max(); + + return bytes; +} + +/*! + \internal + \since 5.7 - unsigned nalloc = qNextPowerOfTwo(alloc + extra); + Returns the memory block size and the number of elements that will fit in + that block for a container containing \a elementCount elements, each of \a + elementSize bytes, plus a header of \a headerSize bytes. This function + assumes the container will grow and pre-allocates a growth factor. - Q_ASSERT(nalloc > unsigned(alloc + extra)); + Both \a elementCount and \a headerSize can be zero, but \a elementSize + cannot. + + This function returns SIZE_MAX (~0) on overflow or if the memory block size + would not fit an int. + + \note The memory block may contain up to \a elementSize - 1 bytes more than + needed. +*/ +CalculateGrowingBlockSizeResult +qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t headerSize) Q_DECL_NOTHROW +{ + CalculateGrowingBlockSizeResult result = { + std::numeric_limits<size_t>::max(),std::numeric_limits<size_t>::max() + }; + + unsigned bytes = unsigned(qCalculateBlockSize(elementCount, elementSize, headerSize)); + if (int(bytes) < 0) // catches std::numeric_limits<size_t>::max() + return result; + + unsigned morebytes = qNextPowerOfTwo(bytes); + if (Q_UNLIKELY(int(morebytes) < 0)) { + // catches morebytes == 2GB + // grow by half the difference between bytes and morebytes + bytes += (morebytes - bytes) / 2; + } else { + bytes = morebytes; + } - return nalloc - extra; + result.elementCount = (bytes - unsigned(headerSize)) / unsigned(elementSize); + result.size = bytes; + return result; } /***************************************************************************** @@ -1618,12 +1706,16 @@ void QByteArray::reallocData(uint alloc, Data::AllocationOptions options) Data::deallocate(d); d = x; } else { + size_t blockSize; if (options & Data::Grow) { - if (alloc > MaxByteArraySize) - qBadAlloc(); - alloc = qAllocMore(alloc, sizeof(Data)); + auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data)); + blockSize = r.size; + alloc = uint(r.elementCount); + } else { + blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data)); } - Data *x = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc)); + + Data *x = static_cast<Data *>(::realloc(d, blockSize)); Q_CHECK_PTR(x); x->alloc = alloc; x->capacityReserved = (options & Data::CapacityReserved) ? 1 : 0; diff --git a/src/corelib/tools/qcryptographichash.cpp b/src/corelib/tools/qcryptographichash.cpp index 3cb3606013..08f89d2f02 100644 --- a/src/corelib/tools/qcryptographichash.cpp +++ b/src/corelib/tools/qcryptographichash.cpp @@ -95,9 +95,29 @@ static SHA3Final * const sha3Final = Final; available on all platforms (MSVC 2008, for example), we #define them to the Qt equivalents. */ + +#ifdef uint64_t +#undef uint64_t +#endif + #define uint64_t QT_PREPEND_NAMESPACE(quint64) + +#ifdef uint32_t +#undef uint32_t +#endif + #define uint32_t QT_PREPEND_NAMESPACE(quint32) + +#ifdef uint8_t +#undef uint8_t +#endif + #define uint8_t QT_PREPEND_NAMESPACE(quint8) + +#ifdef int_least16_t +#undef int_least16_t +#endif + #define int_least16_t QT_PREPEND_NAMESPACE(qint16) // Header from rfc6234 with 1 modification: diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 02afacb861..2ebf7c7977 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -2158,7 +2158,7 @@ static int qt_timezone() // number of seconds west of UTC. // - It also takes DST into account, so we need to adjust it to always // get the Standard Time offset. - return -t.tm_gmtoff + (t.tm_isdst ? SECS_PER_HOUR : 0L); + return -t.tm_gmtoff + (t.tm_isdst ? (long)SECS_PER_HOUR : 0L); #elif defined(Q_OS_INTEGRITY) return 0; #else diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index cc8c08d5b1..9c9009d636 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -708,17 +708,18 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde } const int sectionmaxsize = sectionMaxSize(sectionIndex); - QString sectiontext = text.mid(index, sectionmaxsize); - int sectiontextSize = sectiontext.size(); + QStringRef sectionTextRef = text.midRef(index, sectionmaxsize); + int sectiontextSize = sectionTextRef.size(); QDTPDEBUG << "sectionValue for" << sn.name() - << "with text" << text << "and st" << sectiontext + << "with text" << text << "and st" << sectionTextRef << text.midRef(index, sectionmaxsize) << index; int used = 0; switch (sn.type) { case AmPmSection: { + QString sectiontext = sectionTextRef.toString(); const int ampm = findAmPm(sectiontext, sectionIndex, &used); switch (ampm) { case AM: // sectiontext == AM @@ -750,6 +751,7 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde case DayOfWeekSectionShort: case DayOfWeekSectionLong: if (sn.count >= 3) { + QString sectiontext = sectionTextRef.toString(); if (sn.type == MonthSection) { int min = 1; const QDate minDate = getMinimum().date(); @@ -788,7 +790,7 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde int last = -1; used = -1; - QString digitsStr(sectiontext); + QStringRef digitsStr = sectionTextRef; for (int i = 0; i < sectiontextSize; ++i) { if (digitsStr.at(i).isSpace()) { sectiontextSize = i; @@ -809,7 +811,7 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde } } if (ok && tmp <= absMax) { - QDTPDEBUG << sectiontext.leftRef(digits) << tmp << digits; + QDTPDEBUG << sectionTextRef.left(digits) << tmp << digits; last = tmp; used = digits; break; @@ -817,13 +819,13 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde } if (last == -1) { - QChar first(sectiontext.at(0)); + QChar first(sectionTextRef.at(0)); if (separators.at(sectionIndex + 1).startsWith(first)) { used = 0; state = Intermediate; } else { state = Invalid; - QDTPDEBUG << "invalid because" << sectiontext << "can't become a uint" << last << ok; + QDTPDEBUG << "invalid because" << sectionTextRef << "can't become a uint" << last << ok; } } else { num += last; @@ -1565,7 +1567,7 @@ QString QDateTimeParser::SectionNode::format() const number that is within min and max. */ -bool QDateTimeParser::potentialValue(const QString &str, int min, int max, int index, +bool QDateTimeParser::potentialValue(const QStringRef &str, int min, int max, int index, const QDateTime ¤tValue, int insert) const { if (str.isEmpty()) { @@ -1592,8 +1594,7 @@ bool QDateTimeParser::potentialValue(const QString &str, int min, int max, int i if (potentialValue(str + QLatin1Char('0' + j), min, max, index, currentValue, insert)) { return true; } else if (insert >= 0) { - QString tmp = str; - tmp.insert(insert, QLatin1Char('0' + j)); + const QString tmp = str.left(insert) + QLatin1Char('0' + j) + str.mid(insert); if (potentialValue(tmp, min, max, index, currentValue, insert)) return true; } @@ -1603,7 +1604,7 @@ bool QDateTimeParser::potentialValue(const QString &str, int min, int max, int i return false; } -bool QDateTimeParser::skipToNextSection(int index, const QDateTime ¤t, const QString &text) const +bool QDateTimeParser::skipToNextSection(int index, const QDateTime ¤t, const QStringRef &text) const { Q_ASSERT(current >= getMinimum() && current <= getMaximum()); diff --git a/src/corelib/tools/qdatetimeparser_p.h b/src/corelib/tools/qdatetimeparser_p.h index 9689d88616..01a2f20802 100644 --- a/src/corelib/tools/qdatetimeparser_p.h +++ b/src/corelib/tools/qdatetimeparser_p.h @@ -214,9 +214,19 @@ public: QString *dayName = 0, int *used = 0) const; #endif AmPmFinder findAmPm(QString &str, int index, int *used = 0) const; - bool potentialValue(const QString &str, int min, int max, int index, + bool potentialValue(const QStringRef &str, int min, int max, int index, const QDateTime ¤tValue, int insert) const; - bool skipToNextSection(int section, const QDateTime ¤t, const QString §ionText) const; + bool potentialValue(const QString &str, int min, int max, int index, + const QDateTime ¤tValue, int insert) const + { + return potentialValue(QStringRef(&str), min, max, index, currentValue, insert); + } + + bool skipToNextSection(int section, const QDateTime ¤t, const QStringRef §ionText) const; + bool skipToNextSection(int section, const QDateTime ¤t, const QString §ionText) const + { + return skipToNextSection(section, current, QStringRef(§ionText)); + } QString stateName(State s) const; diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 2f0886edce..593a87e65d 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -58,6 +58,7 @@ #include <qbytearray.h> #include <qdatetime.h> #include <qbasicatomic.h> +#include <qendian.h> #include <private/qsimd_p.h> #ifndef QT_BOOTSTRAPPED @@ -112,24 +113,24 @@ static uint crc32(const Char *ptr, size_t len, uint h) p += 8; for ( ; p <= e; p += 8) - h2 = _mm_crc32_u64(h2, qUnalignedLoad<qlonglong>(p - 8)); + h2 = _mm_crc32_u64(h2, qFromUnaligned<qlonglong>(p - 8)); h = h2; p -= 8; len = e - p; if (len & 4) { - h = _mm_crc32_u32(h, qUnalignedLoad<uint>(p)); + h = _mm_crc32_u32(h, qFromUnaligned<uint>(p)); p += 4; } # else p += 4; for ( ; p <= e; p += 4) - h = _mm_crc32_u32(h, qUnalignedLoad<uint>(p - 4)); + h = _mm_crc32_u32(h, qFromUnaligned<uint>(p - 4)); p -= 4; len = e - p; # endif if (len & 2) { - h = _mm_crc32_u16(h, qUnalignedLoad<ushort>(p)); + h = _mm_crc32_u16(h, qFromUnaligned<ushort>(p)); p += 2; } if (sizeof(Char) == 1 && len & 1) diff --git a/src/corelib/tools/qlist.cpp b/src/corelib/tools/qlist.cpp index 7dd02bf954..1762da2c8f 100644 --- a/src/corelib/tools/qlist.cpp +++ b/src/corelib/tools/qlist.cpp @@ -60,15 +60,6 @@ QT_BEGIN_NAMESPACE const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, { 0 } }; -static int grow(int size) -{ - if (size_t(size) > (MaxAllocSize - QListData::DataHeaderSize) / sizeof(void *)) - qBadAlloc(); - // dear compiler: don't optimize me out. - volatile int x = qAllocMore(size * sizeof(void *), QListData::DataHeaderSize) / sizeof(void *); - return x; -} - /*! * Detaches the QListData by allocating new memory for a list which will be bigger * than the copied one and is expected to grow further. @@ -84,12 +75,12 @@ QListData::Data *QListData::detach_grow(int *idx, int num) Data *x = d; int l = x->end - x->begin; int nl = l + num; - int alloc = grow(nl); - Data* t = static_cast<Data *>(::malloc(DataHeaderSize + alloc * sizeof(void *))); + auto blockInfo = qCalculateGrowingBlockSize(nl, sizeof(void *), DataHeaderSize); + Data* t = static_cast<Data *>(::malloc(blockInfo.size)); Q_CHECK_PTR(t); + t->alloc = int(uint(blockInfo.elementCount)); t->ref.initializeOwned(); - t->alloc = alloc; // The space reservation algorithm's optimization is biased towards appending: // Something which looks like an append will put the data at the beginning, // while something which looks like a prepend will put it in the middle @@ -99,12 +90,12 @@ QListData::Data *QListData::detach_grow(int *idx, int num) int bg; if (*idx < 0) { *idx = 0; - bg = (alloc - nl) >> 1; + bg = (t->alloc - nl) >> 1; } else if (*idx > l) { *idx = l; bg = 0; } else if (*idx < (l >> 1)) { - bg = (alloc - nl) >> 1; + bg = (t->alloc - nl) >> 1; } else { bg = 0; } @@ -126,7 +117,7 @@ QListData::Data *QListData::detach_grow(int *idx, int num) QListData::Data *QListData::detach(int alloc) { Data *x = d; - Data* t = static_cast<Data *>(::malloc(DataHeaderSize + alloc * sizeof(void *))); + Data* t = static_cast<Data *>(::malloc(qCalculateBlockSize(alloc, sizeof(void*), DataHeaderSize))); Q_CHECK_PTR(t); t->ref.initializeOwned(); @@ -146,7 +137,7 @@ QListData::Data *QListData::detach(int alloc) void QListData::realloc(int alloc) { Q_ASSERT(!d->ref.isShared()); - Data *x = static_cast<Data *>(::realloc(d, DataHeaderSize + alloc * sizeof(void *))); + Data *x = static_cast<Data *>(::realloc(d, qCalculateBlockSize(alloc, sizeof(void *), DataHeaderSize))); Q_CHECK_PTR(x); d = x; @@ -158,12 +149,12 @@ void QListData::realloc(int alloc) void QListData::realloc_grow(int growth) { Q_ASSERT(!d->ref.isShared()); - int alloc = grow(d->alloc + growth); - Data *x = static_cast<Data *>(::realloc(d, DataHeaderSize + alloc * sizeof(void *))); + auto r = qCalculateGrowingBlockSize(d->alloc + growth, sizeof(void *), DataHeaderSize); + Data *x = static_cast<Data *>(::realloc(d, r.size)); Q_CHECK_PTR(x); d = x; - d->alloc = alloc; + d->alloc = int(uint(r.elementCount)); } void QListData::dispose(Data *d) diff --git a/src/corelib/tools/qmessageauthenticationcode.cpp b/src/corelib/tools/qmessageauthenticationcode.cpp index 9b91474283..9a84191452 100644 --- a/src/corelib/tools/qmessageauthenticationcode.cpp +++ b/src/corelib/tools/qmessageauthenticationcode.cpp @@ -46,9 +46,29 @@ available on all platforms (MSVC 2008, for example), we #define them to the Qt equivalents. */ + +#ifdef uint64_t +#undef uint64_t +#endif + #define uint64_t QT_PREPEND_NAMESPACE(quint64) + +#ifdef uint32_t +#undef uint32_t +#endif + #define uint32_t QT_PREPEND_NAMESPACE(quint32) + +#ifdef uint8_t +#undef uint8_t +#endif + #define uint8_t QT_PREPEND_NAMESPACE(quint8) + +#ifdef int_least16_t +#undef int_least16_t +#endif + #define int_least16_t QT_PREPEND_NAMESPACE(qint16) // Header from rfc6234 with 1 modification: diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index 7b1d94c501..d4edf459de 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -724,26 +724,4 @@ void qDumpCPUFeatures() puts(""); } -/*! - \internal - \fn T qUnalignedLoad(const void *ptr) - \since 5.6.1 - - Loads a \c{T} from address \a ptr, which may be misaligned. - - Use of this function avoid the undefined behavior that the C++ standard - otherwise attributes to unaligned loads. -*/ - -/*! - \internal - \fn void qUnalignedStore(void *ptr, T t) - \since 5.6.1 - - Stores \a t to address \a ptr, which may be misaligned. - - Use of this function avoid the undefined behavior that the C++ standard - otherwise attributes to unaligned stores. -*/ - QT_END_NAMESPACE diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 6c1ee25234..c79bced52e 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -581,7 +581,7 @@ static int ucstrncmp(const QChar *a, const uchar *c, int l) // we'll read uc[offset..offset+7] (16 bytes) and c[offset..offset+7] (8 bytes) if (uc + offset + 7 < e) { // same, but we're using an 8-byte load - __m128i chunk = _mm_cvtsi64_si128(qUnalignedLoad<long long>(c + offset)); + __m128i chunk = _mm_cvtsi64_si128(qFromUnaligned<long long>(c + offset)); __m128i secondHalf = _mm_unpacklo_epi8(chunk, nullmask); __m128i ucdata = _mm_loadu_si128((const __m128i*)(uc + offset)); @@ -1757,10 +1757,13 @@ void QString::resize(int size, QChar fillChar) void QString::reallocData(uint alloc, bool grow) { + size_t blockSize; if (grow) { - if (alloc > (uint(MaxAllocSize) - sizeof(Data)) / sizeof(QChar)) - qBadAlloc(); - alloc = qAllocMore(alloc * sizeof(QChar), sizeof(Data)) / sizeof(QChar); + auto r = qCalculateGrowingBlockSize(alloc, sizeof(QChar), sizeof(Data)); + blockSize = r.size; + alloc = uint(r.elementCount); + } else { + blockSize = qCalculateBlockSize(alloc, sizeof(QChar), sizeof(Data)); } if (d->ref.isShared() || IS_RAW_DATA(d)) { @@ -1774,7 +1777,7 @@ void QString::reallocData(uint alloc, bool grow) Data::deallocate(d); d = x; } else { - Data *p = static_cast<Data *>(::realloc(d, sizeof(Data) + alloc * sizeof(QChar))); + Data *p = static_cast<Data *>(::realloc(d, blockSize)); Q_CHECK_PTR(p); d = p; d->alloc = alloc; @@ -2343,8 +2346,7 @@ QString &QString::remove(QChar ch, Qt::CaseSensitivity cs) */ QString &QString::replace(int pos, int len, const QString &after) { - QString copy = after; - return replace(pos, len, copy.constData(), copy.length()); + return replace(pos, len, after.constData(), after.length()); } /*! diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 8040365581..c2630c8593 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -47,6 +47,8 @@ #include <qdebug.h> +#include "qlocale_tools_p.h" + #include <algorithm> QT_BEGIN_NAMESPACE @@ -376,39 +378,126 @@ static QDate calculatePosixDate(const QByteArray &dateRule, int year) } } -static QTime parsePosixTime(const QByteArray &timeRule) +// returns the time in seconds, INT_MIN if we failed to parse +static int parsePosixTime(const char *begin, const char *end) { - // Format "HH:mm:ss", put check parts count just in case - QList<QByteArray> parts = timeRule.split(':'); - int count = parts.count(); - if (count == 3) - return QTime(parts.at(0).toInt(), parts.at(1).toInt(), parts.at(2).toInt()); - else if (count == 2) - return QTime(parts.at(0).toInt(), parts.at(1).toInt(), 0); - else if (count == 1) - return QTime(parts.at(0).toInt(), 0, 0); - return QTime(2, 0, 0); + // Format "hh[:mm[:ss]]" + int hour, min = 0, sec = 0; + + // Note that the calls to qstrtoll do *not* check the end pointer, which + // means they proceed until they find a non-digit. We check that we're + // still in range at the end, but we may have read from past end. It's the + // caller's responsibility to ensure that begin is part of a + // null-terminated string. + + bool ok = false; + hour = qstrtoll(begin, &begin, 10, &ok); + if (!ok || hour < 0) + return INT_MIN; + if (begin < end && *begin == ':') { + // minutes + ++begin; + min = qstrtoll(begin, &begin, 10, &ok); + if (!ok || min < 0) + return INT_MIN; + + if (begin < end && *begin == ':') { + // seconds + ++begin; + sec = qstrtoll(begin, &begin, 10, &ok); + if (!ok || sec < 0) + return INT_MIN; + } + } + + // we must have consumed everything + if (begin != end) + return INT_MIN; + + return (hour * 60 + min) * 60 + sec; } -static int parsePosixOffset(const QByteArray &timeRule) +static QTime parsePosixTransitionTime(const QByteArray &timeRule) +{ + // Format "hh[:mm[:ss]]" + int value = parsePosixTime(timeRule.constBegin(), timeRule.constEnd()); + if (value == INT_MIN) { + // if we failed to parse, return 02:00 + return QTime(2, 0, 0); + } + return QTime::fromMSecsSinceStartOfDay(value * 1000); +} + +static int parsePosixOffset(const char *begin, const char *end) { // Format "[+|-]hh[:mm[:ss]]" - QList<QByteArray> parts = timeRule.split(':'); - int count = parts.count(); - if (count == 3) { - int hour = parts.at(0).toInt(); - int sign = hour >= 0 ? -1 : 1; - return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60) + parts.at(2).toInt()); - } else if (count == 2) { - int hour = parts.at(0).toInt(); - int sign = hour >= 0 ? -1 : 1; - return sign * ((qAbs(hour) * 60 * 60) + (parts.at(1).toInt() * 60)); - } else if (count == 1) { - int hour = parts.at(0).toInt(); - int sign = hour >= 0 ? -1 : 1; - return sign * (qAbs(hour) * 60 * 60); - } - return 0; + // note that the sign is inverted because POSIX counts in hours West of GMT + bool negate = true; + if (*begin == '+') { + ++begin; + } else if (*begin == '-') { + negate = false; + ++begin; + } + + int value = parsePosixTime(begin, end); + if (value == INT_MIN) + return value; + return negate ? -value : value; +} + +static inline bool asciiIsLetter(char ch) +{ + ch |= 0x20; // lowercases if it is a letter, otherwise just corrupts ch + return ch >= 'a' && ch <= 'z'; +} + +// Returns the zone name, the offset (in seconds) and advances \a begin to +// where the parsing ended. Returns a zone of INT_MIN in case an offset +// couldn't be read. +static QPair<QString, int> parsePosixZoneNameAndOffset(const char *&pos, const char *end) +{ + static const char offsetChars[] = "0123456789:"; + QPair<QString, int> result = qMakePair(QString(), INT_MIN); + + const char *nameBegin = pos; + const char *nameEnd; + Q_ASSERT(pos < end); + + if (*pos == '<') { + nameBegin = pos + 1; // skip the '<' + nameEnd = nameBegin; + while (nameEnd < end && *nameEnd != '>') { + // POSIX says only alphanumeric, but we allow anything + ++nameEnd; + } + pos = nameEnd + 1; // skip the '>' + } else { + nameBegin = pos; + nameEnd = nameBegin; + while (nameEnd < end && asciiIsLetter(*nameEnd)) + ++nameEnd; + pos = nameEnd; + } + if (nameEnd - nameBegin < 3) + return result; // name must be at least 3 characters long + + // zone offset, form [+-]hh:mm:ss + const char *zoneBegin = pos; + const char *zoneEnd = pos; + if (zoneEnd < end && (zoneEnd[0] == '+' || zoneEnd[0] == '-')) + ++zoneEnd; + while (zoneEnd < end) { + if (strchr(offsetChars, char(*zoneEnd)) == NULL) + break; + ++zoneEnd; + } + + result.first = QString::fromUtf8(nameBegin, nameEnd - nameBegin); + if (zoneEnd > zoneBegin) + result.second = parsePosixOffset(zoneBegin, zoneEnd); + pos = zoneEnd; + return result; } static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArray &posixRule, @@ -425,58 +514,45 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra // POSIX Format is like "TZ=CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00" // i.e. "std offset dst [offset],start[/time],end[/time]" - // See http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html + // See the section about TZ at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html QList<QByteArray> parts = posixRule.split(','); - QString name = QString::fromUtf8(parts.at(0)); - QString stdName; - QString stdOffsetString; - QString dstName; - QString dstOffsetString; - bool parsedStdName = false; - bool parsedStdOffset = false; - for (int i = 0; i < name.size(); ++i) { - if (name.at(i).isLetter()) { - if (parsedStdName) { - parsedStdOffset = true; - dstName.append(name.at(i)); - } else { - stdName.append(name.at(i)); + QPair<QString, int> stdZone, dstZone; + { + const QByteArray &zoneinfo = parts.at(0); + const char *begin = zoneinfo.constBegin(); + + stdZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd()); + if (stdZone.second == INT_MIN) { + stdZone.second = 0; // reset to UTC if we failed to parse + } else if (begin < zoneinfo.constEnd()) { + dstZone = parsePosixZoneNameAndOffset(begin, zoneinfo.constEnd()); + if (dstZone.second == INT_MIN) { + // if the dst offset isn't provided, it is 1 hour ahead of the standard offset + dstZone.second = stdZone.second + (60 * 60); } - } else { - parsedStdName = true; - if (parsedStdOffset) - dstOffsetString.append(name.at(i)); - else - stdOffsetString.append(name.at(i)); } } - int utcOffset = parsePosixOffset(stdOffsetString.toUtf8()); - // If only the name part then no transitions if (parts.count() == 1) { QTimeZonePrivate::Data data; data.atMSecsSinceEpoch = lastTranMSecs; - data.offsetFromUtc = utcOffset; - data.standardTimeOffset = utcOffset; + data.offsetFromUtc = stdZone.second; + data.standardTimeOffset = stdZone.second; data.daylightTimeOffset = 0; - data.abbreviation = stdName; + data.abbreviation = stdZone.first; result << data; return result; } - // If not populated the total dst offset is 1 hour - int dstOffset = utcOffset + (60 * 60); - if (!dstOffsetString.isEmpty()) - dstOffset = parsePosixOffset(dstOffsetString.toUtf8()); // Get the std to dst transtion details QList<QByteArray> dstParts = parts.at(1).split('/'); QByteArray dstDateRule = dstParts.at(0); QTime dstTime; if (dstParts.count() > 1) - dstTime = parsePosixTime(dstParts.at(1)); + dstTime = parsePosixTransitionTime(dstParts.at(1)); else dstTime = QTime(2, 0, 0); @@ -485,25 +561,25 @@ static QVector<QTimeZonePrivate::Data> calculatePosixTransitions(const QByteArra QByteArray stdDateRule = stdParts.at(0); QTime stdTime; if (stdParts.count() > 1) - stdTime = parsePosixTime(stdParts.at(1)); + stdTime = parsePosixTransitionTime(stdParts.at(1)); else stdTime = QTime(2, 0, 0); for (int year = startYear; year <= endYear; ++year) { QTimeZonePrivate::Data dstData; QDateTime dst(calculatePosixDate(dstDateRule, year), dstTime, Qt::UTC); - dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (utcOffset * 1000); - dstData.offsetFromUtc = dstOffset; - dstData.standardTimeOffset = utcOffset; - dstData.daylightTimeOffset = dstOffset - utcOffset; - dstData.abbreviation = dstName; + dstData.atMSecsSinceEpoch = dst.toMSecsSinceEpoch() - (stdZone.second * 1000); + dstData.offsetFromUtc = dstZone.second; + dstData.standardTimeOffset = stdZone.second; + dstData.daylightTimeOffset = dstZone.second - stdZone.second; + dstData.abbreviation = dstZone.first; QTimeZonePrivate::Data stdData; QDateTime std(calculatePosixDate(stdDateRule, year), stdTime, Qt::UTC); - stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstOffset * 1000); - stdData.offsetFromUtc = utcOffset; - stdData.standardTimeOffset = utcOffset; + stdData.atMSecsSinceEpoch = std.toMSecsSinceEpoch() - (dstZone.second * 1000); + stdData.offsetFromUtc = stdZone.second; + stdData.standardTimeOffset = stdZone.second; stdData.daylightTimeOffset = 0; - stdData.abbreviation = stdName; + stdData.abbreviation = stdZone.first; // Part of the high year will overflow if (year == 292278994 && (dstData.atMSecsSinceEpoch < 0 || stdData.atMSecsSinceEpoch < 0)) { if (dstData.atMSecsSinceEpoch > 0) { diff --git a/src/corelib/tools/qtools_p.h b/src/corelib/tools/qtools_p.h index 5ec153c818..09adee5586 100644 --- a/src/corelib/tools/qtools_p.h +++ b/src/corelib/tools/qtools_p.h @@ -52,7 +52,7 @@ // #include "QtCore/qglobal.h" -#include <limits> +#include <limits.h> QT_BEGIN_NAMESPACE @@ -88,11 +88,19 @@ Q_DECL_CONSTEXPR inline int fromOct(uint c) Q_DECL_NOTHROW // We typically need an extra bit for qNextPowerOfTwo when determining the next allocation size. enum { - MaxAllocSize = (1 << (std::numeric_limits<int>::digits - 1)) - 1 + MaxAllocSize = INT_MAX +}; + +struct CalculateGrowingBlockSizeResult { + size_t size; + size_t elementCount; }; // implemented in qbytearray.cpp -int Q_CORE_EXPORT qAllocMore(int alloc, int extra) Q_DECL_NOTHROW; +size_t Q_CORE_EXPORT Q_DECL_CONST_FUNCTION +qCalculateBlockSize(size_t elementCount, size_t elementSize, size_t headerSize = 0) Q_DECL_NOTHROW; +CalculateGrowingBlockSizeResult Q_CORE_EXPORT Q_DECL_CONST_FUNCTION +qCalculateGrowingBlockSize(size_t elementCount, size_t elementSize, size_t headerSize = 0) Q_DECL_NOTHROW ; QT_END_NAMESPACE diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index fea50f4c34..b68ca87063 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -736,7 +736,7 @@ typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend) const int itemsUntouched = abegin - d->begin(); // FIXME we could do a proper realloc, which copy constructs only needed data. - // FIXME we ara about to delete data maybe it is good time to shrink? + // FIXME we are about to delete data - maybe it is good time to shrink? // FIXME the shrink is also an issue in removeLast, that is just a copy + reduce of this. if (d->alloc) { detach(); @@ -756,7 +756,11 @@ typename QVector<T>::iterator QVector<T>::erase(iterator abegin, iterator aend) } } else { destruct(abegin, aend); - memmove(abegin, aend, (d->size - itemsToErase - itemsUntouched) * sizeof(T)); + // QTBUG-53605: static_cast<void *> masks clang errors of the form + // error: destination for this 'memmove' call is a pointer to class containing a dynamic class + // FIXME maybe use std::is_polymorphic (as soon as allowed) to avoid the memmove + memmove(static_cast<void *>(abegin), static_cast<void *>(aend), + (d->size - itemsToErase - itemsUntouched) * sizeof(T)); } d->size -= itemsToErase; } diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 8e62804025..3949d2c3ac 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -3025,10 +3025,14 @@ void QXmlStreamWriterPrivate::checkIfASCIICompatibleCodec() { #ifndef QT_NO_TEXTCODEC Q_ASSERT(encoder); - // assumes ASCII-compatibility for all 8-bit encodings - QChar space = QLatin1Char(' '); - const QByteArray bytes = encoder->fromUnicode(&space, 1); - isCodecASCIICompatible = (bytes.count() == 1); + // test ASCII-compatibility using the letter 'a' + QChar letterA = QLatin1Char('a'); + const QByteArray bytesA = encoder->fromUnicode(&letterA, 1); + const bool isCodecASCIICompatibleA = (bytesA.count() == 1) && (bytesA[0] == 0x61) ; + QChar letterLess = QLatin1Char('<'); + const QByteArray bytesLess = encoder->fromUnicode(&letterLess, 1); + const bool isCodecASCIICompatibleLess = (bytesLess.count() == 1) && (bytesLess[0] == 0x3C) ; + isCodecASCIICompatible = isCodecASCIICompatibleA && isCodecASCIICompatibleLess ; #else isCodecASCIICompatible = true; #endif @@ -3790,7 +3794,8 @@ void QXmlStreamWriter::writeStartDocument(const QString &version) #ifdef QT_NO_TEXTCODEC d->write("iso-8859-1"); #else - d->write(d->codec->name().constData(), d->codec->name().length()); + const QByteArray name = d->codec->name(); + d->write(name.constData(), name.length()); #endif } d->write("\"?>"); @@ -3813,7 +3818,8 @@ void QXmlStreamWriter::writeStartDocument(const QString &version, bool standalon #ifdef QT_NO_TEXTCODEC d->write("iso-8859-1"); #else - d->write(d->codec->name().constData(), d->codec->name().length()); + const QByteArray name = d->codec->name(); + d->write(name.constData(), name.length()); #endif } if (standalone) diff --git a/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp b/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp index d5f610cf28..8581510133 100644 --- a/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp +++ b/src/gui/doc/snippets/code/src_gui_kernel_qclipboard.cpp @@ -49,7 +49,7 @@ ****************************************************************************/ //! [0] -QClipboard *clipboard = QApplication::clipboard(); +QClipboard *clipboard = QGuiApplication::clipboard(); QString originalText = clipboard->text(); ... clipboard->setText(newText); diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index b8290861af..9545abfd21 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -289,6 +289,12 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int format = QImage::Format_Mono; } + if (depth != 32) { + ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits; + if (ncols < 1 || ncols > 256) // sanity check - don't run out of mem if color table is broken + return false; + } + if (bi.biHeight < 0) h = -h; // support images with negative height @@ -296,19 +302,15 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int image = QImage(w, h, format); if (image.isNull()) // could not create image return false; - } - - if (depth != 32) { - ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits; - if (ncols < 1 || ncols > 256) // sanity check - don't run out of mem if color table is broken - return false; - image.setColorCount(ncols); + if (ncols) + image.setColorCount(ncols); // Ensure valid QImage } image.setDotsPerMeterX(bi.biXPelsPerMeter); image.setDotsPerMeterY(bi.biYPelsPerMeter); if (ncols > 0) { // read color table + image.setColorCount(ncols); uchar rgb[4]; int rgb_len = t == BMP_OLD ? 3 : 4; for (int i=0; i<ncols; i++) { diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index 620cbde25d..0dec4b512d 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -284,7 +284,7 @@ QPixmap QPixmapIconEngine::pixmap(const QSize &size, QIcon::Mode mode, QIcon::St if (pm.isNull()) { int idx = pixmaps.count(); while (--idx >= 0) { - if (pe == &pixmaps[idx]) { + if (pe == &pixmaps.at(idx)) { pixmaps.remove(idx); break; } diff --git a/src/gui/image/qiconloader.cpp b/src/gui/image/qiconloader.cpp index cc8337fcb9..38782ac0a0 100644 --- a/src/gui/image/qiconloader.cpp +++ b/src/gui/image/qiconloader.cpp @@ -296,7 +296,7 @@ QIconTheme::QIconTheme(const QString &themeName) { QFile themeIndex; - QStringList iconDirs = QIcon::themeSearchPaths(); + const QStringList iconDirs = QIcon::themeSearchPaths(); for ( int i = 0 ; i < iconDirs.size() ; ++i) { QDir iconDir(iconDirs[i]); QString themeDir = iconDir.path() + QLatin1Char('/') + themeName; diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 3238d83729..3a31af8645 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -176,6 +176,9 @@ QImageData::~QImageData() data = 0; } +#if defined(_M_ARM) +#pragma optimize("", off) +#endif bool QImageData::checkForAlphaPixels() const { @@ -193,74 +196,81 @@ bool QImageData::checkForAlphaPixels() const break; case QImage::Format_ARGB32: case QImage::Format_ARGB32_Premultiplied: { - uchar *bits = data; + const uchar *bits = data; for (int y=0; y<height && !has_alpha_pixels; ++y) { + uint alphaAnd = 0xff000000; for (int x=0; x<width; ++x) - has_alpha_pixels |= (((uint *)bits)[x] & 0xff000000) != 0xff000000; + alphaAnd &= reinterpret_cast<const uint*>(bits)[x]; + has_alpha_pixels = (alphaAnd != 0xff000000); bits += bytes_per_line; } } break; case QImage::Format_RGBA8888: case QImage::Format_RGBA8888_Premultiplied: { - uchar *bits = data; + const uchar *bits = data; for (int y=0; y<height && !has_alpha_pixels; ++y) { + uchar alphaAnd = 0xff; for (int x=0; x<width; ++x) - has_alpha_pixels |= bits[x*4+3] != 0xff; + alphaAnd &= bits[x * 4+ 3]; + has_alpha_pixels = (alphaAnd != 0xff); bits += bytes_per_line; } } break; case QImage::Format_A2BGR30_Premultiplied: case QImage::Format_A2RGB30_Premultiplied: { - uchar *bits = data; + const uchar *bits = data; for (int y=0; y<height && !has_alpha_pixels; ++y) { + uint alphaAnd = 0xc0000000; for (int x=0; x<width; ++x) - has_alpha_pixels |= (((uint *)bits)[x] & 0xc0000000) != 0xc0000000; + alphaAnd &= reinterpret_cast<const uint*>(bits)[x]; + has_alpha_pixels = (alphaAnd != 0xc0000000); bits += bytes_per_line; } } break; case QImage::Format_ARGB8555_Premultiplied: case QImage::Format_ARGB8565_Premultiplied: { - uchar *bits = data; - uchar *end_bits = data + bytes_per_line; + const uchar *bits = data; + const uchar *end_bits = data + bytes_per_line; for (int y=0; y<height && !has_alpha_pixels; ++y) { + uchar alphaAnd = 0xff; while (bits < end_bits) { - has_alpha_pixels |= bits[0] != 0; + alphaAnd &= bits[0]; bits += 3; } + has_alpha_pixels = (alphaAnd != 0xff); bits = end_bits; end_bits += bytes_per_line; } } break; case QImage::Format_ARGB6666_Premultiplied: { - uchar *bits = data; - uchar *end_bits = data + bytes_per_line; + const uchar *bits = data; + const uchar *end_bits = data + bytes_per_line; for (int y=0; y<height && !has_alpha_pixels; ++y) { + uchar alphaAnd = 0xfc; while (bits < end_bits) { - has_alpha_pixels |= (bits[0] & 0xfc) != 0; + alphaAnd &= bits[0]; bits += 3; } + has_alpha_pixels = (alphaAnd != 0xfc); bits = end_bits; end_bits += bytes_per_line; } } break; case QImage::Format_ARGB4444_Premultiplied: { - uchar *bits = data; - uchar *end_bits = data + bytes_per_line; - + const uchar *bits = data; for (int y=0; y<height && !has_alpha_pixels; ++y) { - while (bits < end_bits) { - has_alpha_pixels |= (bits[0] & 0xf0) != 0; - bits += 2; - } - bits = end_bits; - end_bits += bytes_per_line; + ushort alphaAnd = 0xf000; + for (int x=0; x<width; ++x) + alphaAnd &= reinterpret_cast<const ushort*>(bits)[x]; + has_alpha_pixels = (alphaAnd != 0xf000); + bits += bytes_per_line; } } break; @@ -283,6 +293,9 @@ bool QImageData::checkForAlphaPixels() const return has_alpha_pixels; } +#if defined(_M_ARM) +#pragma optimize("", on) +#endif /*! \class QImage diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp index 10fa4303b2..f383e7a60e 100644 --- a/src/gui/image/qimagepixmapcleanuphooks.cpp +++ b/src/gui/image/qimagepixmapcleanuphooks.cpp @@ -84,38 +84,38 @@ void QImagePixmapCleanupHooks::removeImageHook(_qt_image_cleanup_hook_64 hook) void QImagePixmapCleanupHooks::executePlatformPixmapModificationHooks(QPlatformPixmap* pmd) { - QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); + const QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); // the global destructor for the pixmap and image hooks might have // been called already if the app is "leaking" global // pixmaps/images if (!h) return; - for (int i = 0; i < h->pixmapModificationHooks.count(); ++i) - h->pixmapModificationHooks[i](pmd); + for (auto hook : h->pixmapModificationHooks) + hook(pmd); } void QImagePixmapCleanupHooks::executePlatformPixmapDestructionHooks(QPlatformPixmap* pmd) { - QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); + const QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); // the global destructor for the pixmap and image hooks might have // been called already if the app is "leaking" global // pixmaps/images if (!h) return; - for (int i = 0; i < h->pixmapDestructionHooks.count(); ++i) - h->pixmapDestructionHooks[i](pmd); + for (auto hook : h->pixmapDestructionHooks) + hook(pmd); } void QImagePixmapCleanupHooks::executeImageHooks(qint64 key) { - QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); + const QImagePixmapCleanupHooks *h = qt_image_and_pixmap_cleanup_hooks(); // the global destructor for the pixmap and image hooks might have // been called already if the app is "leaking" global // pixmaps/images if (!h) return; - for (int i = 0; i < h->imageHooks.count(); ++i) - h->imageHooks[i](key); + for (auto hook : h->imageHooks) + hook(key); } diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 7fbb498bbb..96d6be502d 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -749,7 +749,7 @@ static void set_text(const QImage &image, png_structp png_ptr, png_infop info_pt QMap<QString, QString>::ConstIterator it = text.constBegin(); int i = 0; while (it != text.constEnd()) { - text_ptr[i].key = qstrdup(it.key().left(79).toLatin1().constData()); + text_ptr[i].key = qstrdup(it.key().leftRef(79).toLatin1().constData()); bool noCompress = (it.value().length() < 40); #ifdef PNG_iTXt_SUPPORTED diff --git a/src/gui/image/qxpmhandler.cpp b/src/gui/image/qxpmhandler.cpp index 5c8ff84929..756e31318f 100644 --- a/src/gui/image/qxpmhandler.cpp +++ b/src/gui/image/qxpmhandler.cpp @@ -1154,7 +1154,7 @@ static bool write_xpm_image(const QImage &sourceImage, QIODevice *device, const int cc = 0; for(x=0; x<w; x++) { int color = (int)(*(yp + x)); - QByteArray chars(xpm_color_name(cpp, colorMap[color])); + const QByteArray chars(xpm_color_name(cpp, colorMap[color])); line[cc++] = QLatin1Char(chars[0]); if (cpp > 1) { line[cc++] = QLatin1Char(chars[1]); diff --git a/src/gui/itemmodels/qstandarditemmodel.cpp b/src/gui/itemmodels/qstandarditemmodel.cpp index ff54602a5d..973e5c4333 100644 --- a/src/gui/itemmodels/qstandarditemmodel.cpp +++ b/src/gui/itemmodels/qstandarditemmodel.cpp @@ -3018,10 +3018,7 @@ QMimeData *QStandardItemModel::mimeData(const QModelIndexList &indexes) const for (int i = 0; i < childList.count(); ++i) { QStandardItem *chi = childList.at(i); if (chi) { - QSet<QStandardItem *>::iterator it = itemsSet.find(chi); - if (it != itemsSet.end()) { - itemsSet.erase(it); - } + itemsSet.erase(itemsSet.constFind(chi)); stack.push(chi); } } @@ -3130,13 +3127,13 @@ bool QStandardItemModel::dropMimeData(const QMimeData *data, Qt::DropAction acti for (int i = 0; i < rows.count(); ++i) rowsToInsert[rows.at(i)] = 1; for (int i = 0; i < rowsToInsert.count(); ++i) { - if (rowsToInsert[i] == 1){ + if (rowsToInsert.at(i) == 1){ rowsToInsert[i] = dragRowCount; ++dragRowCount; } } for (int i = 0; i < rows.count(); ++i) - rows[i] = top + rowsToInsert[rows[i]]; + rows[i] = top + rowsToInsert.at(rows.at(i)); QBitArray isWrittenTo(dragRowCount * dragColumnCount); diff --git a/src/gui/kernel/qclipboard.cpp b/src/gui/kernel/qclipboard.cpp index 7932b9a2dc..e9da36a42a 100644 --- a/src/gui/kernel/qclipboard.cpp +++ b/src/gui/kernel/qclipboard.cpp @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE Drop}. There is a single QClipboard object in an application, accessible - as QApplication::clipboard(). + as QGuiApplication::clipboard(). Example: \snippet code/src_gui_kernel_qclipboard.cpp 0 @@ -137,7 +137,7 @@ QT_BEGIN_NAMESPACE \endlist - \sa QApplication + \sa QGuiApplication */ /*! @@ -147,7 +147,7 @@ QT_BEGIN_NAMESPACE Do not call this function. - Call QApplication::clipboard() instead to get a pointer to the + Call QGuiApplication::clipboard() instead to get a pointer to the application's global clipboard object. There is only one clipboard in the window system, and creating @@ -165,7 +165,7 @@ QClipboard::QClipboard(QObject *parent) Destroys the clipboard. - You should never delete the clipboard. QApplication will do this + You should never delete the clipboard. QGuiApplication will do this when the application terminates. */ QClipboard::~QClipboard() diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 305ce5c82e..6adbea6da6 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -3904,6 +3904,9 @@ QDebug operator<<(QDebug dbg, const QEvent *e) case QEvent::Expose: dbg << "QExposeEvent(" << static_cast<const QExposeEvent *>(e)->region() << ')'; break; + case QEvent::Paint: + dbg << "QPaintEvent(" << static_cast<const QPaintEvent *>(e)->region() << ')'; + break; case QEvent::MouseButtonPress: case QEvent::MouseMove: case QEvent::MouseButtonRelease: diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index d0bfc7ff5f..7afeadcced 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1035,7 +1035,7 @@ QWindow *QGuiApplication::topLevelAt(const QPoint &pos) // may repeat. Find only when there is more than one virtual desktop. if (!windowScreen && screens.count() != primaryScreens.count()) { for (int i = 1; i < screens.size(); ++i) { - QScreen *screen = screens[i]; + QScreen *screen = screens.at(i); if (screen->geometry().contains(pos)) { windowScreen = screen; break; @@ -2641,7 +2641,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To if (b == Qt::NoButton) self->synthesizedMousePoints.clear(); - QList<QTouchEvent::TouchPoint> touchPoints = touchEvent.touchPoints(); + const QList<QTouchEvent::TouchPoint> &touchPoints = touchEvent.touchPoints(); if (eventType == QEvent::TouchBegin) m_fakeMouseSourcePointId = touchPoints.first().id(); diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index 8ccd85795b..e7b1f9e073 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -1154,21 +1154,22 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence } int p = accel.lastIndexOf(QLatin1Char('+'), str.length() - 2); // -2 so that Ctrl++ works + QStringRef accelRef(&accel); if(p > 0) - accel = accel.mid(p + 1); + accelRef = accelRef.mid(p + 1); int fnum = 0; - if (accel.length() == 1) { + if (accelRef.length() == 1) { #if defined(Q_OS_MACX) - int qtKey = qtkeyForMacSymbol(accel[0]); + int qtKey = qtkeyForMacSymbol(accelRef.at(0)); if (qtKey != -1) { ret |= qtKey; } else #endif { - ret |= accel[0].toUpper().unicode(); + ret |= accelRef.at(0).toUpper().unicode(); } - } else if (accel[0] == QLatin1Char('f') && (fnum = accel.mid(1).toInt()) && (fnum >= 1) && (fnum <= 35)) { + } else if (accelRef.at(0) == QLatin1Char('f') && (fnum = accelRef.mid(1).toInt()) >= 1 && fnum <= 35) { ret |= Qt::Key_F1 + fnum - 1; } else { // For NativeText, check the traslation table first, @@ -1182,7 +1183,7 @@ int QKeySequencePrivate::decodeString(const QString &str, QKeySequence::Sequence QString keyName(tran == 0 ? QCoreApplication::translate("QShortcut", keyname[i].name) : QString::fromLatin1(keyname[i].name)); - if (accel == keyName.toLower()) { + if (accelRef == keyName.toLower()) { ret |= keyname[i].key; found = true; break; diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 19464eeca3..7e5697e5d8 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -1418,7 +1418,7 @@ void QOpenGLContextGroupPrivate::removeContext(QOpenGLContext *ctx) m_shares.removeOne(ctx); if (ctx == m_context && !m_shares.isEmpty()) - m_context = m_shares.first(); + m_context = m_shares.constFirst(); if (!m_refs.deref()) { cleanup(); @@ -1582,7 +1582,7 @@ QOpenGLMultiGroupSharedResource::~QOpenGLMultiGroupSharedResource() #endif for (int i = 0; i < m_groups.size(); ++i) { if (!m_groups.at(i)->shares().isEmpty()) { - QOpenGLContext *context = m_groups.at(i)->shares().first(); + QOpenGLContext *context = m_groups.at(i)->shares().constFirst(); QOpenGLSharedResource *resource = value(context); if (resource) resource->free(); diff --git a/src/gui/kernel/qplatformintegration.cpp b/src/gui/kernel/qplatformintegration.cpp index a0e65654a6..3490e786a8 100644 --- a/src/gui/kernel/qplatformintegration.cpp +++ b/src/gui/kernel/qplatformintegration.cpp @@ -474,11 +474,11 @@ void QPlatformIntegration::screenAdded(QPlatformScreen *ps, bool isPrimary) void QPlatformIntegration::removeScreen(QScreen *screen) { - const bool wasPrimary = (!QGuiApplicationPrivate::screen_list.isEmpty() && QGuiApplicationPrivate::screen_list[0] == screen); + const bool wasPrimary = (!QGuiApplicationPrivate::screen_list.isEmpty() && QGuiApplicationPrivate::screen_list.at(0) == screen); QGuiApplicationPrivate::screen_list.removeOne(screen); if (wasPrimary && qGuiApp && !QGuiApplicationPrivate::screen_list.isEmpty()) - emit qGuiApp->primaryScreenChanged(QGuiApplicationPrivate::screen_list[0]); + emit qGuiApp->primaryScreenChanged(QGuiApplicationPrivate::screen_list.at(0)); } /*! diff --git a/src/gui/kernel/qplatformscreen.cpp b/src/gui/kernel/qplatformscreen.cpp index 8450c6a083..3c1552c31e 100644 --- a/src/gui/kernel/qplatformscreen.cpp +++ b/src/gui/kernel/qplatformscreen.cpp @@ -93,7 +93,7 @@ QPixmap QPlatformScreen::grabWindow(WId window, int x, int y, int width, int hei */ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const { - QWindowList list = QGuiApplication::topLevelWindows(); + const QWindowList list = QGuiApplication::topLevelWindows(); for (int i = list.size()-1; i >= 0; --i) { QWindow *w = list[i]; if (w->isVisible() && QHighDpi::toNativePixels(w->geometry(), w).contains(pos)) diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 81310ae2a2..fa26fd77a3 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -1688,11 +1688,9 @@ void QWindow::destroy() if (QGuiApplicationPrivate::currentMousePressWindow == this) QGuiApplicationPrivate::currentMousePressWindow = parent(); - for (int i = 0; i < QGuiApplicationPrivate::tabletDevicePoints.size(); ++i) { - QGuiApplicationPrivate::TabletPointData &pointData = QGuiApplicationPrivate::tabletDevicePoints[i]; - if (pointData.target == this) - pointData.target = parent(); - } + for (int i = 0; i < QGuiApplicationPrivate::tabletDevicePoints.size(); ++i) + if (QGuiApplicationPrivate::tabletDevicePoints.at(i).target == this) + QGuiApplicationPrivate::tabletDevicePoints[i].target = parent(); bool wasVisible = isVisible(); d->visibilityOnDestroy = wasVisible && d->platformWindow; diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index cde70a1102..5e42f5ba90 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -117,7 +117,7 @@ public: static void handleWheelEvent(QWindow *w, ulong timestamp, const QPointF & local, const QPointF & global, int d, Qt::Orientation o, Qt::KeyboardModifiers mods = Qt::NoModifier); struct TouchPoint { - TouchPoint() : id(0), uniqueId(-1), pressure(0), rotation(0), state(Qt::TouchPointStationary), flags(0) { } + TouchPoint() : id(0), uniqueId(-1), pressure(0), rotation(0), state(Qt::TouchPointStationary) { } int id; // for application use qint64 uniqueId; // for TUIO: object/token ID; otherwise empty // TODO for TUIO 2.0: add registerPointerUniqueID(QPointerUniqueId) @@ -142,7 +142,7 @@ public: // rect is relative to parent static void handleGeometryChange(QWindow *w, const QRect &newRect, const QRect &oldRect = QRect()); - static void handleCloseEvent(QWindow *w, bool *accepted = 0); + static void handleCloseEvent(QWindow *w, bool *accepted = Q_NULLPTR); static void handleEnterEvent(QWindow *w, const QPointF &local = QPointF(), const QPointF& global = QPointF()); static void handleLeaveEvent(QWindow *w); static void handleEnterLeaveEvent(QWindow *enter, QWindow *leave, const QPointF &local = QPointF(), const QPointF& global = QPointF()); diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp index b932ee60c9..303d4d4eb1 100644 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ b/src/gui/opengl/qopenglframebufferobject.cpp @@ -1073,7 +1073,7 @@ bool QOpenGLFramebufferObject::bind() if (d->format.samples() == 0) { // Create new textures to replace the ones stolen via takeTexture(). for (int i = 0; i < d->colorAttachments.count(); ++i) { - if (!d->colorAttachments[i].guard) + if (!d->colorAttachments.at(i).guard) d->initTexture(i); } } @@ -1206,10 +1206,11 @@ GLuint QOpenGLFramebufferObject::takeTexture(int colorAttachmentIndex) QOpenGLContext *current = QOpenGLContext::currentContext(); if (current && current->shareGroup() == d->fbo_guard->group() && isBound()) release(); - id = d->colorAttachments[colorAttachmentIndex].guard ? d->colorAttachments[colorAttachmentIndex].guard->id() : 0; + auto &guard = d->colorAttachments[colorAttachmentIndex].guard; + id = guard ? guard->id() : 0; // Do not call free() on texture_guard, just null it out. // This way the texture will not be deleted when the guard is destroyed. - d->colorAttachments[colorAttachmentIndex].guard = 0; + guard = 0; } return id; } diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp index c135489379..58dcbed50a 100644 --- a/src/gui/opengl/qopenglgradientcache.cpp +++ b/src/gui/opengl/qopenglgradientcache.cpp @@ -108,7 +108,7 @@ GLuint QOpenGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity { quint64 hash_val = 0; - QGradientStops stops = gradient.stops(); + const QGradientStops stops = gradient.stops(); for (int i = 0; i < stops.size() && i <= 2; i++) hash_val += stops[i].second.rgba(); @@ -170,16 +170,12 @@ GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, qreal opacity) const { int pos = 0; - QGradientStops s = gradient.stops(); - QVector<QRgba64> colors(s.size()); - - for (int i = 0; i < s.size(); ++i) - colors[i] = s[i].second.rgba64(); + const QGradientStops s = gradient.stops(); bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); uint alpha = qRound(opacity * 256); - QRgba64 current_color = combineAlpha256(colors[0], alpha); + QRgba64 current_color = combineAlpha256(s[0].second.rgba64(), alpha); qreal incr = 1.0 / qreal(size); qreal fpos = 1.5 * incr; colorTable[pos++] = qPremultiply(current_color); @@ -193,9 +189,10 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient if (colorInterpolation) current_color = qPremultiply(current_color); - for (int i = 0; i < s.size() - 1; ++i) { + const int sLast = s.size() - 1; + for (int i = 0; i < sLast; ++i) { qreal delta = 1/(s[i+1].first - s[i].first); - QRgba64 next_color = combineAlpha256(colors[i+1], alpha); + QRgba64 next_color = combineAlpha256(s[i + 1].second.rgba64(), alpha); if (colorInterpolation) next_color = qPremultiply(next_color); @@ -214,7 +211,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient Q_ASSERT(s.size() > 0); - QRgba64 last_color = qPremultiply(combineAlpha256(colors[s.size() - 1], alpha)); + QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha)); for (;pos < size; ++pos) colorTable[pos] = last_color; @@ -225,16 +222,13 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const { int pos = 0; - QGradientStops s = gradient.stops(); - QVector<uint> colors(s.size()); - - for (int i = 0; i < s.size(); ++i) - colors[i] = s[i].second.rgba(); // Qt LIES! It returns ARGB (on little-endian AND on big-endian) + const QGradientStops s = gradient.stops(); bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); uint alpha = qRound(opacity * 256); - uint current_color = ARGB_COMBINE_ALPHA(colors[0], alpha); + // Qt LIES! It returns ARGB (on little-endian AND on big-endian) + uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha); qreal incr = 1.0 / qreal(size); qreal fpos = 1.5 * incr; colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color)); @@ -248,9 +242,10 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient if (colorInterpolation) current_color = qPremultiply(current_color); - for (int i = 0; i < s.size() - 1; ++i) { + const int sLast = s.size() - 1; + for (int i = 0; i < sLast; ++i) { qreal delta = 1/(s[i+1].first - s[i].first); - uint next_color = ARGB_COMBINE_ALPHA(colors[i+1], alpha); + uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha); if (colorInterpolation) next_color = qPremultiply(next_color); @@ -269,7 +264,7 @@ void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient Q_ASSERT(s.size() > 0); - uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(colors[s.size() - 1], alpha))); + uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha))); for (;pos < size; ++pos) colorTable[pos] = last_color; diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 8defcfb28d..6472481e7a 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -2186,11 +2186,10 @@ void QPainter::setBrushOrigin(const QPointF &p) destination pixel in such a way that the alpha component of the source defines the translucency of the pixel. - When the paint device is a QImage, the image format must be set to - \l {QImage::Format}{Format_ARGB32_Premultiplied} or - \l {QImage::Format}{Format_ARGB32} for the composition modes to have - any effect. For performance the premultiplied version is the preferred - format. + Several composition modes require an alpha channel in the source or + target images to have an effect. For optimal performance the + image format \l {QImage::Format}{Format_ARGB32_Premultiplied} is + preferred. When a composition mode is set it applies to all painting operator, pens, brushes, gradients and pixmap/image drawing. @@ -2469,7 +2468,7 @@ void QPainter::setClipping(bool enable) // we can't enable clipping if we don't have a clip if (enable - && (d->state->clipInfo.isEmpty() || d->state->clipInfo.last().operation == Qt::NoClip)) + && (d->state->clipInfo.isEmpty() || d->state->clipInfo.constLast().operation == Qt::NoClip)) return; d->state->clipEnabled = enable; diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 7072a2d79c..7dbc83b338 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -690,7 +690,7 @@ void QPainterPath::moveTo(const QPointF &p) d->require_moveTo = false; - if (d->elements.last().type == MoveToElement) { + if (d->elements.constLast().type == MoveToElement) { d->elements.last().x = p.x(); d->elements.last().y = p.y(); } else { @@ -738,7 +738,7 @@ void QPainterPath::lineTo(const QPointF &p) QPainterPathData *d = d_func(); Q_ASSERT(!d->elements.isEmpty()); d->maybeMoveTo(); - if (p == QPointF(d->elements.last())) + if (p == QPointF(d->elements.constLast())) return; Element elm = { p.x(), p.y(), LineToElement }; d->elements.append(elm); @@ -801,7 +801,7 @@ void QPainterPath::cubicTo(const QPointF &c1, const QPointF &c2, const QPointF & // Abort on empty curve as a stroker cannot handle this and the // curve is irrelevant anyway. - if (d->elements.last() == c1 && c1 == c2 && c2 == e) + if (d->elements.constLast() == c1 && c1 == c2 && c2 == e) return; d->maybeMoveTo(); @@ -984,7 +984,7 @@ QPointF QPainterPath::currentPosition() const { return !d_ptr || d_func()->elements.isEmpty() ? QPointF() - : QPointF(d_func()->elements.last().x, d_func()->elements.last().y); + : QPointF(d_func()->elements.constLast().x, d_func()->elements.constLast().y); } @@ -1073,7 +1073,7 @@ void QPainterPath::addPolygon(const QPolygonF &polygon) d_func()->elements.reserve(d_func()->elements.size() + polygon.size()); - moveTo(polygon.first()); + moveTo(polygon.constFirst()); for (int i=1; i<polygon.size(); ++i) { Element elm = { polygon.at(i).x(), polygon.at(i).y(), LineToElement }; d_func()->elements << elm; @@ -1178,12 +1178,12 @@ void QPainterPath::addText(const QPointF &point, const QFont &f, const QString & QVarLengthArray<int> visualOrder(nItems); QVarLengthArray<uchar> levels(nItems); for (int i = 0; i < nItems; ++i) - levels[i] = eng->layoutData->items[i].analysis.bidiLevel; + levels[i] = eng->layoutData->items.at(i).analysis.bidiLevel; QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data()); for (int i = 0; i < nItems; ++i) { int item = visualOrder[i]; - QScriptItem &si = eng->layoutData->items[item]; + const QScriptItem &si = eng->layoutData->items.at(item); if (si.analysis.flags < QScriptAnalysis::TabOrObject) { QGlyphLayout glyphs = eng->shapedGlyphs(&si); @@ -1230,7 +1230,7 @@ void QPainterPath::addPath(const QPainterPath &other) QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func()); // Remove last moveto so we don't get multiple moveto's - if (d->elements.last().type == MoveToElement) + if (d->elements.constLast().type == MoveToElement) d->elements.remove(d->elements.size()-1); // Locate where our own current subpath will start after the other path is added. @@ -1261,7 +1261,7 @@ void QPainterPath::connectPath(const QPainterPath &other) QPainterPathData *d = reinterpret_cast<QPainterPathData *>(d_func()); // Remove last moveto so we don't get multiple moveto's - if (d->elements.last().type == MoveToElement) + if (d->elements.constLast().type == MoveToElement) d->elements.remove(d->elements.size()-1); // Locate where our own current subpath will start after the other path is added. @@ -1273,7 +1273,7 @@ void QPainterPath::connectPath(const QPainterPath &other) d->elements[first].type = LineToElement; // avoid duplicate points - if (first > 0 && QPointF(d->elements[first]) == QPointF(d->elements[first - 1])) { + if (first > 0 && QPointF(d->elements.at(first)) == QPointF(d->elements.at(first - 1))) { d->elements.remove(first--); --cStart; } @@ -1685,8 +1685,9 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const int isect_j = current_isects.at(j); if (isect_j == i) continue; - for (int k=0; k<isects[isect_j].size(); ++k) { - int isect_k = isects[isect_j][k]; + const QVector<int> &isects_j = isects.at(isect_j); + for (int k = 0, size = isects_j.size(); k < size; ++k) { + int isect_k = isects_j.at(k); if (isect_k != i && !isects.at(i).contains(isect_k)) { isects[i] += isect_k; } @@ -1708,7 +1709,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const // Join the intersected subpaths as rewinded polygons for (int i=0; i<count; ++i) { - const QVector<int> &subpath_list = isects[i]; + const QVector<int> &subpath_list = isects.at(i); if (!subpath_list.isEmpty()) { QPolygonF buildUp; for (int j=0; j<subpath_list.size(); ++j) { @@ -1717,7 +1718,7 @@ QList<QPolygonF> QPainterPath::toFillPolygons(const QTransform &matrix) const if (!subpath.isClosed()) buildUp += subpath.first(); if (!buildUp.isClosed()) - buildUp += buildUp.first(); + buildUp += buildUp.constFirst(); } polys += buildUp; } @@ -2789,7 +2790,7 @@ void QPainterPathStroker::setDashOffset(qreal offset) QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const { - QList<QPolygonF> flats = toSubpathPolygons(matrix); + const QList<QPolygonF> flats = toSubpathPolygons(matrix); QPolygonF polygon; if (flats.isEmpty()) return polygon; diff --git a/src/gui/painting/qpathclipper.cpp b/src/gui/painting/qpathclipper.cpp index 48ae3cfc80..4f2b59c775 100644 --- a/src/gui/painting/qpathclipper.cpp +++ b/src/gui/painting/qpathclipper.cpp @@ -1648,7 +1648,7 @@ bool QPathClipper::doClip(QWingedEdge &list, ClipperMode mode) #ifdef QDEBUG_CLIPPER printf("sorted y coords:\n"); for (int i = 0; i < y_coords.size(); ++i) { - printf("%.9f\n", y_coords[i]); + printf("%.9f\n", y_coords.at(i)); } #endif @@ -1686,23 +1686,23 @@ bool QPathClipper::doClip(QWingedEdge &list, ClipperMode mode) QPathVertex *b = list.vertex(edge->second); // FIXME: this can be optimized by using binary search - const int first = qFuzzyFind(y_coords.begin(), y_coords.end(), qMin(a->y, b->y)) - y_coords.begin(); - const int last = qFuzzyFind(y_coords.begin() + first, y_coords.end(), qMax(a->y, b->y)) - y_coords.begin(); + const int first = qFuzzyFind(y_coords.cbegin(), y_coords.cend(), qMin(a->y, b->y)) - y_coords.cbegin(); + const int last = qFuzzyFind(y_coords.cbegin() + first, y_coords.cend(), qMax(a->y, b->y)) - y_coords.cbegin(); Q_ASSERT(first < y_coords.size() - 1); Q_ASSERT(last < y_coords.size()); - qreal bestY = 0.5 * (y_coords[first] + y_coords[first+1]); - qreal biggestGap = y_coords[first+1] - y_coords[first]; - + qreal biggestGap = y_coords.at(first + 1) - y_coords.at(first); + int bestIdx = first; for (int i = first + 1; i < last; ++i) { - qreal gap = y_coords[i+1] - y_coords[i]; + qreal gap = y_coords.at(i + 1) - y_coords.at(i); if (gap > biggestGap) { - bestY = 0.5 * (y_coords[i] + y_coords[i+1]); + bestIdx = i; biggestGap = gap; } } + const qreal bestY = 0.5 * (y_coords.at(bestIdx) + y_coords.at(bestIdx + 1)); #ifdef QDEBUG_CLIPPER printf("y: %.9f, gap: %.9f\n", bestY, biggestGap); diff --git a/src/gui/painting/qpdf.cpp b/src/gui/painting/qpdf.cpp index b014305796..34f1c51f6d 100644 --- a/src/gui/painting/qpdf.cpp +++ b/src/gui/painting/qpdf.cpp @@ -1674,7 +1674,7 @@ void QPdfEnginePrivate::writePage() uint resources = requestObject(); uint annots = requestObject(); - addXrefEntry(pages.last()); + addXrefEntry(pages.constLast()); xprintf("<<\n" "/Type /Page\n" "/Parent %d 0 R\n" @@ -1767,7 +1767,7 @@ void QPdfEnginePrivate::writeTail() ">>\n" "startxref\n%d\n" "%%%%EOF\n", - xrefPositions.size()-1, info, catalog, xrefPositions.last()); + xrefPositions.size()-1, info, catalog, xrefPositions.constLast()); } int QPdfEnginePrivate::addXrefEntry(int object, bool printostr) diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index bb92e6bfba..940de87eee 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -1507,10 +1507,10 @@ QRect Declaration::rectValue() const const QCss::Value &v = d->values.at(0); if (v.type != Value::Function) return QRect(); - QStringList func = v.variant.toStringList(); + const QStringList func = v.variant.toStringList(); if (func.count() != 2 || func.at(0).compare(QLatin1String("rect")) != 0) return QRect(); - QStringList args = func[1].split(QLatin1Char(' '), QString::SkipEmptyParts); + const auto args = func[1].splitRef(QLatin1Char(' '), QString::SkipEmptyParts); if (args.count() != 4) return QRect(); QRect rect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()); @@ -1653,6 +1653,7 @@ Qt::Alignment Declaration::alignmentValue() const void Declaration::borderImageValue(QString *image, int *cuts, TileMode *h, TileMode *v) const { + const DeclarationData *d = this->d.data(); // make it const and shadow d *image = uriValue(); for (int i = 0; i < 4; i++) cuts[i] = -1; @@ -1914,9 +1915,8 @@ bool StyleSelector::basicSelectorMatches(const BasicSelector &sel, NodePtr node) return false; if (a.valueMatchCriterium == QCss::AttributeSelector::MatchContains) { - - QStringList lst = attrValue.split(QLatin1Char(' ')); - if (!lst.contains(a.value)) + const auto lst = attrValue.splitRef(QLatin1Char(' ')); + if (!lst.contains(QStringRef(&a.value))) return false; } else if ( (a.valueMatchCriterium == QCss::AttributeSelector::MatchEqual diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index f92e4ab457..828dbc318c 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2033,7 +2033,7 @@ uint qHash(const QFont &font, uint seed) Q_DECL_NOTHROW */ bool QFont::fromString(const QString &descrip) { - QStringList l(descrip.split(QLatin1Char(','))); + const auto l = descrip.splitRef(QLatin1Char(',')); int count = l.count(); if (!count || (count > 2 && count < 9) || count > 11) { @@ -2042,7 +2042,7 @@ bool QFont::fromString(const QString &descrip) return false; } - setFamily(l[0]); + setFamily(l[0].toString()); if (count > 1 && l[1].toDouble() > 0.0) setPointSizeF(l[1].toDouble()); if (count == 9) { diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index e4c9b45dc2..cdfcdec80c 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -697,25 +697,20 @@ static QStringList familyList(const QFontDef &req) if (req.family.isEmpty()) return family_list; - QStringList list = req.family.split(QLatin1Char(',')); + const auto list = req.family.splitRef(QLatin1Char(',')); const int numFamilies = list.size(); family_list.reserve(numFamilies); for (int i = 0; i < numFamilies; ++i) { - QString str = list.at(i).trimmed(); + QStringRef str = list.at(i).trimmed(); if ((str.startsWith(QLatin1Char('"')) && str.endsWith(QLatin1Char('"'))) || (str.startsWith(QLatin1Char('\'')) && str.endsWith(QLatin1Char('\'')))) str = str.mid(1, str.length() - 2); - family_list << str; + family_list << str.toString(); } // append the substitute list for each family in family_list - QStringList subs_list; - QStringList::ConstIterator it = family_list.constBegin(), end = family_list.constEnd(); - for (; it != end; ++it) - subs_list += QFont::substitutes(*it); -// qDebug() << "adding substs: " << subs_list; - - family_list += subs_list; + for (int i = 0, size = family_list.size(); i < size; ++i) + family_list += QFont::substitutes(family_list.at(i)); return family_list; } @@ -2737,8 +2732,6 @@ void QFontDatabase::load(const QFontPrivate *d, int script) } if (req.pointSize < 0) req.pointSize = req.pixelSize*72.0/d->dpi; - if (req.weight == 0) - req.weight = QFont::Normal; if (req.stretch == 0) req.stretch = 100; diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 16c654dcb7..adc8f634dc 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -1833,8 +1833,7 @@ QFontEngine *QFontEngineMulti::loadEngine(int at) request.family = fallbackFamilyAt(at - 1); if (QFontEngine *engine = QFontDatabase::findFont(request, m_script)) { - if (request.weight > QFont::Normal) - engine->fontDef.weight = request.weight; + engine->fontDef.weight = request.weight; if (request.style > QFont::StyleNormal) engine->fontDef.style = request.style; return engine; diff --git a/src/gui/text/qfragmentmap_p.h b/src/gui/text/qfragmentmap_p.h index 4cf17aadc7..b54d7261d0 100644 --- a/src/gui/text/qfragmentmap_p.h +++ b/src/gui/text/qfragmentmap_p.h @@ -255,14 +255,11 @@ uint QFragmentMapData<Fragment>::createFragment() uint freePos = head->freelist; if (freePos == head->allocated) { // need to create some free space - if (freePos >= uint(MaxAllocSize) / fragmentSize) - qBadAlloc(); - uint needed = qAllocMore((freePos+1)*fragmentSize, 0); - Q_ASSERT(needed/fragmentSize > head->allocated); - Fragment *newFragments = (Fragment *)realloc(fragments, needed); + auto blockInfo = qCalculateGrowingBlockSize(freePos + 1, fragmentSize); + Fragment *newFragments = (Fragment *)realloc(fragments, blockInfo.size); Q_CHECK_PTR(newFragments); fragments = newFragments; - head->allocated = needed/fragmentSize; + head->allocated = quint32(blockInfo.elementCount); F(freePos).right = 0; } diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 8e4fa8a730..a3dbf455cf 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2430,7 +2430,7 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format) html += QLatin1Char(';'); attributesEmitted = true; } else { - html.chop(qstrlen(decorationTag.latin1())); + html.chop(decorationTag.size()); } if (format.foreground() != defaultCharFormat.foreground() @@ -2665,7 +2665,7 @@ void QTextHtmlExporter::emitFragment(const QTextFragment &fragment) if (attributesEmitted) html += QLatin1String("\">"); else - html.chop(qstrlen(styleTag.latin1())); + html.chop(styleTag.size()); if (isObject) { for (int i = 0; isImage && i < txt.length(); ++i) { @@ -2700,13 +2700,8 @@ void QTextHtmlExporter::emitFragment(const QTextFragment &fragment) // split for [\n{LineSeparator}] QString forcedLineBreakRegExp = QString::fromLatin1("[\\na]"); forcedLineBreakRegExp[3] = QChar::LineSeparator; - - const QStringList lines = txt.split(QRegExp(forcedLineBreakRegExp)); - for (int i = 0; i < lines.count(); ++i) { - if (i > 0) - html += QLatin1String("<br />"); // space on purpose for compatibility with Netscape, Lynx & Co. - html += lines.at(i); - } + // space in BR on purpose for compatibility with old-fashioned browsers + html += txt.replace(QRegExp(forcedLineBreakRegExp), QLatin1String("<br />")); } if (attributesEmitted) @@ -3227,7 +3222,7 @@ void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType QString::number(format.rightMargin())); if (html.length() == originalHtmlLength) // nothing emitted? - html.chop(qstrlen(styleAttribute.latin1())); + html.chop(styleAttribute.size()); else html += QLatin1Char('\"'); } diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index df0d52d8e9..3537adba9e 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -1006,9 +1006,9 @@ int QTextDocumentPrivate::undoRedo(bool undo) bool inBlock = ( undoState > 0 && undoState < undoStack.size() - && undoStack[undoState].block_part - && undoStack[undoState-1].block_part - && !undoStack[undoState-1].block_end + && undoStack.at(undoState).block_part + && undoStack.at(undoState - 1).block_part + && !undoStack.at(undoState - 1).block_end ); if (!inBlock) break; @@ -1074,13 +1074,14 @@ void QTextDocumentPrivate::appendUndoItem(const QTextUndoCommand &c) if (!undoStack.isEmpty() && modified) { - QTextUndoCommand &last = undoStack[undoState - 1]; + const int lastIdx = undoState - 1; + const QTextUndoCommand &last = undoStack.at(lastIdx); if ( (last.block_part && c.block_part && !last.block_end) // part of the same block => can merge || (!c.block_part && !last.block_part) // two single undo items => can merge || (c.command == QTextUndoCommand::Inserted && last.command == c.command && (last.block_part && !c.block_part))) { // two sequential inserts that are not part of the same block => can merge - if (last.tryMerge(c)) + if (undoStack[lastIdx].tryMerge(c)) return; } } @@ -1102,7 +1103,7 @@ void QTextDocumentPrivate::clearUndoRedoStacks(QTextDocument::Stacks stacksToCle bool redoCommandsAvailable = undoState != undoStack.size(); if (stacksToClear == QTextDocument::UndoStack && undoCommandsAvailable) { for (int i = 0; i < undoState; ++i) { - QTextUndoCommand c = undoStack[undoState]; + QTextUndoCommand c = undoStack.at(undoState); if (c.command & QTextUndoCommand::Custom) delete c.custom; } @@ -1114,7 +1115,7 @@ void QTextDocumentPrivate::clearUndoRedoStacks(QTextDocument::Stacks stacksToCle } else if (stacksToClear == QTextDocument::RedoStack && redoCommandsAvailable) { for (int i = undoState; i < undoStack.size(); ++i) { - QTextUndoCommand c = undoStack[i]; + QTextUndoCommand c = undoStack.at(i); if (c.command & QTextUndoCommand::Custom) delete c.custom; } @@ -1124,7 +1125,7 @@ void QTextDocumentPrivate::clearUndoRedoStacks(QTextDocument::Stacks stacksToCle } else if (stacksToClear == QTextDocument::UndoAndRedoStacks && !undoStack.isEmpty()) { for (int i = 0; i < undoStack.size(); ++i) { - QTextUndoCommand c = undoStack[i]; + QTextUndoCommand c = undoStack.at(i); if (c.command & QTextUndoCommand::Custom) delete c.custom; } @@ -1187,8 +1188,8 @@ void QTextDocumentPrivate::endEditBlock() return; if (undoEnabled && undoState > 0) { - const bool wasBlocking = !undoStack[undoState - 1].block_end; - if (undoStack[undoState - 1].block_part) { + const bool wasBlocking = !undoStack.at(undoState - 1).block_end; + if (undoStack.at(undoState - 1).block_part) { undoStack[undoState - 1].block_end = true; if (wasBlocking) emit document()->undoCommandAdded(); diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp index f8f4e454e0..a1a562c839 100644 --- a/src/gui/text/qtextdocumentfragment.cpp +++ b/src/gui/text/qtextdocumentfragment.cpp @@ -882,7 +882,7 @@ QTextHtmlImporter::Table QTextHtmlImporter::scanTable(int tableNodeIdx) if (at(cell).isTableCell()) { // skip all columns with spans from previous rows while (colsInRow < rowColSpanForColumn.size()) { - const RowColSpanInfo &spanInfo = rowColSpanForColumn[colsInRow]; + const RowColSpanInfo &spanInfo = rowColSpanForColumn.at(colsInRow); if (spanInfo.row + spanInfo.rowSpan > effectiveRow) { Q_ASSERT(spanInfo.col == colsInRow); @@ -1081,8 +1081,8 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode() && indent != 0 && (lists.isEmpty() || !hasBlock - || !lists.last().list - || lists.last().list->itemNumber(cursor.block()) == -1 + || !lists.constLast().list + || lists.constLast().list->itemNumber(cursor.block()) == -1 ) ) { block.setIndent(indent); diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index 1b2113d281..0c8904b4c5 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -265,7 +265,7 @@ void QTextTableData::updateTableSize() const QFixed effectiveLeftMargin = this->leftMargin + border + padding; const QFixed effectiveRightMargin = this->rightMargin + border + padding; size.height = contentsHeight == -1 - ? rowPositions.last() + heights.last() + padding + border + cellSpacing + effectiveBottomMargin + ? rowPositions.constLast() + heights.constLast() + padding + border + cellSpacing + effectiveBottomMargin : effectiveTopMargin + contentsHeight + effectiveBottomMargin; size.width = effectiveLeftMargin + contentsWidth + effectiveRightMargin; } @@ -1238,7 +1238,7 @@ void QTextDocumentLayoutPrivate::drawFlow(const QPointF &offset, QPainter *paint // if we're past what is already laid out then we're better off // not trying to draw things that may not be positioned correctly yet - if (currentPosInDoc >= checkPoints.last().positionInFrame) + if (currentPosInDoc >= checkPoints.constLast().positionInFrame) break; if (lastVisibleCheckPoint != checkPoints.end() @@ -1798,7 +1798,7 @@ recalc_minmax_widths: td->columnPositions[i] = td->columnPositions.at(i-1) + td->widths.at(i-1) + 2 * td->border + cellSpacing; // - margin to compensate the + margin in columnPositions[0] - const QFixed contentsWidth = td->columnPositions.last() + td->widths.last() + td->padding + td->border + cellSpacing - leftMargin; + const QFixed contentsWidth = td->columnPositions.constLast() + td->widths.constLast() + td->padding + td->border + cellSpacing - leftMargin; // if the table is too big and causes an overflow re-do the layout with WrapAnywhere as wrap // mode @@ -1845,14 +1845,14 @@ recalc_minmax_widths: td->calcRowPosition(r); const int tableStartPage = (absoluteTableY / pageHeight).truncate(); - const int currentPage = ((td->rowPositions[r] + absoluteTableY) / pageHeight).truncate(); + const int currentPage = ((td->rowPositions.at(r) + absoluteTableY) / pageHeight).truncate(); const QFixed pageBottom = (currentPage + 1) * pageHeight - td->effectiveBottomMargin - absoluteTableY - cellSpacing - td->border; const QFixed pageTop = currentPage * pageHeight + td->effectiveTopMargin - absoluteTableY + cellSpacing + td->border; const QFixed nextPageTop = pageTop + pageHeight; - if (td->rowPositions[r] > pageBottom) + if (td->rowPositions.at(r) > pageBottom) td->rowPositions[r] = nextPageTop; - else if (td->rowPositions[r] < pageTop) + else if (td->rowPositions.at(r) < pageTop) td->rowPositions[r] = pageTop; bool dropRowToNextPage = true; @@ -1863,7 +1863,7 @@ recalc_minmax_widths: QFixed dropDistance = 0; relayout: - const int rowStartPage = ((td->rowPositions[r] + absoluteTableY) / pageHeight).truncate(); + const int rowStartPage = ((td->rowPositions.at(r) + absoluteTableY) / pageHeight).truncate(); // if any of the header rows or the first non-header row start on the next page // then the entire header should be dropped if (r <= headerRowCount && rowStartPage > tableStartPage && !hasDroppedTable) { @@ -1927,13 +1927,13 @@ relayout: } if (rowCellCount > 0 && dropRowToNextPage) { - dropDistance = nextPageTop - td->rowPositions[r]; + dropDistance = nextPageTop - td->rowPositions.at(r); td->rowPositions[r] = nextPageTop; td->heights[r] = 0; dropRowToNextPage = false; cellHeights.resize(cellCountBeforeRow); if (r > headerRowCount) - td->heights[r-1] = pageBottom - td->rowPositions[r-1]; + td->heights[r - 1] = pageBottom - td->rowPositions.at(r - 1); goto relayout; } @@ -1944,7 +1944,7 @@ relayout: } if (r == headerRowCount - 1) { - td->headerHeight = td->rowPositions[r] + td->heights[r] - td->rowPositions[0] + td->cellSpacing + 2 * td->border; + td->headerHeight = td->rowPositions.at(r) + td->heights.at(r) - td->rowPositions.at(0) + td->cellSpacing + 2 * td->border; td->headerHeight -= td->headerHeight * (td->headerHeight / pageHeight).truncate(); td->effectiveTopMargin += td->headerHeight; } @@ -2304,7 +2304,7 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout docPos = it.currentBlock().position(); if (inRootFrame) { - if (qAbs(layoutStruct->y - checkPoints.last().y) > 2000) { + if (qAbs(layoutStruct->y - checkPoints.constLast().y) > 2000) { QFixed left, right; floatMargins(layoutStruct->y, layoutStruct, &left, &right); if (left == layoutStruct->x_left && right == layoutStruct->x_right) { @@ -2554,7 +2554,7 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout checkPoints.append(cp); checkPoints.reserve(checkPoints.size()); } else { - currentLazyLayoutPosition = checkPoints.last().positionInFrame; + currentLazyLayoutPosition = checkPoints.constLast().positionInFrame; // ####### //checkPoints.last().positionInFrame = q->document()->docHandle()->length(); } diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 6be84c0186..d11f8c34b1 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1643,8 +1643,14 @@ void QTextEngine::itemize() const if (analysis->bidiLevel % 2) --analysis->bidiLevel; analysis->flags = QScriptAnalysis::LineOrParagraphSeparator; - if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) + if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) { + const int offset = uc - string; + layoutData->string.detach(); + string = reinterpret_cast<const ushort *>(layoutData->string.unicode()); + uc = string + offset; + e = uc + length; *const_cast<ushort*>(uc) = 0x21B5; // visual line separator + } break; case QChar::Tabulation: analysis->flags = QScriptAnalysis::Tab; @@ -3272,7 +3278,7 @@ int QTextEngine::endOfLine(int lineNum) insertionPointsForLine(lineNum, insertionPoints); if (insertionPoints.size() > 0) - return insertionPoints.last(); + return insertionPoints.constLast(); return 0; } @@ -3282,7 +3288,7 @@ int QTextEngine::beginningOfLine(int lineNum) insertionPointsForLine(lineNum, insertionPoints); if (insertionPoints.size() > 0) - return insertionPoints.first(); + return insertionPoints.constFirst(); return 0; } diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp index 49ec9ca768..2109b15a85 100644 --- a/src/gui/text/qtextformat.cpp +++ b/src/gui/text/qtextformat.cpp @@ -364,9 +364,10 @@ void QTextFormatPrivate::recalcFont() const f.setPixelSize(props.at(i).value.toInt()); break; case QTextFormat::FontWeight: { - int weight = props.at(i).value.toInt(); - if (weight == 0) weight = QFont::Normal; - f.setWeight(weight); + const QVariant weightValue = props.at(i).value; + int weight = weightValue.toInt(); + if (weight >= 0 && weightValue.isValid()) + f.setWeight(weight); break; } case QTextFormat::FontItalic: f.setItalic(props.at(i).value.toBool()); @@ -3462,7 +3463,7 @@ void QTextFormatCollection::setDefaultFont(const QFont &f) { defaultFnt = f; for (int i = 0; i < formats.count(); ++i) - if (formats[i].d) + if (formats.at(i).d) formats[i].d->resolveFont(defaultFnt); } diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h index bc627521ff..805affd87c 100644 --- a/src/gui/text/qtextformat.h +++ b/src/gui/text/qtextformat.h @@ -431,9 +431,9 @@ public: { return doubleProperty(FontPointSize); } inline void setFontWeight(int weight) - { if (weight == QFont::Normal) weight = 0; setProperty(FontWeight, weight); } + { setProperty(FontWeight, weight); } inline int fontWeight() const - { int weight = intProperty(FontWeight); if (weight == 0) weight = QFont::Normal; return weight; } + { return hasProperty(FontWeight) ? intProperty(FontWeight) : QFont::Normal; } inline void setFontItalic(bool italic) { setProperty(FontItalic, italic); } inline bool fontItalic() const diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index 576ff7d935..103a208c26 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -665,7 +665,7 @@ void QTextHtmlParser::parseTag() if (hasPrefix(QLatin1Char('/'))) { if (nodes.last().id == Html_style) { #ifndef QT_NO_CSSPARSER - QCss::Parser parser(nodes.last().text); + QCss::Parser parser(nodes.constLast().text); QCss::StyleSheet sheet; sheet.origin = QCss::StyleSheetOrigin_Author; parser.parse(&sheet, Qt::CaseInsensitive); diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index f7741bad2c..73d2e545ba 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -812,10 +812,10 @@ bool QTextOdfWriter::writeAll() } // add objects for lists, frames and tables - QVector<QTextFormat> allFormats = m_document->allFormats(); - QList<int> copy = formats.toList(); - for (QList<int>::Iterator iter = copy.begin(); iter != copy.end(); ++iter) { - QTextObject *object = m_document->objectForFormat(allFormats[*iter]); + const QVector<QTextFormat> allFormats = m_document->allFormats(); + const QList<int> copy = formats.toList(); + for (auto index : copy) { + QTextObject *object = m_document->objectForFormat(allFormats[index]); if (object) formats << object->formatIndex(); } diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp index 2d5636e1d9..e4a3c2b915 100644 --- a/src/gui/text/qtexttable.cpp +++ b/src/gui/text/qtexttable.cpp @@ -824,7 +824,7 @@ void QTextTable::insertColumns(int pos, int num) QVector<QTextLength> columnWidths = tfmt.columnWidthConstraints(); if (! columnWidths.isEmpty()) { for (int i = num; i > 0; --i) - columnWidths.insert(pos, columnWidths[qMax(0, pos-1)]); + columnWidths.insert(pos, columnWidths.at(qMax(0, pos - 1))); } tfmt.setColumnWidthConstraints (columnWidths); QTextObject::setFormat(tfmt); @@ -1046,11 +1046,12 @@ void QTextTable::mergeCells(int row, int column, int numRows, int numCols) // find the position at which to insert the contents of the merged cells QFragmentFindHelper helper(origCellPosition, p->fragmentMap()); - const auto it = std::lower_bound(d->cells.begin(), d->cells.end(), helper); + const auto begin = d->cells.cbegin(); + const auto it = std::lower_bound(begin, d->cells.cend(), helper); Q_ASSERT(it != d->cells.end()); Q_ASSERT(!(helper < *it)); Q_ASSERT(*it == cellFragment); - const int insertCellIndex = it - d->cells.begin(); + const int insertCellIndex = it - begin; int insertFragment = d->cells.value(insertCellIndex + 1, d->fragment_end); uint insertPos = p->fragmentMap().position(insertFragment); @@ -1079,11 +1080,12 @@ void QTextTable::mergeCells(int row, int column, int numRows, int numCols) if (firstCellIndex == -1) { QFragmentFindHelper helper(pos, p->fragmentMap()); - const auto it = std::lower_bound(d->cells.begin(), d->cells.end(), helper); + const auto begin = d->cells.cbegin(); + const auto it = std::lower_bound(begin, d->cells.cend(), helper); Q_ASSERT(it != d->cells.end()); Q_ASSERT(!(helper < *it)); Q_ASSERT(*it == fragment); - firstCellIndex = cellIndex = it - d->cells.begin(); + firstCellIndex = cellIndex = it - begin; } ++cellIndex; @@ -1136,7 +1138,7 @@ void QTextTable::mergeCells(int row, int column, int numRows, int numCols) } } - d->fragment_start = d->cells.first(); + d->fragment_start = d->cells.constFirst(); fmt.setTableCellRowSpan(numRows); fmt.setTableCellColumnSpan(numCols); @@ -1212,9 +1214,9 @@ void QTextTable::splitCell(int row, int column, int numRows, int numCols) for (int r = row + 1; r < row + rowSpan; ++r) { // find the cell before which to insert the new cell markers int gridIndex = r * d->nCols + column; - QVector<int>::iterator it = std::upper_bound(d->cellIndices.begin(), d->cellIndices.end(), gridIndex); - int cellIndex = it - d->cellIndices.begin(); - int fragment = d->cells.value(cellIndex, d->fragment_end); + const auto begin = d->cellIndices.cbegin(); + const auto it = std::upper_bound(begin, d->cellIndices.cend(), gridIndex); + int fragment = d->cells.value(it - begin, d->fragment_end); rowPositions[r - row] = p->fragmentMap().position(fragment); } diff --git a/src/gui/util/qgridlayoutengine.cpp b/src/gui/util/qgridlayoutengine.cpp index 20bc7166ab..8ff2a3eeec 100644 --- a/src/gui/util/qgridlayoutengine.cpp +++ b/src/gui/util/qgridlayoutengine.cpp @@ -218,8 +218,9 @@ void QGridLayoutRowData::calculateGeometries(int start, int end, qreal targetSiz qreal sumAvailable; for (int i = 0; i < n; ++i) { - if (stretches[start + i] > 0) - sumStretches += stretches[start + i]; + const int stretch = stretches.at(start + i); + if (stretch > 0) + sumStretches += stretch; } if (targetSize < totalBox.q_preferredSize) { @@ -1034,19 +1035,19 @@ void QGridLayoutEngine::setGeometries(const QRectF &contentsGeometry, const QAbs for (int i = q_items.count() - 1; i >= 0; --i) { QGridLayoutItem *item = q_items.at(i); - qreal x = q_xx[item->firstColumn()]; - qreal y = q_yy[item->firstRow()]; - qreal width = q_widths[item->lastColumn()]; - qreal height = q_heights[item->lastRow()]; + qreal x = q_xx.at(item->firstColumn()); + qreal y = q_yy.at(item->firstRow()); + qreal width = q_widths.at(item->lastColumn()); + qreal height = q_heights.at(item->lastRow()); if (item->columnSpan() != 1) - width += q_xx[item->lastColumn()] - x; + width += q_xx.at(item->lastColumn()) - x; if (item->rowSpan() != 1) - height += q_yy[item->lastRow()] - y; + height += q_yy.at(item->lastRow()) - y; const Qt::Alignment align = effectiveAlignment(item); QRectF geom = item->geometryWithin(contentsGeometry.x() + x, contentsGeometry.y() + y, - width, height, q_descents[item->lastRow()], align, m_snapToPixelGrid); + width, height, q_descents.at(item->lastRow()), align, m_snapToPixelGrid); if (m_snapToPixelGrid) { // x and y should already be rounded, but the call to geometryWithin() above might // result in a geom with x,y at half-pixels (due to centering within the cell) diff --git a/src/network/access/access.pri b/src/network/access/access.pri index 94f8b7cbc0..ba0e448010 100644 --- a/src/network/access/access.pri +++ b/src/network/access/access.pri @@ -74,14 +74,4 @@ SOURCES += \ mac: LIBS_PRIVATE += -framework Security -uikit { - HEADERS += \ - access/qnetworkreplynsurlconnectionimpl_p.h - - OBJECTIVE_SOURCES += \ - access/qnetworkreplynsurlconnectionimpl.mm - - LIBS_PRIVATE += -framework Foundation -} - include($$PWD/../../3rdparty/zlib_dependency.pri) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 56716cbe01..2f7be01078 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -331,7 +331,7 @@ bool QHttpNetworkConnectionChannel::ensureConnection() priv->phase = QAuthenticatorPrivate::Start; QString connectHost = connection->d_func()->hostName; - qint16 connectPort = connection->d_func()->port; + quint16 connectPort = connection->d_func()->port; #ifndef QT_NO_NETWORKPROXY // HTTPS always use transparent proxy. diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 1aa2d71bc5..9fee172283 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -56,10 +56,6 @@ #include "qnetworkreplydataimpl_p.h" #include "qnetworkreplyfileimpl_p.h" -#if defined(QT_PLATFORM_UIKIT) && defined(QT_NO_SSL) -#include "qnetworkreplynsurlconnectionimpl_p.h" -#endif - #include "QtCore/qbuffer.h" #include "QtCore/qurl.h" #include "QtCore/qvector.h" @@ -1207,12 +1203,6 @@ QNetworkReply *QNetworkAccessManager::createRequest(QNetworkAccessManager::Opera } } -// Use NSURLConnection for https on iOS when OpenSSL is disabled. -#if defined(QT_PLATFORM_UIKIT) && defined(QT_NO_SSL) - if (scheme == QLatin1String("https")) - return new QNetworkReplyNSURLConnectionImpl(this, request, op, outgoingData); -#endif - #ifndef QT_NO_HTTP // Since Qt 5 we use the new QNetworkReplyHttpImpl if (scheme == QLatin1String("http") || scheme == QLatin1String("preconnect-http") diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 7e8c399047..6df0b63ba7 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -94,6 +94,7 @@ public: NotAccessible = 0, Accessible = 1 }; + Q_ENUM(NetworkAccessibility) #endif explicit QNetworkAccessManager(QObject *parent = Q_NULLPTR); diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp index e27391f760..30f4bb26ce 100644 --- a/src/network/access/qnetworkreplyhttpimpl.cpp +++ b/src/network/access/qnetworkreplyhttpimpl.cpp @@ -296,7 +296,7 @@ qint64 QNetworkReplyHttpImpl::bytesAvailable() const // if we load from cache device if (d->cacheLoadDevice) { - return QNetworkReply::bytesAvailable() + d->cacheLoadDevice->bytesAvailable() + d->downloadMultiBuffer.byteAmount(); + return QNetworkReply::bytesAvailable() + d->cacheLoadDevice->bytesAvailable(); } // zerocopy buffer @@ -305,7 +305,7 @@ qint64 QNetworkReplyHttpImpl::bytesAvailable() const } // normal buffer - return QNetworkReply::bytesAvailable() + d->downloadMultiBuffer.byteAmount(); + return QNetworkReply::bytesAvailable(); } bool QNetworkReplyHttpImpl::isSequential () const @@ -329,12 +329,6 @@ qint64 QNetworkReplyHttpImpl::readData(char* data, qint64 maxlen) if (d->cacheLoadDevice) { // FIXME bytesdownloaded, position etc? - // There is something already in the buffer we buffered before because the user did not read() - // anything, so we read there first: - if (!d->downloadMultiBuffer.isEmpty()) { - return d->downloadMultiBuffer.read(data, maxlen); - } - qint64 ret = d->cacheLoadDevice->read(data, maxlen); return ret; } @@ -351,25 +345,14 @@ qint64 QNetworkReplyHttpImpl::readData(char* data, qint64 maxlen) } // normal buffer - if (d->downloadMultiBuffer.isEmpty()) { - if (d->state == d->Finished || d->state == d->Aborted) - return -1; - return 0; - } + if (d->state == d->Finished || d->state == d->Aborted) + return -1; - if (maxlen == 1) { - // optimization for getChar() - *data = d->downloadMultiBuffer.getChar(); - if (readBufferSize()) - emit readBufferFreed(1); - return 1; - } - - maxlen = qMin<qint64>(maxlen, d->downloadMultiBuffer.byteAmount()); - qint64 bytesRead = d->downloadMultiBuffer.read(data, maxlen); + qint64 wasBuffered = d->bytesBuffered; + d->bytesBuffered = 0; if (readBufferSize()) - emit readBufferFreed(bytesRead); - return bytesRead; + emit readBufferFreed(wasBuffered); + return 0; } void QNetworkReplyHttpImpl::setReadBufferSize(qint64 size) @@ -387,12 +370,12 @@ bool QNetworkReplyHttpImpl::canReadLine () const return true; if (d->cacheLoadDevice) - return d->cacheLoadDevice->canReadLine() || d->downloadMultiBuffer.canReadLine(); + return d->cacheLoadDevice->canReadLine(); if (d->downloadZerocopyBuffer) return memchr(d->downloadZerocopyBuffer + d->downloadBufferReadPosition, '\n', d->downloadBufferCurrentSize - d->downloadBufferReadPosition); - return d->downloadMultiBuffer.canReadLine(); + return false; } #ifndef QT_NO_SSL @@ -444,6 +427,7 @@ QNetworkReplyHttpImplPrivate::QNetworkReplyHttpImplPrivate() , resumeOffset(0) , preMigrationDownloaded(-1) , bytesDownloaded(0) + , bytesBuffered(0) , downloadBufferReadPosition(0) , downloadBufferCurrentSize(0) , downloadZerocopyBuffer(0) @@ -1047,10 +1031,11 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d) cacheSaveDevice->write(item.constData(), item.size()); if (!isHttpRedirectResponse()) - downloadMultiBuffer.append(item); + buffer.append(item); bytesWritten += item.size(); } + bytesBuffered += bytesWritten; pendingDownloadDataCopy.clear(); QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader); @@ -1823,9 +1808,8 @@ void QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead() // If there are still bytes available in the cacheLoadDevice then the user did not read // in response to the readyRead() signal. This means we have to load from the cacheLoadDevice // and buffer that stuff. This is needed to be able to properly emit finished() later. - while (cacheLoadDevice->bytesAvailable() && !isHttpRedirectResponse()) { - downloadMultiBuffer.append(cacheLoadDevice->readAll()); - } + while (cacheLoadDevice->bytesAvailable() && !isHttpRedirectResponse()) + buffer.append(cacheLoadDevice->readAll()); if (cacheLoadDevice->isSequential()) { // check if end and we can read the EOF -1 diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h index 669258f15b..4aba915c7d 100644 --- a/src/network/access/qnetworkreplyhttpimpl_p.h +++ b/src/network/access/qnetworkreplyhttpimpl_p.h @@ -240,12 +240,11 @@ public: quint64 resumeOffset; qint64 preMigrationDownloaded; - // Used for normal downloading. For "zero copy" the downloadZerocopyBuffer is used - QByteDataBuffer downloadMultiBuffer; QByteDataBuffer pendingDownloadData; // For signal compression qint64 bytesDownloaded; + qint64 bytesBuffered; - // only used when the "zero copy" style is used. Else downloadMultiBuffer is used. + // Only used when the "zero copy" style is used. // Please note that the whole "zero copy" download buffer API is private right now. Do not use it. qint64 downloadBufferReadPosition; qint64 downloadBufferCurrentSize; diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index d69d5983cb..54930a351a 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -184,17 +184,13 @@ void QNetworkReplyImplPrivate::_q_copyReadyRead() break; bytesToRead = qBound<qint64>(1, bytesToRead, copyDevice->bytesAvailable()); - QByteArray byteData; - byteData.resize(bytesToRead); - qint64 bytesActuallyRead = copyDevice->read(byteData.data(), byteData.size()); + qint64 bytesActuallyRead = copyDevice->read(buffer.reserve(bytesToRead), bytesToRead); if (bytesActuallyRead == -1) { - byteData.clear(); + buffer.chop(bytesToRead); backendNotify(NotifyCopyFinished); break; } - - byteData.resize(bytesActuallyRead); - readBuffer.append(byteData); + buffer.chop(bytesToRead - bytesActuallyRead); if (!copyDevice->isSequential() && copyDevice->atEnd()) { backendNotify(NotifyCopyFinished); @@ -582,7 +578,7 @@ qint64 QNetworkReplyImplPrivate::nextDownstreamBlockSize() const if (readBufferMaxSize == 0) return DesiredBufferSize; - return qMax<qint64>(0, readBufferMaxSize - readBuffer.byteAmount()); + return qMax<qint64>(0, readBufferMaxSize - buffer.size()); } void QNetworkReplyImplPrivate::initCacheSaveDevice() @@ -624,7 +620,7 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice() } // we received downstream data and send this to the cache -// and to our readBuffer (which in turn gets read by the user of QNetworkReply) +// and to our buffer (which in turn gets read by the user of QNetworkReply) void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) { Q_Q(QNetworkReplyImpl); @@ -641,7 +637,7 @@ void QNetworkReplyImplPrivate::appendDownstreamData(QByteDataBuffer &data) if (cacheSaveDevice) cacheSaveDevice->write(item.constData(), item.size()); - readBuffer.append(item); + buffer.append(item); bytesWritten += item.size(); } @@ -975,13 +971,6 @@ void QNetworkReplyImpl::close() d->finished(); } -bool QNetworkReplyImpl::canReadLine () const -{ - Q_D(const QNetworkReplyImpl); - return QNetworkReply::canReadLine() || d->readBuffer.canReadLine(); -} - - /*! Returns the number of bytes available for reading with QIODevice::read(). The number of bytes available may grow until @@ -996,14 +985,14 @@ qint64 QNetworkReplyImpl::bytesAvailable() const return QNetworkReply::bytesAvailable() + maxAvail; } - return QNetworkReply::bytesAvailable() + d_func()->readBuffer.byteAmount(); + return QNetworkReply::bytesAvailable(); } void QNetworkReplyImpl::setReadBufferSize(qint64 size) { Q_D(QNetworkReplyImpl); if (size > d->readBufferMaxSize && - size > d->readBuffer.byteAmount()) + size > d->buffer.size()) d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite); QNetworkReply::setReadBufferSize(size); @@ -1061,19 +1050,12 @@ qint64 QNetworkReplyImpl::readData(char *data, qint64 maxlen) } - if (d->readBuffer.isEmpty()) - return d->state == QNetworkReplyPrivate::Finished ? -1 : 0; // FIXME what about "Aborted" state? + if (d->state == QNetworkReplyPrivate::Finished) + return -1; d->backendNotify(QNetworkReplyImplPrivate::NotifyDownstreamReadyWrite); - if (maxlen == 1) { - // optimization for getChar() - *data = d->readBuffer.getChar(); - return 1; - } - - maxlen = qMin<qint64>(maxlen, d->readBuffer.byteAmount()); - return d->readBuffer.read(data, maxlen); + return 0; } /*! diff --git a/src/network/access/qnetworkreplyimpl_p.h b/src/network/access/qnetworkreplyimpl_p.h index 156cb411c7..054cbcc3a7 100644 --- a/src/network/access/qnetworkreplyimpl_p.h +++ b/src/network/access/qnetworkreplyimpl_p.h @@ -81,7 +81,6 @@ public: virtual void close() Q_DECL_OVERRIDE; virtual qint64 bytesAvailable() const Q_DECL_OVERRIDE; virtual void setReadBufferSize(qint64 size) Q_DECL_OVERRIDE; - virtual bool canReadLine () const Q_DECL_OVERRIDE; virtual qint64 readData(char *data, qint64 maxlen) Q_DECL_OVERRIDE; virtual bool event(QEvent *) Q_DECL_OVERRIDE; @@ -187,8 +186,6 @@ public: QList<QNetworkProxy> proxyList; #endif - // Used for normal downloading. For "zero copy" the downloadBuffer is used - QByteDataBuffer readBuffer; qint64 bytesDownloaded; qint64 lastBytesDownloaded; qint64 bytesUploaded; @@ -199,7 +196,7 @@ public: State state; - // only used when the "zero copy" style is used. Else readBuffer is used. + // Only used when the "zero copy" style is used. // Please note that the whole "zero copy" download buffer API is private right now. Do not use it. qint64 downloadBufferReadPosition; qint64 downloadBufferCurrentSize; diff --git a/src/network/access/qnetworkreplynsurlconnectionimpl.mm b/src/network/access/qnetworkreplynsurlconnectionimpl.mm deleted file mode 100644 index 25b79e3347..0000000000 --- a/src/network/access/qnetworkreplynsurlconnectionimpl.mm +++ /dev/null @@ -1,454 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 "qnetworkreplynsurlconnectionimpl_p.h" - -#include "QtCore/qdatetime.h" -#include <QtCore/qcoreapplication.h> -#include <QtCore/qdebug.h> -#include <Foundation/Foundation.h> - -QT_BEGIN_NAMESPACE - -// Network reply implementation using NSUrlConnection. -// -// Class/object structure: -// -// QNetworkReplyNSURLConnectionImpl -// |- QNetworkReplyNSURLConnectionImplPrivate -// |- (bytes read) -// |- (QIODevice and CFStream for async POST data transfer) -// |- NSURLConnection -// |- QtNSURLConnectionDelegate <NSURLConnectionDataDelegate> -// |- NSURLResponse/NSHTTPURLResponse -// |- (response data) -// -// The main entry point is the QNetworkReplyNSURLConnectionImpl constructor, which -// receives a network request from QNetworkAccessManager. The constructor -// creates a NSURLRequest and initiates a NSURLConnection with a QtNSURLConnectionDelegate. -// The delegate callbacks are then called asynchronously as the request completes. -// - -@class QtNSURLConnectionDelegate; -class QNetworkReplyNSURLConnectionImplPrivate: public QNetworkReplyPrivate -{ -public: - QNetworkReplyNSURLConnectionImplPrivate(); - virtual ~QNetworkReplyNSURLConnectionImplPrivate(); - - Q_DECLARE_PUBLIC(QNetworkReplyNSURLConnectionImpl) - NSURLConnection * urlConnection; - QtNSURLConnectionDelegate *urlConnectionDelegate; - qint64 bytesRead; - - // Sequental outgiong data streaming - QIODevice *outgoingData; - CFReadStreamRef readStream; - CFWriteStreamRef writeStream; - CFIndex transferBufferSize; - - // Forwarding functions to the public class. - void setFinished(); - void setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value); - void setRawHeader(const QByteArray &headerName, const QByteArray &value); - void setError(QNetworkReply::NetworkError errorCode, const QString &errorString); - void setAttribute(QNetworkRequest::Attribute code, const QVariant &value); -}; - -@interface QtNSURLConnectionDelegate : NSObject -{ - NSURLResponse *response; - NSMutableData *responseData; - QNetworkReplyNSURLConnectionImplPrivate * replyprivate; -} - -- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate ; -- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge; -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError*)error; -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse*)response; -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data; -- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten - totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; -- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse; -- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse; -- (void)connectionDidFinishLoading:(NSURLConnection*)connection; -- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection; - -@end - -QNetworkReplyNSURLConnectionImplPrivate::QNetworkReplyNSURLConnectionImplPrivate() - : QNetworkReplyPrivate() - , urlConnection(0) - , urlConnectionDelegate(0) - , bytesRead(0) - , readStream(0) - , writeStream(0) - , transferBufferSize(4096) -{ -} - -QNetworkReplyNSURLConnectionImplPrivate::~QNetworkReplyNSURLConnectionImplPrivate() -{ - [urlConnection cancel]; - [urlConnection release]; - [urlConnectionDelegate release]; - if (readStream) - CFRelease(readStream); - if (writeStream) - CFRelease(writeStream); -} - -void QNetworkReplyNSURLConnectionImplPrivate::setFinished() -{ - q_func()->setFinished(true); - QMetaObject::invokeMethod(q_func(), "finished", Qt::QueuedConnection); -} - -void QNetworkReplyNSURLConnectionImplPrivate::setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value) -{ - q_func()->setHeader(header, value); -} - -void QNetworkReplyNSURLConnectionImplPrivate::setRawHeader(const QByteArray &headerName, const QByteArray &value) -{ - q_func()->setRawHeader(headerName, value); -} - -void QNetworkReplyNSURLConnectionImplPrivate::setError(QNetworkReply::NetworkError errorCode, const QString &errorString) -{ - q_func()->setError(errorCode, errorString); -} - -void QNetworkReplyNSURLConnectionImplPrivate::setAttribute(QNetworkRequest::Attribute code, const QVariant &value) -{ - q_func()->setAttribute(code, value); -} - -void QNetworkReplyNSURLConnectionImpl::readyReadOutgoingData() -{ - Q_D(QNetworkReplyNSURLConnectionImpl); - int bytesRead = 0; - do { - char data[d->transferBufferSize]; - bytesRead = d->outgoingData->read(data, d->transferBufferSize); - if (bytesRead <= 0) - break; - CFIndex bytesWritten = CFWriteStreamWrite(d->writeStream, reinterpret_cast<unsigned char *>(data), bytesRead); - if (bytesWritten != bytesRead) { - CFErrorRef err = CFWriteStreamCopyError(d->writeStream); - qWarning() << "QNetworkReplyNSURLConnectionImpl: CFWriteStreamWrite error" - << (err ? QString::number(CFErrorGetCode(err)) : QStringLiteral("")); - } - } while (bytesRead > 0); - - if (d->outgoingData->atEnd()) - CFWriteStreamClose(d->writeStream); -} - -@interface QtNSURLConnectionDelegate () - -@property (nonatomic, retain) NSURLResponse* response; -@property (nonatomic, retain) NSMutableData* responseData; - -@end - -@implementation QtNSURLConnectionDelegate - -@synthesize response; -@synthesize responseData; - -- (id)initWithQNetworkReplyNSURLConnectionImplPrivate:(QNetworkReplyNSURLConnectionImplPrivate *)a_replyPrivate -{ - if (self = [super init]) - replyprivate = a_replyPrivate; - return self; -} - -- (void)dealloc -{ - [response release]; - [responseData release]; - [super dealloc]; -} - -- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge -{ - Q_UNUSED(connection) - Q_UNUSED(challenge) - - if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; - SecTrustResultType resultType; - SecTrustEvaluate(serverTrust, &resultType); - if (resultType == kSecTrustResultUnspecified) { - // All good - [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; - } else if (resultType == kSecTrustResultRecoverableTrustFailure) { - // Certificate verification error, ask user - // ### TODO actually ask user - // (test site: https://testssl-expire.disig.sk/index.en.html) - qWarning() << "QNetworkReplyNSURLConnection: Certificate verification error handlig is" - << "not implemented. Connection will time out."; - } else { - // other error, which the default handler will handle - [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; - } - } - - [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; -} - -- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error -{ - Q_UNUSED(connection) - - QNetworkReply::NetworkError qtError = QNetworkReply::UnknownNetworkError; - if ([[error domain] isEqualToString:NSURLErrorDomain]) { - switch ([error code]) { - case NSURLErrorTimedOut: qtError = QNetworkReply::TimeoutError; break; - case NSURLErrorUnsupportedURL: qtError = QNetworkReply::ProtocolUnknownError; break; - case NSURLErrorCannotFindHost: qtError = QNetworkReply::HostNotFoundError; break; - case NSURLErrorCannotConnectToHost: qtError = QNetworkReply::ConnectionRefusedError; break; - case NSURLErrorNetworkConnectionLost: qtError = QNetworkReply::NetworkSessionFailedError; break; - case NSURLErrorDNSLookupFailed: qtError = QNetworkReply::HostNotFoundError; break; - case NSURLErrorNotConnectedToInternet: qtError = QNetworkReply::NetworkSessionFailedError; break; - case NSURLErrorUserAuthenticationRequired: qtError = QNetworkReply::AuthenticationRequiredError; break; - default: break; - } - } - - replyprivate->setError(qtError, QString::fromNSString([error localizedDescription])); - replyprivate->setFinished(); -} - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)aResponse -{ - Q_UNUSED(connection) - self.response = aResponse; - self.responseData = [NSMutableData data]; - - // copy headers - if ([aResponse isKindOfClass:[NSHTTPURLResponse class]]) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)aResponse; - NSDictionary *headers = [httpResponse allHeaderFields]; - for (NSString *key in headers) { - NSString *value = [headers objectForKey:key]; - replyprivate->setRawHeader(QString::fromNSString(key).toUtf8(), QString::fromNSString(value).toUtf8()); - } - - int code = [httpResponse statusCode]; - replyprivate->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, code); - } else { - if ([aResponse expectedContentLength] != NSURLResponseUnknownLength) - replyprivate->setHeader(QNetworkRequest::ContentLengthHeader, [aResponse expectedContentLength]); - } - - QMetaObject::invokeMethod(replyprivate->q_func(), "metaDataChanged", Qt::QueuedConnection); -} - -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data -{ - Q_UNUSED(connection) - [responseData appendData:data]; - - if ([response expectedContentLength] != NSURLResponseUnknownLength) { - QMetaObject::invokeMethod(replyprivate->q_func(), "downloadProgress", Qt::QueuedConnection, - Q_ARG(qint64, qint64([responseData length] + replyprivate->bytesRead)), - Q_ARG(qint64, qint64([response expectedContentLength]))); - } - - QMetaObject::invokeMethod(replyprivate->q_func(), "readyRead", Qt::QueuedConnection); -} - -- (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten - totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite -{ - Q_UNUSED(connection) - Q_UNUSED(bytesWritten) - QMetaObject::invokeMethod(replyprivate->q_func(), "uploadProgress", Qt::QueuedConnection, - Q_ARG(qint64, qint64(totalBytesWritten)), - Q_ARG(qint64, qint64(totalBytesExpectedToWrite))); -} - -- (NSCachedURLResponse*)connection:(NSURLConnection*)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse -{ - Q_UNUSED(connection) - return cachedResponse; -} - -- (NSURLRequest*)connection:(NSURLConnection*)connection willSendRequest:(NSURLRequest*)request redirectResponse:(NSURLResponse*)redirectResponse -{ - Q_UNUSED(connection) - Q_UNUSED(redirectResponse) - return request; -} - -- (void)connectionDidFinishLoading:(NSURLConnection*)connection -{ - Q_UNUSED(connection) - replyprivate->setFinished(); -} - -- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection*)connection -{ - Q_UNUSED(connection) - return YES; -} - -@end - -QNetworkReplyNSURLConnectionImpl::~QNetworkReplyNSURLConnectionImpl() -{ -} - -QNetworkReplyNSURLConnectionImpl::QNetworkReplyNSURLConnectionImpl(QObject *parent, - const QNetworkRequest &request, const QNetworkAccessManager::Operation operation, QIODevice* outgoingData) - : QNetworkReply(*new QNetworkReplyNSURLConnectionImplPrivate(), parent) -{ - setRequest(request); - setUrl(request.url()); - setOperation(operation); - QNetworkReply::open(QIODevice::ReadOnly); - - QNetworkReplyNSURLConnectionImplPrivate *d = (QNetworkReplyNSURLConnectionImplPrivate*) d_func(); - - QUrl url = request.url(); - if (url.host() == QLatin1String("localhost")) - url.setHost(QString()); - - if (url.path().isEmpty()) - url.setPath(QLatin1String("/")); - setUrl(url); - - // Create a NSMutableURLRequest from QNetworkRequest - NSMutableURLRequest *nsRequest = [NSMutableURLRequest requestWithURL:request.url().toNSURL() - cachePolicy:NSURLRequestUseProtocolCachePolicy - timeoutInterval:60.0]; - // copy headers - const auto headers = request.rawHeaderList(); - for (const QByteArray &header : headers) { - QByteArray headerValue = request.rawHeader(header); - [nsRequest addValue:QString::fromUtf8(headerValue).toNSString() - forHTTPHeaderField:QString::fromUtf8(header).toNSString()]; - } - - if (operation == QNetworkAccessManager::GetOperation) - [nsRequest setHTTPMethod:@"GET"]; - else if (operation == QNetworkAccessManager::PostOperation) - [nsRequest setHTTPMethod:@"POST"]; - else if (operation == QNetworkAccessManager::PutOperation) - [nsRequest setHTTPMethod:@"PUT"]; - else if (operation == QNetworkAccessManager::DeleteOperation) - [nsRequest setHTTPMethod:@"DELETE"]; - else - qWarning() << "QNetworkReplyNSURLConnection: Unsupported netork operation" << operation; - - if (outgoingData) { - d->outgoingData = outgoingData; - if (outgoingData->isSequential()) { - // set up streaming from outgoingData iodevice to request - CFStreamCreateBoundPair(kCFAllocatorDefault, &d->readStream, &d->writeStream, d->transferBufferSize); - CFWriteStreamOpen(d->writeStream); - [nsRequest setHTTPBodyStream:reinterpret_cast<NSInputStream *>(d->readStream)]; - connect(outgoingData, SIGNAL(readyRead()), this, SLOT(readyReadOutgoingData())); - readyReadOutgoingData(); - } else { - // move all data at once - QByteArray data = outgoingData->readAll(); - [nsRequest setHTTPBody:[NSData dataWithBytes:data.constData() length:data.length()]]; - } - } - - // Create connection - d->urlConnectionDelegate = [[QtNSURLConnectionDelegate alloc] initWithQNetworkReplyNSURLConnectionImplPrivate:d]; - d->urlConnection = [[NSURLConnection alloc] initWithRequest:nsRequest delegate:d->urlConnectionDelegate]; - if (!d->urlConnection) { - // ### what type of error is an initWithRequest fail? - setError(QNetworkReply::ProtocolUnknownError, QStringLiteral("QNetworkReplyNSURLConnection internal error")); - } -} - -void QNetworkReplyNSURLConnectionImpl::close() -{ - // No-op? Network ops should continue (especially POSTs) - QNetworkReply::close(); -} - -void QNetworkReplyNSURLConnectionImpl::abort() -{ - Q_D(QNetworkReplyNSURLConnectionImpl); - [d->urlConnection cancel]; - QNetworkReply::close(); -} - -qint64 QNetworkReplyNSURLConnectionImpl::bytesAvailable() const -{ - Q_D(const QNetworkReplyNSURLConnectionImpl); - qint64 available = QNetworkReply::bytesAvailable() + - [[d->urlConnectionDelegate responseData] length]; - return available; -} - -bool QNetworkReplyNSURLConnectionImpl::isSequential() const -{ - return true; -} - -qint64 QNetworkReplyNSURLConnectionImpl::size() const -{ - Q_D(const QNetworkReplyNSURLConnectionImpl); - return [[d->urlConnectionDelegate responseData] length] + d->bytesRead; -} - -/*! - \internal -*/ -qint64 QNetworkReplyNSURLConnectionImpl::readData(char *data, qint64 maxlen) -{ - Q_D(QNetworkReplyNSURLConnectionImpl); - qint64 dataSize = [[d->urlConnectionDelegate responseData] length]; - qint64 canRead = qMin(maxlen, dataSize); - const char *sourceBase = static_cast<const char *>([[d->urlConnectionDelegate responseData] bytes]); - memcpy(data, sourceBase, canRead); - [[d->urlConnectionDelegate responseData] replaceBytesInRange:NSMakeRange(0, canRead) withBytes:NULL length:0]; - d->bytesRead += canRead; - return canRead; -} - -QT_END_NAMESPACE diff --git a/src/network/access/qnetworkreplynsurlconnectionimpl_p.h b/src/network/access/qnetworkreplynsurlconnectionimpl_p.h deleted file mode 100644 index c948e66629..0000000000 --- a/src/network/access/qnetworkreplynsurlconnectionimpl_p.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 QNETWORKREPLYNSURLCONNECTIONIMPL_H -#define QNETWORKREPLYNSURLCONNECTIONIMPL_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the Network Access API. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include "qnetworkreply.h" -#include "qnetworkreply_p.h" -#include "qnetworkaccessmanager.h" -#include <QFile> -#include <private/qabstractfileengine_p.h> - -QT_BEGIN_NAMESPACE - - -class QNetworkReplyNSURLConnectionImplPrivate; -class QNetworkReplyNSURLConnectionImpl: public QNetworkReply -{ - Q_OBJECT -public: - QNetworkReplyNSURLConnectionImpl(QObject *parent, const QNetworkRequest &req, const QNetworkAccessManager::Operation op, QIODevice* outgoingData); - virtual ~QNetworkReplyNSURLConnectionImpl(); - virtual void abort(); - - // reimplemented from QNetworkReply - virtual void close(); - virtual qint64 bytesAvailable() const; - virtual bool isSequential () const; - qint64 size() const; - - virtual qint64 readData(char *data, qint64 maxlen); -public Q_SLOTS: - void readyReadOutgoingData(); - - Q_DECLARE_PRIVATE(QNetworkReplyNSURLConnectionImpl) -}; - -QT_END_NAMESPACE - -#endif // QNetworkReplyNSURLConnectionImpl_H diff --git a/src/network/kernel/qdnslookup_unix.cpp b/src/network/kernel/qdnslookup_unix.cpp index 35981a2f2c..41038dc8da 100644 --- a/src/network/kernel/qdnslookup_unix.cpp +++ b/src/network/kernel/qdnslookup_unix.cpp @@ -47,7 +47,9 @@ #include <sys/types.h> #include <netinet/in.h> #include <arpa/nameser.h> -#include <arpa/nameser_compat.h> +#if !defined(Q_OS_OPENBSD) +# include <arpa/nameser_compat.h> +#endif #include <resolv.h> #if defined(__GNU_LIBRARY__) && !defined(__UCLIBC__) @@ -58,6 +60,9 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_LIBRARY +#if defined(Q_OS_OPENBSD) +typedef struct __res_state* res_state; +#endif typedef int (*dn_expand_proto)(const unsigned char *, const unsigned char *, const unsigned char *, char *, int); static dn_expand_proto local_dn_expand = 0; typedef void (*res_nclose_proto)(res_state); diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 757a6ad0b0..681c81d6eb 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -115,14 +115,13 @@ public: QString ipString; QString scopeId; - quint32 a; // IPv4 address union { Q_IPV6ADDR a6; // IPv6 address struct { quint64 c[2]; } a6_64; struct { quint32 c[4]; } a6_32; }; - QAbstractSocket::NetworkLayerProtocol protocol; - + quint32 a; // IPv4 address + qint8 protocol; bool isParsed; friend class QHostAddress; @@ -735,7 +734,7 @@ quint32 QHostAddress::toIPv4Address(bool *ok) const QAbstractSocket::NetworkLayerProtocol QHostAddress::protocol() const { QT_ENSURE_PARSED(this); - return d->protocol; + return QAbstractSocket::NetworkLayerProtocol(d->protocol); } /*! diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index b3e456be69..7ef9d7f26b 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -560,7 +560,9 @@ int QNativeSocketEnginePrivate::nativeAccept() setError(QAbstractSocket::SocketResourceError, NotSocketErrorString); break; case EPROTONOSUPPORT: +#if !defined(Q_OS_OPENBSD) case EPROTO: +#endif case EAFNOSUPPORT: case EINVAL: setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString); @@ -900,7 +902,9 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) { sockaddr_dl *sdl = reinterpret_cast<sockaddr_dl *>(CMSG_DATA(cmsgptr)); - +# if defined(Q_OS_OPENBSD) +# define LLINDEX(s) ((s)->sdl_index) +# endif header->ifindex = LLINDEX(sdl); } # endif diff --git a/src/network/socket/qnativesocketengine_winrt.cpp b/src/network/socket/qnativesocketengine_winrt.cpp index 181c49f200..dd43615f98 100644 --- a/src/network/socket/qnativesocketengine_winrt.cpp +++ b/src/network/socket/qnativesocketengine_winrt.cpp @@ -337,7 +337,7 @@ bool QNativeSocketEngine::connectToHostByName(const QString &name, quint16 port) d->socketState = QAbstractSocket::ConnectingState; hr = QEventDispatcherWinRT::runOnXamlThread([d]() { return d->connectOp->put_Completed(Callback<IAsyncActionCompletedHandler>( - d, &QNativeSocketEnginePrivate::handleConnectToHost).Get()); + d, &QNativeSocketEnginePrivate::handleConnectOpFinished).Get()); }); Q_ASSERT_SUCCEEDED(hr); @@ -477,7 +477,10 @@ void QNativeSocketEngine::close() hr = socket3->CancelIOAsync(&action); Q_ASSERT_SUCCEEDED(hr); hr = QWinRTFunctions::await(action); - Q_ASSERT_SUCCEEDED(hr); + // If there is no pending IO (no read established before) the function will fail with + // "function was called at an unexpected time" which is fine. + if (hr != E_ILLEGAL_METHOD_CALL) + Q_ASSERT_SUCCEEDED(hr); return S_OK; }); Q_ASSERT_SUCCEEDED(hr); @@ -759,7 +762,7 @@ bool QNativeSocketEngine::waitForWrite(int msecs, bool *timedOut) if (d->socketState == QAbstractSocket::ConnectingState) { HRESULT hr = QWinRTFunctions::await(d->connectOp, QWinRTFunctions::ProcessMainThreadEvents); if (SUCCEEDED(hr)) { - d->handleConnectionEstablished(d->connectOp.Get()); + d->handleConnectOpFinished(d->connectOp.Get(), Completed); return true; } } @@ -1214,38 +1217,32 @@ HRESULT QNativeSocketEnginePrivate::handleClientConnection(IStreamSocketListener return S_OK; } -HRESULT QNativeSocketEnginePrivate::handleConnectToHost(IAsyncAction *action, AsyncStatus) -{ - handleConnectionEstablished(action); - return S_OK; -} - -void QNativeSocketEnginePrivate::handleConnectionEstablished(IAsyncAction *action) +HRESULT QNativeSocketEnginePrivate::handleConnectOpFinished(IAsyncAction *action, AsyncStatus) { Q_Q(QNativeSocketEngine); if (wasDeleted || !connectOp) // Protect against a late callback - return; + return S_OK; HRESULT hr = action->GetResults(); switch (hr) { case 0x8007274c: // A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond. setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); socketState = QAbstractSocket::UnconnectedState; - break; + return S_OK; case 0x80072751: // A socket operation was attempted to an unreachable host. setError(QAbstractSocket::HostNotFoundError, HostUnreachableErrorString); socketState = QAbstractSocket::UnconnectedState; - break; + return S_OK; case 0x8007274d: // No connection could be made because the target machine actively refused it. setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); socketState = QAbstractSocket::UnconnectedState; - break; + return S_OK; default: if (FAILED(hr)) { setError(QAbstractSocket::UnknownSocketError, UnknownSocketErrorString); socketState = QAbstractSocket::UnconnectedState; + return S_OK; } - break; } // The callback might be triggered several times if we do not cancel/reset it here @@ -1267,13 +1264,14 @@ void QNativeSocketEnginePrivate::handleConnectionEstablished(IAsyncAction *actio emit q->connectionReady(); if (socketType != QAbstractSocket::TcpSocket) - return; + return S_OK; // Delay the reader so that the SSL socket can upgrade if (sslSocket) QObject::connect(qobject_cast<QSslSocket *>(sslSocket), &QSslSocket::encrypted, q, &QNativeSocketEngine::establishRead); else q->establishRead(); + return S_OK; } HRESULT QNativeSocketEnginePrivate::handleReadyRead(IAsyncBufferOperation *asyncInfo, AsyncStatus status) diff --git a/src/network/socket/qnativesocketengine_winrt_p.h b/src/network/socket/qnativesocketengine_winrt_p.h index 325e4965e6..5b76c2d223 100644 --- a/src/network/socket/qnativesocketengine_winrt_p.h +++ b/src/network/socket/qnativesocketengine_winrt_p.h @@ -220,8 +220,7 @@ private: ABI::Windows::Networking::Sockets::IDatagramSocketMessageReceivedEventArgs *args); HRESULT handleClientConnection(ABI::Windows::Networking::Sockets::IStreamSocketListener *tcpListener, ABI::Windows::Networking::Sockets::IStreamSocketListenerConnectionReceivedEventArgs *args); - HRESULT handleConnectToHost(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); - void handleConnectionEstablished(ABI::Windows::Foundation::IAsyncAction *action); + HRESULT handleConnectOpFinished(ABI::Windows::Foundation::IAsyncAction *, ABI::Windows::Foundation::AsyncStatus); HRESULT handleReadyRead(ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer *, UINT32> *asyncInfo, ABI::Windows::Foundation::AsyncStatus); }; diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index 1870091693..ee3e0d9f0e 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -1118,7 +1118,9 @@ bool QSocks5SocketEngine::connectInternal() } if (d->socketState != QAbstractSocket::ConnectingState) { - if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized) { + if (d->socks5State == QSocks5SocketEnginePrivate::Uninitialized + // We may have new auth credentials since an earlier failure: + || d->socks5State == QSocks5SocketEnginePrivate::AuthenticatingError) { setState(QAbstractSocket::ConnectingState); //limit buffer in internal socket, data is buffered in the external socket under application control d->data->controlSocket->setReadBufferSize(65536); diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 75a38db5f9..580b0fbdde 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2642,7 +2642,8 @@ QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories() << "/var/ssl/certs/" // AIX << "/usr/local/ssl/certs/" // Solaris << "/etc/openssl/certs/" // BlackBerry - << "/opt/openssl/certs/"; // HP-UX + << "/opt/openssl/certs/" // HP-UX + << "/etc/ssl/"; // OpenBSD } /*! diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index c1ea10aefb..35d7654730 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1344,8 +1344,12 @@ void QSslSocketBackendPrivate::_q_caRootLoaded(QSslCertificate cert, QSslCertifi if (plainSocket) plainSocket->resume(); paused = false; - if (checkSslErrors() && ssl) + if (checkSslErrors() && ssl) { + bool willClose = (autoStartHandshake && pendingClose); continueHandshake(); + if (!willClose) + transmit(); + } } class QWindowsCaRootFetcherThread : public QThread diff --git a/src/platformheaders/doc/src/qtplatformheaders.qdoc b/src/platformheaders/doc/src/qtplatformheaders.qdoc index 745edf7983..6eb7b27cce 100644 --- a/src/platformheaders/doc/src/qtplatformheaders.qdoc +++ b/src/platformheaders/doc/src/qtplatformheaders.qdoc @@ -80,6 +80,19 @@ \sa QXcbWindowFunctions QWindowsWindowFunctions + \section1 Getting Started + + To include the definitions of the module's functions and classes, use the following directives: + \code + #include <QtPlatformHeaders/QWindowsWindowFunctions> + #include <QtPlatformHeaders/QXcbWindowFunctions> + \endcode + + As the module is header-only, no further modifications to the .pro files are required to use it. + + \note The module name (\c QtPlatformHeaders) must appear in the \c #include directive. + \note It is not necessary to enclose the code in \c #ifdef directives depending on platform. + \section1 API Reference \list \li \l{Qt Platform Headers C++ Classes}{C++ Classes} diff --git a/src/platformsupport/devicediscovery/devicediscovery.pri b/src/platformsupport/devicediscovery/devicediscovery.pri index 1ac25da901..9829ae88ba 100644 --- a/src/platformsupport/devicediscovery/devicediscovery.pri +++ b/src/platformsupport/devicediscovery/devicediscovery.pri @@ -1,18 +1,14 @@ HEADERS += $$PWD/qdevicediscovery_p.h -linux { - contains(QT_CONFIG, libudev) { - SOURCES += $$PWD/qdevicediscovery_udev.cpp - HEADERS += $$PWD/qdevicediscovery_udev_p.h - INCLUDEPATH += $$QMAKE_INCDIR_LIBUDEV - LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV - } else: contains(QT_CONFIG, evdev) { - SOURCES += $$PWD/qdevicediscovery_static.cpp - HEADERS += $$PWD/qdevicediscovery_static_p.h - } else { - SOURCES += $$PWD/qdevicediscovery_dummy.cpp - HEADERS += $$PWD/qdevicediscovery_dummy_p.h - } +contains(QT_CONFIG, libudev) { + SOURCES += $$PWD/qdevicediscovery_udev.cpp + HEADERS += $$PWD/qdevicediscovery_udev_p.h + INCLUDEPATH += $$QMAKE_INCDIR_LIBUDEV + LIBS_PRIVATE += $$QMAKE_LIBS_LIBUDEV +} else: contains(QT_CONFIG, evdev) { + SOURCES += $$PWD/qdevicediscovery_static.cpp + HEADERS += $$PWD/qdevicediscovery_static_p.h } else { SOURCES += $$PWD/qdevicediscovery_dummy.cpp + HEADERS += $$PWD/qdevicediscovery_dummy_p.h } diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index f8efd105bc..da41cfeabf 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -587,6 +587,10 @@ int q_screenDepthFromFb(int framebufferDevice) qreal q_refreshRateFromFb(int framebufferDevice) { +#ifndef Q_OS_LINUX + Q_UNUSED(framebufferDevice) +#endif + static qreal rate = 0; #ifdef Q_OS_LINUX diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp index 36de1e0c69..c7f6dd2740 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp @@ -60,7 +60,7 @@ Q_LOGGING_CATEGORY(qLcEvdevKeyMap, "qt.qpa.input.keymap") #include "qevdevkeyboard_defaultmap_p.h" QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, int fd, bool disableZap, bool enableCompose, const QString &keymapFile) - : m_device(device), m_fd(fd), + : m_device(device), m_fd(fd), m_notify(Q_NULLPTR), m_modifiers(0), m_composing(0), m_dead_unicode(0xffff), m_no_zap(disableZap), m_do_compose(enableCompose), m_keymap(0), m_keymap_size(0), m_keycompose(0), m_keycompose_size(0) @@ -75,9 +75,8 @@ QEvdevKeyboardHandler::QEvdevKeyboardHandler(const QString &device, int fd, bool unloadKeymap(); // socket notifier for events on the keyboard device - QSocketNotifier *notifier; - notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), this, SLOT(readKeycode())); + m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(m_notify, SIGNAL(activated(int)), this, SLOT(readKeycode())); } QEvdevKeyboardHandler::~QEvdevKeyboardHandler() @@ -162,6 +161,14 @@ void QEvdevKeyboardHandler::readKeycode() } else if (result < 0) { if (errno != EINTR && errno != EAGAIN) { qErrnoWarning(errno, "evdevkeyboard: Could not read from input device"); + // If the device got disconnected, stop reading, otherwise we get flooded + // by the above error over and over again. + if (errno == ENODEV) { + delete m_notify; + m_notify = Q_NULLPTR; + qt_safe_close(m_fd); + m_fd = -1; + } return; } } else { diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h index 89fa879115..b94323fcbb 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler_p.h @@ -57,6 +57,8 @@ QT_BEGIN_NAMESPACE +class QSocketNotifier; + namespace QEvdevKeyboardMap { const quint32 FileMagic = 0x514d4150; // 'QMAP' @@ -186,6 +188,7 @@ private: QString m_device; int m_fd; + QSocketNotifier *m_notify; // keymap handling quint8 m_modifiers; diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index 382b9b1514..d5ea04bee8 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -111,9 +111,8 @@ QEvdevMouseHandler::QEvdevMouseHandler(const QString &device, int fd, bool abs, m_abs = getHardwareMaximum(); // socket notifier for events on the mouse device - QSocketNotifier *notifier; - notifier = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); - connect(notifier, SIGNAL(activated(int)), this, SLOT(readMouseData())); + m_notify = new QSocketNotifier(m_fd, QSocketNotifier::Read, this); + connect(m_notify, SIGNAL(activated(int)), this, SLOT(readMouseData())); } QEvdevMouseHandler::~QEvdevMouseHandler() @@ -202,6 +201,14 @@ void QEvdevMouseHandler::readMouseData() } else if (result < 0) { if (errno != EINTR && errno != EAGAIN) { qErrnoWarning(errno, "evdevmouse: Could not read from input device"); + // If the device got disconnected, stop reading, otherwise we get flooded + // by the above error over and over again. + if (errno == ENODEV) { + delete m_notify; + m_notify = Q_NULLPTR; + qt_safe_close(m_fd); + m_fd = -1; + } return; } } else { diff --git a/src/platformsupport/platformsupport.pro b/src/platformsupport/platformsupport.pro index 8fb05be3fa..9f6f3380e1 100644 --- a/src/platformsupport/platformsupport.pro +++ b/src/platformsupport/platformsupport.pro @@ -21,7 +21,11 @@ include(accessibility/accessibility.pri) include(linuxaccessibility/linuxaccessibility.pri) include(clipboard/clipboard.pri) include(platformcompositor/platformcompositor.pri) -contains(QT_CONFIG, dbus) { + +# dbus convenience, but not for darwin: the platform +# plugins for these platforms do not use dbus and we +# don't want to create a false dependency. +!darwin: contains(QT_CONFIG, dbus) { include(dbusmenu/dbusmenu.pri) include(dbustray/dbustray.pri) } diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 004ed04cab..c9c7ff6c2c 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -153,7 +153,7 @@ static bool isMouseEvent(NSEvent *ev) if (NSMouseInRect(loc, windowFrame, NO) && !NSMouseInRect(loc, contentFrame, NO)) { - QNSView *contentView = (QNSView *)pw->contentView(); + QNSView *contentView = pw->m_qtView; [contentView handleFrameStrutMouseEvent: theEvent]; } } @@ -1188,7 +1188,11 @@ NSView *QCocoaWindow::contentView() const void QCocoaWindow::setContentView(NSView *contentView) { // Remove and release the previous content view - [m_contentView removeFromSuperview]; + if (m_nsWindow) + [m_nsWindow setContentView:nil]; + else + [m_contentView removeFromSuperview]; + [m_contentView release]; // Insert and retain the new content view diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index ffc3dec814..7834c2991d 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -632,7 +632,9 @@ static bool _q_dontOverrideCtrlLMB = false; - (BOOL)becomeFirstResponder { - if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) ) + if (!m_window || !m_platformWindow) + return NO; + if (m_window->flags() & Qt::WindowTransparentForInput) return NO; if (!m_platformWindow->windowIsPopupType() && !m_isMenuView) QWindowSystemInterface::handleWindowActivated([self topLevelWindow]); @@ -641,11 +643,13 @@ static bool _q_dontOverrideCtrlLMB = false; - (BOOL)acceptsFirstResponder { + if (!m_window || !m_platformWindow) + return NO; if (m_isMenuView) return NO; if (m_platformWindow->shouldRefuseKeyWindowAndFirstResponder()) return NO; - if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) ) + if (m_window->flags() & Qt::WindowTransparentForInput) return NO; if ((m_window->flags() & Qt::ToolTip) == Qt::ToolTip) return NO; @@ -655,7 +659,9 @@ static bool _q_dontOverrideCtrlLMB = false; - (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { Q_UNUSED(theEvent) - if (m_window && (m_window->flags() & Qt::WindowTransparentForInput) ) + if (!m_window || !m_platformWindow) + return NO; + if (m_window->flags() & Qt::WindowTransparentForInput) return NO; return YES; } @@ -2162,7 +2168,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin // keep our state, and QGuiApplication state (buttons member) in-sync, // or future mouse events will be processed incorrectly - m_buttons &= ~(m_sendUpAsRightButton ? Qt::RightButton : Qt::LeftButton); + NSUInteger pmb = [NSEvent pressedMouseButtons]; + for (int buttonNumber = 0; buttonNumber < 32; buttonNumber++) { // see cocoaButton2QtButton() for the 32 value + if (!(pmb & (1 << buttonNumber))) + m_buttons &= ~cocoaButton2QtButton(buttonNumber); + } NSPoint windowPoint = [self convertPoint: point fromView: nil]; QPoint qtWindowPoint(windowPoint.x, windowPoint.y); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp index abff88b4bd..5b779d6732 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_kms/qeglfskmsgbmcursor.cpp @@ -132,7 +132,7 @@ void QEglFSKmsGbmCursor::updateMouseStatus() m_state = visible ? CursorPendingVisible : CursorPendingHidden; #ifndef QT_NO_CURSOR - changeCursor(nullptr, m_screen->topLevelAt(pos())); + changeCursor(Q_NULLPTR, m_screen->topLevelAt(pos())); #endif } diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h index 82bcf48855..2b0643f26e 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.h +++ b/src/plugins/platforms/ios/qiosinputcontext.h @@ -42,6 +42,7 @@ #include <UIKit/UIKit.h> +#include <QtCore/qlocale.h> #include <QtGui/qevent.h> #include <QtGui/qtransform.h> #include <qpa/qplatforminputcontext.h> @@ -52,6 +53,7 @@ const char kImePlatformDataReturnKeyType[] = "returnKeyType"; QT_BEGIN_NAMESPACE +@class QIOSLocaleListener; @class QIOSKeyboardListener; @class QIOSTextInputResponder; @protocol KeyboardState; @@ -98,6 +100,8 @@ public: void reset() Q_DECL_OVERRIDE; void commit() Q_DECL_OVERRIDE; + QLocale locale() const Q_DECL_OVERRIDE; + void clearCurrentFocusObject(); void setFocusObject(QObject *object) Q_DECL_OVERRIDE; @@ -118,6 +122,7 @@ public: private: UIView* scrollableRootView(); + QIOSLocaleListener *m_localeListener; QIOSKeyboardListener *m_keyboardHideGesture; QIOSTextInputResponder *m_textResponder; KeyboardState m_keyboardState; diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm index a1c51b6968..c6cbb9b101 100644 --- a/src/plugins/platforms/ios/qiosinputcontext.mm +++ b/src/plugins/platforms/ios/qiosinputcontext.mm @@ -62,6 +62,39 @@ static QUIView *focusView() // ------------------------------------------------------------------------- +@interface QIOSLocaleListener : NSObject +@end + +@implementation QIOSLocaleListener + +- (id)init +{ + if (self = [super init]) { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(localeDidChange:) + name:NSCurrentLocaleDidChangeNotification object:nil]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (void)localeDidChange:(NSNotification *)notification +{ + Q_UNUSED(notification); + QIOSInputContext::instance()->emitLocaleChanged(); +} + +@end + +// ------------------------------------------------------------------------- + @interface QIOSKeyboardListener : UIGestureRecognizer <UIGestureRecognizerDelegate> { @private QIOSInputContext *m_context; @@ -293,6 +326,7 @@ QIOSInputContext *QIOSInputContext::instance() QIOSInputContext::QIOSInputContext() : QPlatformInputContext() + , m_localeListener([QIOSLocaleListener new]) , m_keyboardHideGesture([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this]) , m_textResponder(0) { @@ -306,6 +340,7 @@ QIOSInputContext::QIOSInputContext() QIOSInputContext::~QIOSInputContext() { + [m_localeListener release]; [m_keyboardHideGesture.view removeGestureRecognizer:m_keyboardHideGesture]; [m_keyboardHideGesture release]; @@ -673,3 +708,8 @@ void QIOSInputContext::commit() [m_textResponder unmarkText]; [m_textResponder notifyInputDelegate:Qt::ImSurroundingText]; } + +QLocale QIOSInputContext::locale() const +{ + return QLocale(QString::fromNSString([[NSLocale currentLocale] objectForKey:NSLocaleIdentifier])); +} diff --git a/src/plugins/platforms/ios/qiostextinputoverlay.mm b/src/plugins/platforms/ios/qiostextinputoverlay.mm index 655e457664..94d82c3eb9 100644 --- a/src/plugins/platforms/ios/qiostextinputoverlay.mm +++ b/src/plugins/platforms/ios/qiostextinputoverlay.mm @@ -45,6 +45,7 @@ #include "qiostextinputoverlay.h" typedef QPair<int, int> SelectionPair; +typedef void (^Block)(void); static const CGFloat kKnobWidth = 10; @@ -68,7 +69,7 @@ static bool hasSelection() return selection.first != selection.second; } -static void executeBlockWithoutAnimation(void (^block)(void)) +static void executeBlockWithoutAnimation(Block block) { [CATransaction begin]; [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions]; @@ -306,6 +307,7 @@ static void executeBlockWithoutAnimation(void (^block)(void)) @property (nonatomic, assign) CGRect cursorRectangle; @property (nonatomic, assign) CGFloat handleScale; @property (nonatomic, assign) BOOL visible; +@property (nonatomic, copy) Block onAnimationDidStop; @end @implementation QIOSHandleLayer @@ -359,7 +361,8 @@ static void executeBlockWithoutAnimation(void (^block)(void)) [NSNumber numberWithFloat:1], nil]; return animation; } else { - CABasicAnimation * animation = [CABasicAnimation animationWithKeyPath:key]; + CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key]; + [animation setDelegate:self]; animation.fromValue = [self valueForKey:key]; [animation setDuration:0.2]; return animation; @@ -368,6 +371,14 @@ static void executeBlockWithoutAnimation(void (^block)(void)) return [super actionForKey:key]; } +- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag +{ + Q_UNUSED(animation); + Q_UNUSED(flag); + if (self.onAnimationDidStop) + self.onAnimationDidStop(); +} + - (void)setVisible:(BOOL)visible { if (visible == _visible) @@ -679,7 +690,7 @@ static void executeBlockWithoutAnimation(void (^block)(void)) if (enabled) { // Create a layer that clips the handles inside the input field - _clipRectLayer = [[CALayer new] autorelease]; + _clipRectLayer = [CALayer new]; _clipRectLayer.masksToBounds = YES; [self.focusView.layer addSublayer:_clipRectLayer]; @@ -705,7 +716,26 @@ static void executeBlockWithoutAnimation(void (^block)(void)) [self updateSelection]; } else { - [_clipRectLayer removeFromSuperlayer]; + // Fade out the handles by setting visible to NO, and wait for the animations + // to finish before removing the clip rect layer, including the handles. + // Create a local variable to hold the clipRectLayer while the animation is + // ongoing to ensure that any subsequent calls to setEnabled does not interfere. + // Also, declare it as __block to stop it from being automatically retained, which + // would cause a cyclic dependency between clipRectLayer and the block. + __block CALayer *clipRectLayer = _clipRectLayer; + __block int handleCount = 2; + Block block = ^{ + if (--handleCount == 0) { + [clipRectLayer removeFromSuperlayer]; + [clipRectLayer release]; + } + }; + + _cursorLayer.onAnimationDidStop = block; + _anchorLayer.onAnimationDidStop = block; + _cursorLayer.visible = NO; + _anchorLayer.visible = NO; + _clipRectLayer = 0; _cursorLayer = 0; _anchorLayer = 0; diff --git a/src/plugins/platforms/ios/qiostextresponder.mm b/src/plugins/platforms/ios/qiostextresponder.mm index 031cd90828..5ec05ec8ce 100644 --- a/src/plugins/platforms/ios/qiostextresponder.mm +++ b/src/plugins/platforms/ios/qiostextresponder.mm @@ -359,6 +359,7 @@ - (void)sendKeyPressRelease:(Qt::Key)key modifiers:(Qt::KeyboardModifiers)modifiers { + QScopedValueRollback<BOOL> rollback(m_inSendEventToFocusObject, true); QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyPress, key, modifiers); QWindowSystemInterface::handleKeyEvent(qApp->focusWindow(), QEvent::KeyRelease, key, modifiers); QWindowSystemInterface::flushWindowSystemEvents(); diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm index 643192797a..c8c07bd298 100644 --- a/src/plugins/platforms/ios/qiosviewcontroller.mm +++ b/src/plugins/platforms/ios/qiosviewcontroller.mm @@ -310,17 +310,16 @@ - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration { - Q_UNUSED(orientation); - Q_UNUSED(duration); - self.changingOrientation = YES; + + [super willRotateToInterfaceOrientation:orientation duration:duration]; } - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)orientation { - Q_UNUSED(orientation); - self.changingOrientation = NO; + + [super didRotateFromInterfaceOrientation:orientation]; } - (void)willChangeStatusBarFrame:(NSNotification*)notification diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro index 0d31d6605b..bd6f2d8e6f 100644 --- a/src/plugins/platforms/minimal/minimal.pro +++ b/src/plugins/platforms/minimal/minimal.pro @@ -11,6 +11,7 @@ HEADERS = qminimalintegration.h \ OTHER_FILES += minimal.json CONFIG += qpa/genericunixfontdatabase +darwin: DEFINES += QT_NO_FONTCONFIG PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro index b447cf9b81..454d7f43bd 100644 --- a/src/plugins/platforms/platforms.pro +++ b/src/plugins/platforms/platforms.pro @@ -2,9 +2,9 @@ TEMPLATE = subdirs android: SUBDIRS += android -SUBDIRS += minimal +!android: SUBDIRS += minimal -!win32|contains(QT_CONFIG, freetype):SUBDIRS += offscreen +!android:if(!win32|contains(QT_CONFIG, freetype)): SUBDIRS += offscreen contains(QT_CONFIG, xcb) { SUBDIRS += xcb diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 23a6f35576..6124b004b6 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -201,26 +201,9 @@ QWindowsEGLStaticContext::QWindowsEGLStaticContext(EGLDisplay display) { } -QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester::Renderers preferredType) +bool QWindowsEGLStaticContext::initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc, + EGLDisplay *display, EGLint *major, EGLint *minor) { - const HDC dc = QWindowsContext::instance()->displayContext(); - if (!dc){ - qWarning("%s: No Display", __FUNCTION__); - return 0; - } - - if (!libEGL.init()) { - qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__); - return 0; - } - if (!libGLESv2.init()) { - qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__); - return 0; - } - - EGLDisplay display = EGL_NO_DISPLAY; - EGLint major = 0; - EGLint minor = 0; #ifdef EGL_ANGLE_platform_angle if (libEGL.eglGetPlatformDisplayEXT && (preferredType & QWindowsOpenGLTester::AngleBackendMask)) { @@ -238,16 +221,52 @@ QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester: else if (preferredType & QWindowsOpenGLTester::AngleRendererD3d11Warp) attributes = anglePlatformAttributes[2]; if (attributes) { - display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes); - if (!libEGL.eglInitialize(display, &major, &minor)) { - display = EGL_NO_DISPLAY; - major = minor = 0; + *display = libEGL.eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, dc, attributes); + if (!libEGL.eglInitialize(*display, major, minor)) { + libEGL.eglTerminate(*display); + *display = EGL_NO_DISPLAY; + *major = *minor = 0; + return false; } } } #else // EGL_ANGLE_platform_angle - Q_UNUSED(preferredType) + Q_UNUSED(preferredType); + Q_UNUSED(dc); + Q_UNUSED(display); + Q_UNUSED(major); + Q_UNUSED(minor); #endif + return true; +} + +QWindowsEGLStaticContext *QWindowsEGLStaticContext::create(QWindowsOpenGLTester::Renderers preferredType) +{ + const HDC dc = QWindowsContext::instance()->displayContext(); + if (!dc){ + qWarning("%s: No Display", __FUNCTION__); + return 0; + } + + if (!libEGL.init()) { + qWarning("%s: Failed to load and resolve libEGL functions", __FUNCTION__); + return 0; + } + if (!libGLESv2.init()) { + qWarning("%s: Failed to load and resolve libGLESv2 functions", __FUNCTION__); + return 0; + } + + EGLDisplay display = EGL_NO_DISPLAY; + EGLint major = 0; + EGLint minor = 0; + + if (!initializeAngle(preferredType, dc, &display, &major, &minor) + && (preferredType & QWindowsOpenGLTester::AngleRendererD3d11)) { + preferredType &= ~QWindowsOpenGLTester::AngleRendererD3d11; + initializeAngle(preferredType, dc, &display, &major, &minor); + } + if (display == EGL_NO_DISPLAY) display = libEGL.eglGetDisplay(dc); if (!display) { diff --git a/src/plugins/platforms/windows/qwindowseglcontext.h b/src/plugins/platforms/windows/qwindowseglcontext.h index c7f7cee3c2..48a19f81e5 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.h +++ b/src/plugins/platforms/windows/qwindowseglcontext.h @@ -131,6 +131,8 @@ public: private: explicit QWindowsEGLStaticContext(EGLDisplay display); + static bool initializeAngle(QWindowsOpenGLTester::Renderers preferredType, HDC dc, + EGLDisplay *display, EGLint *major, EGLint *minor); const EGLDisplay m_display; }; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 0f49c66462..744d882bb2 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -1236,8 +1236,7 @@ QFontEngine *QWindowsMultiFontEngine::loadEngine(int at) QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, fontEngine->fontDef.pixelSize, data); - if (fontEngine->fontDef.weight > QFont::Normal) - fedw->fontDef.weight = fontEngine->fontDef.weight; + fedw->fontDef.weight = fontEngine->fontDef.weight; if (fontEngine->fontDef.style > QFont::StyleNormal) fedw->fontDef.style = fontEngine->fontDef.style; fedw->fontDef.family = fam; @@ -1254,8 +1253,7 @@ QFontEngine *QWindowsMultiFontEngine::loadEngine(int at) // reason QFontEngine *fe = new QWindowsFontEngine(fam, lf, data); - if (fontEngine->fontDef.weight > QFont::Normal) - fe->fontDef.weight = fontEngine->fontDef.weight; + fe->fontDef.weight = fontEngine->fontDef.weight; if (fontEngine->fontDef.style > QFont::StyleNormal) fe->fontDef.style = fontEngine->fontDef.style; fe->fontDef.family = fam; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 6e324ce0ed..5b8cc7893a 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -322,7 +322,9 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons if (customMarginsV.isValid()) requested.customMargins = qvariant_cast<QMargins>(customMarginsV); - QWindowsWindowData obtained = QWindowsWindowData::create(window, requested, window->title()); + QWindowsWindowData obtained = + QWindowsWindowData::create(window, requested, + QWindowsWindow::formatWindowTitle(window->title())); qCDebug(lcQpaWindows).nospace() << __FUNCTION__ << ' ' << window << "\n Requested: " << requested.geometry << " frame incl.=" diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index a9307f79fb..6c6eb42d63 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -132,7 +132,16 @@ public: explicit ShGetFileInfoFunction(const wchar_t *fn, DWORD a, SHFILEINFO *i, UINT f, bool *r) : m_fileName(fn), m_attributes(a), m_flags(f), m_info(i), m_result(r) {} - void operator()() const { *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags); } + void operator()() const + { +#ifndef Q_OS_WINCE + const UINT oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); +#endif + *m_result = SHGetFileInfo(m_fileName, m_attributes, m_info, sizeof(SHFILEINFO), m_flags); +#ifndef Q_OS_WINCE + SetErrorMode(oldErrorMode); +#endif + } private: const wchar_t *m_fileName; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index f54c100f25..3a6e6840fd 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1579,11 +1579,12 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, return false; PAINTSTRUCT ps; + BeginPaint(hwnd, &ps); + // Observed painting problems with Aero style disabled (QTBUG-7865). + // 5.8: Consider making it dependent on !DwmIsCompositionEnabled(). if (testFlag(OpenGLSurface) && testFlag(OpenGLDoubleBuffered)) - InvalidateRect(hwnd, 0, false); - - BeginPaint(hwnd, &ps); + SelectClipRgn(ps.hdc, NULL); // If the a window is obscured by another window (such as a child window) // we still need to send isExposed=true, for compatibility. @@ -1598,7 +1599,7 @@ bool QWindowsWindow::handleWmPaint(HWND hwnd, UINT message, void QWindowsWindow::setWindowTitle(const QString &title) { - setWindowTitle_sys(QWindowsWindow::formatWindowTitle(title, QStringLiteral(" - "))); + setWindowTitle_sys(QWindowsWindow::formatWindowTitle(title)); } void QWindowsWindow::setWindowFlags(Qt::WindowFlags flags) @@ -2402,4 +2403,9 @@ void QWindowsWindow::setHasBorderInFullScreen(bool border) clearFlag(HasBorderInFullScreen); } +QString QWindowsWindow::formatWindowTitle(const QString &title) +{ + return QPlatformWindow::formatWindowTitle(title, QStringLiteral(" - ")); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 3736778095..924f242e6e 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -316,6 +316,8 @@ public: void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch); static void setHasBorderInFullScreenStatic(QWindow *window, bool border); void setHasBorderInFullScreen(bool border); + static QString formatWindowTitle(const QString &title); + private: inline void show_sys() const; inline QWindowsWindowData setWindowFlags_sys(Qt::WindowFlags wt, unsigned flags = 0) const; diff --git a/src/plugins/platforms/winrt/qwinrtdrag.cpp b/src/plugins/platforms/winrt/qwinrtdrag.cpp new file mode 100644 index 0000000000..2ef50aa4e2 --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtdrag.cpp @@ -0,0 +1,893 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qwinrtdrag.h" + +#include <QtCore/qglobal.h> +#include <QtCore/QMimeData> +#include <QtCore/QStringList> +#include <QtGui/QGuiApplication> +#include <qpa/qwindowsysteminterface.h> + +#include <qfunctions_winrt.h> +#include <private/qeventdispatcher_winrt_p.h> + +#include <Windows.ApplicationModel.datatransfer.h> +#include <windows.ui.xaml.h> +#include <windows.foundation.collections.h> +#include <windows.graphics.imaging.h> +#include <windows.storage.streams.h> +#include <functional> +#include <robuffer.h> + +using namespace ABI::Windows::ApplicationModel::DataTransfer; +using namespace ABI::Windows::ApplicationModel::DataTransfer::DragDrop; +using namespace ABI::Windows::Foundation; +using namespace ABI::Windows::Foundation::Collections; +using namespace ABI::Windows::Graphics::Imaging; +using namespace ABI::Windows::Storage; +using namespace ABI::Windows::Storage::Streams; +using namespace ABI::Windows::UI::Xaml; +using namespace Microsoft::WRL; +using namespace Microsoft::WRL::Wrappers; + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcQpaMime, "qt.qpa.mime") + +ComPtr<IBuffer> createIBufferFromData(const char *data, qint32 size) +{ + static ComPtr<IBufferFactory> bufferFactory; + HRESULT hr; + if (!bufferFactory) { + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + IID_PPV_ARGS(&bufferFactory)); + Q_ASSERT_SUCCEEDED(hr); + } + + ComPtr<IBuffer> buffer; + const UINT32 length = size; + hr = bufferFactory->Create(length, &buffer); + Q_ASSERT_SUCCEEDED(hr); + hr = buffer->put_Length(length); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess; + hr = buffer.As(&byteArrayAccess); + Q_ASSERT_SUCCEEDED(hr); + + byte *bytes; + hr = byteArrayAccess->Buffer(&bytes); + Q_ASSERT_SUCCEEDED(hr); + memcpy(bytes, data, length); + return buffer; +} + +class DragThreadTransferData : public QObject +{ + Q_OBJECT +public slots: + void handleDrag(); +public: + explicit DragThreadTransferData(QObject *parent = Q_NULLPTR); + QWindow *window; + QWinRTInternalMimeData *mime; + QPoint point; + Qt::DropActions actions; + bool dropAction; + ComPtr<IDragEventArgs> nativeArgs; + ComPtr<IDragOperationDeferral> deferral; +}; + +inline QString hStringToQString(const HString &hString) +{ + quint32 l; + const wchar_t *raw = hString.GetRawBuffer(&l); + return (QString::fromWCharArray(raw, l)); +} + +inline HString qStringToHString(const QString &qString) +{ + HString h; + h.Set(reinterpret_cast<const wchar_t*>(qString.utf16()), qString.size()); + return h; +} + +namespace NativeFormatStrings { + static ComPtr<IStandardDataFormatsStatics> dataStatics; + static HSTRING text; // text/plain + static HSTRING html; // text/html + static HSTRING storage; // text/uri-list +} + +static inline DataPackageOperation translateFromQDragDropActions(const Qt::DropAction action) +{ + switch (action) { + case Qt::CopyAction: + return DataPackageOperation_Copy; + case Qt::MoveAction: + return DataPackageOperation_Move; + case Qt::LinkAction: + return DataPackageOperation_Link; + case Qt::IgnoreAction: + default: + return DataPackageOperation_None; + } +} + +static inline Qt::DropActions translateToQDragDropActions(const DataPackageOperation op) +{ + Qt::DropActions actions = Qt::IgnoreAction; + // None needs to be interpreted as the sender being able to handle + // anything and let the receiver decide + if (op == DataPackageOperation_None) + actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction; + if (op & DataPackageOperation_Link) + actions |= Qt::LinkAction; + if (op & DataPackageOperation_Copy) + actions |= Qt::CopyAction; + if (op & DataPackageOperation_Move) + actions |= Qt::MoveAction; + return actions; +} + +QWinRTInternalMimeData::QWinRTInternalMimeData() + : QInternalMimeData() +{ + qCDebug(lcQpaMime) << __FUNCTION__; + if (!NativeFormatStrings::dataStatics) { + HRESULT hr; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_DataTransfer_StandardDataFormats).Get(), + IID_PPV_ARGS(&NativeFormatStrings::dataStatics)); + Q_ASSERT_SUCCEEDED(hr); + hr = NativeFormatStrings::dataStatics->get_Text(&NativeFormatStrings::text); + Q_ASSERT_SUCCEEDED(hr); + hr = NativeFormatStrings::dataStatics->get_Html(&NativeFormatStrings::html); + Q_ASSERT_SUCCEEDED(hr); + hr = NativeFormatStrings::dataStatics->get_StorageItems(&NativeFormatStrings::storage); + Q_ASSERT_SUCCEEDED(hr); + } +} + +QWinRTInternalMimeData::~QWinRTInternalMimeData() +{ +} + +bool QWinRTInternalMimeData::hasFormat_sys(const QString &mimetype) const +{ + qCDebug(lcQpaMime) << __FUNCTION__ << mimetype; + + if (!dataView) + return false; + + return formats_sys().contains(mimetype); +} + +QStringList QWinRTInternalMimeData::formats_sys() const +{ + qCDebug(lcQpaMime) << __FUNCTION__; + + if (!dataView) + return QStringList(); + + if (!formats.isEmpty()) + return formats; + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([this]() { + boolean contains; + HRESULT hr; + hr = dataView->Contains(NativeFormatStrings::text, &contains); + if (SUCCEEDED(hr) && contains) + formats.append(QLatin1String("text/plain")); + + hr = dataView->Contains(NativeFormatStrings::html, &contains); + if (SUCCEEDED(hr) && contains) + formats.append(QLatin1String("text/html")); + + hr = dataView->Contains(NativeFormatStrings::storage, &contains); + if (SUCCEEDED(hr) && contains) + formats.append(QLatin1String("text/uri-list")); + + // We need to add any additional format as well, for legacy windows + // reasons, but also in case someone adds custom formats. + ComPtr<IVectorView<HSTRING>> availableFormats; + hr = dataView->get_AvailableFormats(&availableFormats); + RETURN_OK_IF_FAILED("Could not query available formats."); + + quint32 size; + hr = availableFormats->get_Size(&size); + RETURN_OK_IF_FAILED("Could not query format vector size."); + for (quint32 i = 0; i < size; ++i) { + HString str; + hr = availableFormats->GetAt(i, str.GetAddressOf()); + if (FAILED(hr)) + continue; + formats.append(hStringToQString(str)); + } + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + + return formats; +} + +QVariant QWinRTInternalMimeData::retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const +{ + qCDebug(lcQpaMime) << __FUNCTION__ << mimetype << preferredType; + + if (!dataView || !formats.contains(mimetype)) + return QVariant(); + + QVariant result; + HRESULT hr; + if (mimetype == QLatin1String("text/plain")) { + hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() { + HRESULT hr; + ComPtr<IAsyncOperation<HSTRING>> op; + HString res; + hr = dataView->GetTextAsync(&op); + Q_ASSERT_SUCCEEDED(hr); + hr = QWinRTFunctions::await(op, res.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(hStringToQString(res)); + return S_OK; + }); + } else if (mimetype == QLatin1String("text/uri-list")) { + hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() { + HRESULT hr; + ComPtr<IAsyncOperation<IVectorView<IStorageItem*>*>> op; + hr = dataView->GetStorageItemsAsync(&op); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IVectorView<IStorageItem*>> nativeItems; + hr = QWinRTFunctions::await(op, nativeItems.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + QList<QVariant> items; + quint32 count; + hr = nativeItems->get_Size(&count); + for (quint32 i = 0; i < count; ++i) { + ComPtr<IStorageItem> item; + hr = nativeItems->GetAt(i, &item); + Q_ASSERT_SUCCEEDED(hr); + HString path; + hr = item->get_Path(path.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + items.append(QUrl::fromLocalFile(hStringToQString(path))); + } + result.setValue(items); + return S_OK; + }); + } else if (mimetype == QLatin1String("text/html")) { + hr = QEventDispatcherWinRT::runOnXamlThread([this, &result]() { + HRESULT hr; + ComPtr<IAsyncOperation<HSTRING>> op; + HString res; + hr = dataView->GetHtmlFormatAsync(&op); + Q_ASSERT_SUCCEEDED(hr); + hr = QWinRTFunctions::await(op, res.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(hStringToQString(res)); + return S_OK; + }); + } else { + // Asking for custom data + hr = QEventDispatcherWinRT::runOnXamlThread([this, &result, mimetype]() { + HRESULT hr; + ComPtr<IAsyncOperation<IInspectable*>> op; + ComPtr<IInspectable> res; + HString type; + type.Set(reinterpret_cast<const wchar_t*>(mimetype.utf16()), mimetype.size()); + hr = dataView->GetDataAsync(type.Get(), &op); + RETURN_OK_IF_FAILED("Could not query custom drag data."); + hr = QWinRTFunctions::await(op, res.GetAddressOf()); + if (FAILED(hr) || !res) { + qCDebug(lcQpaMime) << "Custom drop data operation returned no results or failed."; + return S_OK; + } + + // Test for properties + ComPtr<IPropertyValue> propertyValue; + hr = res.As(&propertyValue); + if (SUCCEEDED(hr)) { + // We need to check which type of custom data we are receiving + PropertyType type; + propertyValue->get_Type(&type); + switch (type) { + case PropertyType_UInt8: { + quint8 v; + hr = propertyValue->GetUInt8(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_Int16: { + qint16 v; + hr = propertyValue->GetInt16(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_UInt16: { + quint16 v; + hr = propertyValue->GetUInt16(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_Int32: { + qint32 v; + hr = propertyValue->GetInt32(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_UInt32: { + quint32 v; + hr = propertyValue->GetUInt32(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_Int64: { + qint64 v; + hr = propertyValue->GetInt64(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_UInt64: { + quint64 v; + hr = propertyValue->GetUInt64(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_Single: { + float v; + hr = propertyValue->GetSingle(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_Double: { + double v; + hr = propertyValue->GetDouble(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_Char16: { + wchar_t v; + hr = propertyValue->GetChar16(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(QString::fromWCharArray(&v, 1)); + return S_OK; + } + case PropertyType_Boolean: { + boolean v; + hr = propertyValue->GetBoolean(&v); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(v); + return S_OK; + } + case PropertyType_String: { + HString stringProperty; + hr = propertyValue->GetString(stringProperty.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + result.setValue(hStringToQString(stringProperty)); + return S_OK; + } + default: + qCDebug(lcQpaMime) << "Unknown property type dropped:" << type; + } + return S_OK; + } + + // Custom data can be read via input streams + ComPtr<IRandomAccessStream> randomAccessStream; + hr = res.As(&randomAccessStream); + if (SUCCEEDED(hr)) { + UINT64 size; + hr = randomAccessStream->get_Size(&size); + Q_ASSERT_SUCCEEDED(hr); + ComPtr<IInputStream> stream; + hr = randomAccessStream.As(&stream); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IBufferFactory> bufferFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_Buffer).Get(), + IID_PPV_ARGS(&bufferFactory)); + Q_ASSERT_SUCCEEDED(hr); + + UINT32 length = qBound(quint64(0), quint64(size), quint64(UINT_MAX)); + ComPtr<IBuffer> buffer; + hr = bufferFactory->Create(length, &buffer); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IAsyncOperationWithProgress<IBuffer *, UINT32>> readOp; + hr = stream->ReadAsync(buffer.Get(), length, InputStreamOptions_None, &readOp); + + ComPtr<IBuffer> effectiveBuffer; + hr = QWinRTFunctions::await(readOp, effectiveBuffer.GetAddressOf()); + + hr = effectiveBuffer->get_Length(&length); + + ComPtr<Windows::Storage::Streams::IBufferByteAccess> byteArrayAccess; + hr = effectiveBuffer.As(&byteArrayAccess); + + byte *bytes; + hr = byteArrayAccess->Buffer(&bytes); + QByteArray array((char *)bytes, length); + result.setValue(array); + return S_OK; + } + + HSTRING runtimeClass; + hr = res->GetRuntimeClassName(&runtimeClass); + Q_ASSERT_SUCCEEDED(hr); + HString converted; + converted.Set(runtimeClass); + qCDebug(lcQpaMime) << "Unknown drop data type received (" << hStringToQString(converted) + << "). Ignoring..."; + return S_OK; + }); + } + return result; +} + +void QWinRTInternalMimeData::setDataView(const Microsoft::WRL::ComPtr<IDataPackageView> &d) +{ + dataView = d; + formats.clear(); +} + +static HRESULT qt_drag_enter(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e) +{ + QWinRTDrag::instance()->handleNativeDragEvent(sender, e); + return S_OK; +} + +static HRESULT qt_drag_over(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e) +{ + QWinRTDrag::instance()->handleNativeDragEvent(sender, e); + return S_OK; +} + +static HRESULT qt_drag_leave(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e) +{ + // Qt internally checks for new drags and auto sends leave events + // Also there is no QPA function for handling leave + Q_UNUSED(sender); + Q_UNUSED(e); + return S_OK; +} + +static HRESULT qt_drop(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e) +{ + QWinRTDrag::instance()->handleNativeDragEvent(sender, e, true); + return S_OK; +} + +#define Q_DECLARE_DRAGHANDLER(name,func) \ +class QtDragEventHandler##name : public IDragEventHandler \ +{ \ +public: \ + virtual HRESULT STDMETHODCALLTYPE Invoke(IInspectable *sender, \ + ABI::Windows::UI::Xaml::IDragEventArgs *e) \ + { \ + return qt_##func(sender, e);\ + } \ + \ + STDMETHODIMP \ + QueryInterface(REFIID riid, void FAR* FAR* ppvObj) \ + { \ + if (riid == IID_IUnknown || riid == IID_IDragEventHandler) { \ + *ppvObj = this; \ + AddRef(); \ + return NOERROR; \ + } \ + *ppvObj = NULL; \ + return ResultFromScode(E_NOINTERFACE); \ + } \ + \ + STDMETHODIMP_(ULONG) \ + AddRef(void) \ + { \ + return ++m_refs; \ + } \ + \ + STDMETHODIMP_(ULONG) \ + Release(void) \ + { \ + if (--m_refs == 0) { \ + delete this; \ + return 0; \ + } \ + return m_refs; \ + } \ +private: \ +ULONG m_refs{0}; \ +}; + +Q_DECLARE_DRAGHANDLER(Enter, drag_enter) +Q_DECLARE_DRAGHANDLER(Over, drag_over) +Q_DECLARE_DRAGHANDLER(Leave, drag_leave) +Q_DECLARE_DRAGHANDLER(Drop, drop) + +#define Q_INST_DRAGHANDLER(name) QtDragEventHandler##name() + +Q_GLOBAL_STATIC(QWinRTDrag, gDrag); + +extern ComPtr<ABI::Windows::UI::Input::IPointerPoint> qt_winrt_lastPointerPoint; // qwinrtscreen.cpp + +QWinRTDrag::QWinRTDrag() + : QPlatformDrag() + , m_dragTarget(0) +{ + qCDebug(lcQpaMime) << __FUNCTION__; + m_enter = new Q_INST_DRAGHANDLER(Enter); + m_over = new Q_INST_DRAGHANDLER(Over); + m_leave = new Q_INST_DRAGHANDLER(Leave); + m_drop = new Q_INST_DRAGHANDLER(Drop); + m_mimeData = new QWinRTInternalMimeData; +} + +QWinRTDrag::~QWinRTDrag() +{ + qCDebug(lcQpaMime) << __FUNCTION__; + delete m_enter; + delete m_over; + delete m_leave; + delete m_drop; + delete m_mimeData; +} + +QWinRTDrag *QWinRTDrag::instance() +{ + return gDrag; +} + +inline HRESULT resetUiElementDrag(ComPtr<IUIElement3> &elem3, EventRegistrationToken startingToken) +{ + return QEventDispatcherWinRT::runOnXamlThread([elem3, startingToken]() { + HRESULT hr; + hr = elem3->put_CanDrag(false); + Q_ASSERT_SUCCEEDED(hr); + hr = elem3->remove_DragStarting(startingToken); + Q_ASSERT_SUCCEEDED(hr); + return S_OK; + }); +} + +Qt::DropAction QWinRTDrag::drag(QDrag *drag) +{ + qCDebug(lcQpaMime) << __FUNCTION__ << drag; + + if (!qt_winrt_lastPointerPoint) { + Q_ASSERT_X(qt_winrt_lastPointerPoint, Q_FUNC_INFO, "No pointerpoint known"); + return Qt::IgnoreAction; + } + + ComPtr<IUIElement3> elem3; + HRESULT hr = m_ui.As(&elem3); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IAsyncOperation<ABI::Windows::ApplicationModel::DataTransfer::DataPackageOperation>> op; + EventRegistrationToken startingToken; + + hr = QEventDispatcherWinRT::runOnXamlThread([drag, &op, &hr, elem3, &startingToken, this]() { + + hr = elem3->put_CanDrag(true); + Q_ASSERT_SUCCEEDED(hr); + + auto startingCallback = Callback<ITypedEventHandler<UIElement*, DragStartingEventArgs*>> ([drag](IInspectable *, IDragStartingEventArgs *args) { + qCDebug(lcQpaMime) << "Drag starting" << args; + + ComPtr<IDataPackage> dataPackage; + HRESULT hr; + hr = args->get_Data(dataPackage.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + Qt::DropAction action = drag->defaultAction(); + hr = dataPackage->put_RequestedOperation(translateFromQDragDropActions(action)); + Q_ASSERT_SUCCEEDED(hr); + +#ifndef QT_WINRT_LIMITED_DRAGANDDROP + ComPtr<IDragStartingEventArgs2> args2; + hr = args->QueryInterface(IID_PPV_ARGS(&args2)); + Q_ASSERT_SUCCEEDED(hr); + + Qt::DropActions actions = drag->supportedActions(); + DataPackageOperation allowedOperations = DataPackageOperation_None; + if (actions & Qt::CopyAction) + allowedOperations |= DataPackageOperation_Copy; + if (actions & Qt::MoveAction) + allowedOperations |= DataPackageOperation_Move; + if (actions & Qt::LinkAction) + allowedOperations |= DataPackageOperation_Link; + hr = args2->put_AllowedOperations(allowedOperations); + Q_ASSERT_SUCCEEDED(hr); +#endif // QT_WINRT_LIMITED_DRAGANDDROP + QMimeData *mimeData = drag->mimeData(); + if (mimeData->hasText()) { + hr = dataPackage->SetText(qStringToHString(mimeData->text()).Get()); + Q_ASSERT_SUCCEEDED(hr); + } + if (mimeData->hasHtml()) { + hr = dataPackage->SetHtmlFormat(qStringToHString(mimeData->html()).Get()); + Q_ASSERT_SUCCEEDED(hr); + } + // ### TODO: Missing: weblink, image + + if (!drag->pixmap().isNull()) { + const QImage image2 = drag->pixmap().toImage(); + const QImage image = image2.convertToFormat(QImage::Format_ARGB32); + if (!image.isNull()) { + // Create IBuffer containing image + ComPtr<IBuffer> imageBuffer = createIBufferFromData(reinterpret_cast<const char*>(image.bits()), image.byteCount()); + + ComPtr<ISoftwareBitmapFactory> bitmapFactory; + hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Graphics_Imaging_SoftwareBitmap).Get(), + IID_PPV_ARGS(&bitmapFactory)); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<ISoftwareBitmap> bitmap; + hr = bitmapFactory->Create(BitmapPixelFormat_Rgba8, image.width(), image.height(), &bitmap); + Q_ASSERT_SUCCEEDED(hr); + + hr = bitmap->CopyFromBuffer(imageBuffer.Get()); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IDragUI> dragUi; + hr = args->get_DragUI(dragUi.GetAddressOf()); + Q_ASSERT_SUCCEEDED(hr); + + hr = dragUi->SetContentFromSoftwareBitmap(bitmap.Get()); + Q_ASSERT_SUCCEEDED(hr); + } + } + + const QStringList formats = mimeData->formats(); + for (auto item : formats) { + QByteArray data = mimeData->data(item); + + ComPtr<IBuffer> buffer = createIBufferFromData(data.constData(), data.size()); + + // We cannot push the buffer to the data package as the result on + // recipient side is different from native events. It still sends a + // buffer, but that potentially cannot be parsed. Hence we need to create + // a IRandomAccessStream which gets forwarded as is to the drop side. + ComPtr<IRandomAccessStream> ras; + hr = RoActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Streams_InMemoryRandomAccessStream).Get(), &ras); + Q_ASSERT_SUCCEEDED(hr); + + hr = ras->put_Size(data.size()); + ComPtr<IOutputStream> outputStream; + hr = ras->GetOutputStreamAt(0, &outputStream); + Q_ASSERT_SUCCEEDED(hr); + + ComPtr<IAsyncOperationWithProgress<UINT32,UINT32>> writeOp; + hr = outputStream->WriteAsync(buffer.Get(), &writeOp); + Q_ASSERT_SUCCEEDED(hr); + + UINT32 result; + hr = QWinRTFunctions::await(writeOp, &result); + Q_ASSERT_SUCCEEDED(hr); + + unsigned char flushResult; + ComPtr<IAsyncOperation<bool>> flushOp; + hr = outputStream->FlushAsync(&flushOp); + Q_ASSERT_SUCCEEDED(hr); + + hr = QWinRTFunctions::await(flushOp, &flushResult); + Q_ASSERT_SUCCEEDED(hr); + + hr = dataPackage->SetData(qStringToHString(item).Get(), ras.Get()); + Q_ASSERT_SUCCEEDED(hr); + } + return S_OK; + }); + + hr = elem3->add_DragStarting(startingCallback.Get(), &startingToken); + Q_ASSERT_SUCCEEDED(hr); + + hr = elem3->StartDragAsync(qt_winrt_lastPointerPoint.Get(), &op); + Q_ASSERT_SUCCEEDED(hr); + + return hr; + }); + if (!op || FAILED(hr)) { + qCDebug(lcQpaMime) << "Drag failed:" << hr; + hr = resetUiElementDrag(elem3, startingToken); + Q_ASSERT_SUCCEEDED(hr); + return Qt::IgnoreAction; + } + + DataPackageOperation nativeOperationType; + // Do not yield, as that can cause deadlocks when dropping inside the same app + hr = QWinRTFunctions::await(op, &nativeOperationType, QWinRTFunctions::ProcessThreadEvents); + Q_ASSERT_SUCCEEDED(hr); + + hr = resetUiElementDrag(elem3, startingToken); + Q_ASSERT_SUCCEEDED(hr); + + Qt::DropAction resultAction; + switch (nativeOperationType) { + case DataPackageOperation_Link: + resultAction = Qt::LinkAction; + break; + case DataPackageOperation_Copy: + resultAction = Qt::CopyAction; + break; + case DataPackageOperation_Move: + resultAction = Qt::MoveAction; + break; + case DataPackageOperation_None: + default: + resultAction = Qt::IgnoreAction; + break; + } + + return resultAction; +} + +void QWinRTDrag::setDropTarget(QWindow *target) +{ + qCDebug(lcQpaMime) << __FUNCTION__ << target; + m_dragTarget = target; +} + +QMimeData *QWinRTDrag::platformDropData() +{ + qCDebug(lcQpaMime) << __FUNCTION__; + return m_mimeData; +} + +void QWinRTDrag::setUiElement(ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element) +{ + qCDebug(lcQpaMime) << __FUNCTION__; + m_ui = element; + // We set the element to always accept drops and then evaluate during + // runtime + HRESULT hr = element->put_AllowDrop(TRUE); + EventRegistrationToken tok; + hr = element->add_DragEnter(m_enter, &tok); + RETURN_VOID_IF_FAILED("Failed to add DragEnter handler."); + hr = element->add_DragOver(m_over, &tok); + RETURN_VOID_IF_FAILED("Failed to add DragOver handler."); + hr = element->add_DragLeave(m_leave, &tok); + RETURN_VOID_IF_FAILED("Failed to add DragLeave handler."); + hr = element->add_Drop(m_drop, &tok); + RETURN_VOID_IF_FAILED("Failed to add Drop handler."); +} + +void QWinRTDrag::handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop) +{ + Q_UNUSED(sender); + + if (!m_dragTarget) + return; + + HRESULT hr; + Point relativePoint; + hr = e->GetPosition(m_ui.Get(), &relativePoint); + RETURN_VOID_IF_FAILED("Could not query drag position."); + const QPoint p(relativePoint.X, relativePoint.Y); + + ComPtr<IDragEventArgs2> e2; + hr = e->QueryInterface(IID_PPV_ARGS(&e2)); + RETURN_VOID_IF_FAILED("Could not convert drag event args"); + + DragDropModifiers modifiers; + hr = e2->get_Modifiers(&modifiers); + +#ifndef QT_WINRT_LIMITED_DRAGANDDROP + ComPtr<IDragEventArgs3> e3; + hr = e->QueryInterface(IID_PPV_ARGS(&e3)); + Q_ASSERT_SUCCEEDED(hr); + + DataPackageOperation dataOp; + hr = e3->get_AllowedOperations(&dataOp); + if (FAILED(hr)) + qCDebug(lcQpaMime) << __FUNCTION__ << "Could not query drag operations"; + + const Qt::DropActions actions = translateToQDragDropActions(dataOp); +#else // !QT_WINRT_LIMITED_DRAGANDDROP + const Qt::DropActions actions = Qt::LinkAction | Qt::CopyAction | Qt::MoveAction;; +#endif // !QT_WINRT_LIMITED_DRAGANDDROP + + ComPtr<IDataPackageView> dataView; + hr = e2->get_DataView(&dataView); + Q_ASSERT_SUCCEEDED(hr); + + m_mimeData->setDataView(dataView); + + // We use deferral as we need to jump to the Qt thread to handle + // the drag event + ComPtr<IDragOperationDeferral> deferral; + hr = e2->GetDeferral(&deferral); + Q_ASSERT_SUCCEEDED(hr); + + DragThreadTransferData *transferData = new DragThreadTransferData; + transferData->moveToThread(qGuiApp->thread()); + transferData->window = m_dragTarget; + transferData->point = p; + transferData->mime = m_mimeData; + transferData->actions = actions; + transferData->dropAction = drop; + transferData->nativeArgs = e; + transferData->deferral = deferral; + QMetaObject::invokeMethod(transferData, "handleDrag", Qt::QueuedConnection); +} + +DragThreadTransferData::DragThreadTransferData(QObject *parent) + : QObject(parent) + , dropAction(false) +{ +} + +void DragThreadTransferData::handleDrag() +{ + bool accepted = false; + Qt::DropAction acceptedAction; + if (dropAction) { + QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(window, mime, point, actions); + accepted = response.isAccepted(); + acceptedAction = response.acceptedAction(); + } else { + QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, mime, point, actions); + accepted = response.isAccepted(); + acceptedAction = response.acceptedAction(); + } + + HRESULT hr; + hr = QEventDispatcherWinRT::runOnXamlThread([accepted, acceptedAction, this]() { + HRESULT hr; + hr = nativeArgs->put_Handled(accepted); + if (acceptedAction != Qt::IgnoreAction) { + ComPtr<IDragEventArgs2> e2; + hr = nativeArgs.As(&e2); + if (SUCCEEDED(hr)) + hr = e2->put_AcceptedOperation(translateFromQDragDropActions(acceptedAction)); + } + deferral->Complete(); + return S_OK; + }); + Q_ASSERT_SUCCEEDED(hr); + deleteLater(); +} + +QT_END_NAMESPACE + +#include "qwinrtdrag.moc" diff --git a/src/plugins/platforms/winrt/qwinrtdrag.h b/src/plugins/platforms/winrt/qwinrtdrag.h new file mode 100644 index 0000000000..97079d831b --- /dev/null +++ b/src/plugins/platforms/winrt/qwinrtdrag.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qpa/qplatformdrag.h> + +#include <QtCore/QLoggingCategory> +#include <QtCore/QMimeData> +#include <QtGui/private/qdnd_p.h> // QInternalMime + +#include <wrl.h> + +namespace ABI { + namespace Windows { + namespace ApplicationModel { + namespace DataTransfer { + struct IDataPackageView; + } + } + namespace UI { + namespace Xaml { + struct IUIElement; + struct IDragEventArgs; + struct IDragOperationDeferral; + //struct IDataPackageView; + } + } + } +} + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(lcQpaMime) + +class QtDragEventHandlerEnter; +class QtDragEventHandlerOver; +class QtDragEventHandlerLeave; +class QtDragEventHandlerDrop; +class QWinRTInternalMimeData; + +class QWinRTInternalMimeData : public QInternalMimeData { +public: + QWinRTInternalMimeData(); + virtual ~QWinRTInternalMimeData(); + + bool hasFormat_sys(const QString &mimetype) const Q_DECL_OVERRIDE; + QStringList formats_sys() const Q_DECL_OVERRIDE; + QVariant retrieveData_sys(const QString &mimetype, QVariant::Type preferredType) const Q_DECL_OVERRIDE; + + void setDataView(const Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> &d); +private: + Microsoft::WRL::ComPtr<ABI::Windows::ApplicationModel::DataTransfer::IDataPackageView> dataView; + mutable QStringList formats; +}; + +class QWinRTDrag : public QPlatformDrag { +public: + QWinRTDrag(); + virtual ~QWinRTDrag(); + static QWinRTDrag *instance(); + + QMimeData *platformDropData(void) Q_DECL_OVERRIDE; + Qt::DropAction drag(QDrag *) Q_DECL_OVERRIDE; + + void setDropTarget(QWindow *target); + + // Native integration and registration + void setUiElement(Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> &element); + + void handleNativeDragEvent(IInspectable *sender, ABI::Windows::UI::Xaml::IDragEventArgs *e, bool drop = false); +private: + Microsoft::WRL::ComPtr<ABI::Windows::UI::Xaml::IUIElement> m_ui; + QWindow *m_dragTarget; + QtDragEventHandlerEnter *m_enter; + QtDragEventHandlerOver *m_over; + QtDragEventHandlerLeave *m_leave; + QtDragEventHandlerDrop *m_drop; + QWinRTInternalMimeData *m_mimeData; +}; + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index 8ef560ba20..42b7f7e909 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -48,6 +48,9 @@ #include "qwinrtfontdatabase.h" #include "qwinrttheme.h" #include "qwinrtclipboard.h" +#ifndef QT_NO_DRAGANDDROP +#include "qwinrtdrag.h" +#endif #include <QtGui/QOffscreenSurface> #include <QtGui/QOpenGLContext> @@ -312,6 +315,17 @@ QPlatformClipboard *QWinRTIntegration::clipboard() const return d->clipboard; } +#ifndef QT_NO_DRAGANDDROP +QPlatformDrag *QWinRTIntegration::drag() const +{ +#if _MSC_VER >= 1900 + return QWinRTDrag::instance(); +#else + return QPlatformIntegration::drag(); +#endif +} +#endif // QT_NO_DRAGANDDROP + Qt::KeyboardModifiers QWinRTIntegration::queryKeyboardModifiers() const { Q_D(const QWinRTIntegration); diff --git a/src/plugins/platforms/winrt/qwinrtintegration.h b/src/plugins/platforms/winrt/qwinrtintegration.h index 9e28beb8fa..7b4d5531fc 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.h +++ b/src/plugins/platforms/winrt/qwinrtintegration.h @@ -97,6 +97,10 @@ public: QPlatformInputContext *inputContext() const Q_DECL_OVERRIDE; QPlatformServices *services() const Q_DECL_OVERRIDE; QPlatformClipboard *clipboard() const Q_DECL_OVERRIDE; +#ifndef QT_NO_DRAGANDDROP + QPlatformDrag *drag() const Q_DECL_OVERRIDE; +#endif + Qt::KeyboardModifiers queryKeyboardModifiers() const Q_DECL_OVERRIDE; QStringList themeNames() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index aed33f6b48..ad32e63cad 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -42,6 +42,9 @@ #include "qwinrtbackingstore.h" #include "qwinrtinputcontext.h" #include "qwinrtcursor.h" +#ifndef QT_NO_DRAGANDDROP +#include "qwinrtdrag.h" +#endif #include "qwinrtwindow.h" #include <private/qeventdispatcher_winrt_p.h> @@ -556,6 +559,9 @@ QWinRTScreen::QWinRTScreen() ComPtr<Xaml::IUIElement> uiElement; hr = canvas.As(&uiElement); Q_ASSERT_SUCCEEDED(hr); +#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) + QWinRTDrag::instance()->setUiElement(uiElement); +#endif hr = window->put_Content(uiElement.Get()); Q_ASSERT_SUCCEEDED(hr); hr = canvas.As(&d->canvas); @@ -764,6 +770,10 @@ void QWinRTScreen::addWindow(QWindow *window) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(); + +#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) + QWinRTDrag::instance()->setDropTarget(window); +#endif } void QWinRTScreen::removeWindow(QWindow *window) @@ -778,6 +788,10 @@ void QWinRTScreen::removeWindow(QWindow *window) QWindowSystemInterface::handleWindowActivated(window, Qt::OtherFocusReason); handleExpose(); QWindowSystemInterface::flushWindowSystemEvents(); +#if _MSC_VER >= 1900 && !defined(QT_NO_DRAGANDDROP) + if (wasTopWindow) + QWinRTDrag::instance()->setDropTarget(topWindow()); +#endif } void QWinRTScreen::raise(QWindow *window) @@ -973,6 +987,9 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) return S_OK; } +// Required for qwinrtdrag.cpp +ComPtr<IPointerPoint> qt_winrt_lastPointerPoint; + HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) { Q_D(QWinRTScreen); @@ -980,6 +997,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) if (FAILED(args->get_CurrentPoint(&pointerPoint))) return E_INVALIDARG; + qt_winrt_lastPointerPoint = pointerPoint; // Common traits - point, modifiers, properties Point point; pointerPoint->get_Position(&point); diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 144c581015..28456f66ec 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -14,6 +14,7 @@ SOURCES = \ qwinrtbackingstore.cpp \ qwinrtclipboard.cpp \ qwinrtcursor.cpp \ + qwinrtdrag.cpp \ qwinrteglcontext.cpp \ qwinrteventdispatcher.cpp \ qwinrtfiledialoghelper.cpp \ @@ -32,6 +33,7 @@ HEADERS = \ qwinrtbackingstore.h \ qwinrtclipboard.h \ qwinrtcursor.h \ + qwinrtdrag.h \ qwinrteglcontext.h \ qwinrteventdispatcher.h \ qwinrtfiledialoghelper.h \ @@ -47,6 +49,15 @@ HEADERS = \ OTHER_FILES += winrt.json +WINRT_SDK_VERSION_STRING = $$(UCRTVersion) +WINRT_SDK_VERSION = $$member($$list($$split(WINRT_SDK_VERSION_STRING, .)), 2) +lessThan(WINRT_SDK_VERSION, 14322): DEFINES += QT_WINRT_LIMITED_DRAGANDDROP + +*-msvc2013|contains(DEFINES, QT_NO_DRAGANDDROP) { + SOURCES -= qwinrtdrag.cpp + HEADERS -= qwinrtdrag.h +} + PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin !equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp index d536121521..f97c01f390 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qxcbglxintegration.cpp @@ -207,8 +207,10 @@ QPlatformOffscreenSurface *QXcbGlxIntegration::createPlatformOffscreenSurface(QO display = static_cast<Display *>(m_connection->xlib_display()); #endif const char *glxvendor = glXGetClientString(display, GLX_VENDOR); - if (glxvendor && !strcmp(glxvendor, "ATI")) - glxPbufferUsable = false; + if (glxvendor) { + if (!strcmp(glxvendor, "ATI") || !strcmp(glxvendor, "Chromium")) + glxPbufferUsable = false; + } } if (glxPbufferUsable) return new QGLXPbuffer(surface); diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index 377cb626ee..5d46c53b30 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include <QtGui/private/qguiapplication_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include <QtCore/QDebug> #include "qxcbconnection.h" @@ -264,6 +265,7 @@ void QXcbConnection::updateScreens(const xcb_randr_notify_event_t *event) } else { screen = createScreen(virtualDesktop, output, outputInfo.data()); qCDebug(lcQpaScreen) << "output" << screen->name() << "is connected and enabled"; + QHighDpiScaling::updateHighDpiScaling(); } } } else if (screen) { diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 789229c0a7..063778a1de 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -797,9 +797,9 @@ void QXcbWindow::show() propagateSizeHints(); // update WM_TRANSIENT_FOR - const QWindow *tp = window()->transientParent(); - if (isTransient(window()) || tp != 0) { - xcb_window_t transientXcbParent = 0; + xcb_window_t transientXcbParent = 0; + if (isTransient(window())) { + const QWindow *tp = window()->transientParent(); if (tp && tp->handle()) transientXcbParent = static_cast<const QXcbWindow *>(tp->handle())->winId(); // Default to client leader if there is no transient parent, else modal dialogs can @@ -812,6 +812,8 @@ void QXcbWindow::show() 1, &transientXcbParent)); } } + if (!transientXcbParent) + Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, XCB_ATOM_WM_TRANSIENT_FOR)); // update _MOTIF_WM_HINTS updateMotifWmHintsBeforeMap(); @@ -1173,9 +1175,11 @@ void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags) mwmhints.flags |= MWM_HINTS_DECORATIONS; bool customize = flags & Qt::CustomizeWindowHint; - if (type == Qt::Window && !customize) - flags |= Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; - + if (type == Qt::Window && !customize) { + const Qt::WindowFlags defaultFlags = Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; + if (!(flags & defaultFlags)) + flags |= defaultFlags; + } if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) { mwmhints.decorations |= MWM_DECOR_BORDER; mwmhints.decorations |= MWM_DECOR_RESIZEH; diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 55660ce31c..0f4207c636 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -6,7 +6,7 @@ qtHaveModule(network):!contains(QT_DISABLED_FEATURES, bearermanagement): SUBDIRS qtHaveModule(gui) { SUBDIRS *= platforms platforminputcontexts platformthemes !contains(QT_DISABLED_FEATURES, imageformatplugin): SUBDIRS *= imageformats - !contains(QT_DISABLED_FEATURES, library): SUBDIRS *= generic + !android:!contains(QT_DISABLED_FEATURES, library): SUBDIRS *= generic } !winrt:!wince*:qtHaveModule(widgets):!contains(QT_DISABLED_FEATURES, printer) { diff --git a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp index 6f5fb417c6..7e6eb7c559 100644 --- a/src/plugins/printsupport/windows/qwindowsprintdevice.cpp +++ b/src/plugins/printsupport/windows/qwindowsprintdevice.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 John Layt <jlayt@kde.org> +** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the plugins of the Qt Toolkit. @@ -80,6 +81,22 @@ static QPrint::InputSlot paperBinToInputSlot(int windowsId, const QString &name) return slot; } +static LPDEVMODE getDevmode(HANDLE hPrinter, const QString &printerId) +{ + LPWSTR printerIdUtf16 = const_cast<LPWSTR>(reinterpret_cast<LPCWSTR>(printerId.utf16())); + // Allocate the required DEVMODE buffer + LONG dmSize = DocumentProperties(NULL, hPrinter, printerIdUtf16, NULL, NULL, 0); + if (dmSize < 0) + return Q_NULLPTR; + LPDEVMODE pDevMode = reinterpret_cast<LPDEVMODE>(malloc(dmSize)); + // Get the default DevMode + LONG result = DocumentProperties(NULL, hPrinter, printerIdUtf16, pDevMode, NULL, DM_OUT_BUFFER); + if (result != IDOK) { + free(pDevMode); + pDevMode = Q_NULLPTR; + } + return pDevMode; +} QWindowsPrintDevice::QWindowsPrintDevice() : QPlatformPrintDevice(), @@ -197,26 +214,21 @@ QPageSize QWindowsPrintDevice::defaultPageSize() const QPageSize pageSize; - // Allocate the required DEVMODE buffer - DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0); - LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize); - - // Get the default DevMode - DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER); - - // Get the default paper size - if (result == IDOK && pDevMode->dmFields & DM_PAPERSIZE) { - // Find the supported page size that matches, in theory default should be one of them - foreach (const QPageSize &ps, m_pageSizes) { - if (ps.windowsId() == pDevMode->dmPaperSize) { - pageSize = ps; - break; + if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) { + // Get the default paper size + if (pDevMode->dmFields & DM_PAPERSIZE) { + // Find the supported page size that matches, in theory default should be one of them + foreach (const QPageSize &ps, m_pageSizes) { + if (ps.windowsId() == pDevMode->dmPaperSize) { + pageSize = ps; + break; + } } } + // Clean-up + free(pDevMode); } - // Clean-up - free(pDevMode); return pageSize; } @@ -232,20 +244,14 @@ QMarginsF QWindowsPrintDevice::printableMargins(const QPageSize &pageSize, QScopedArrayPointer<BYTE> buffer(new BYTE[needed]); if (GetPrinter(m_hPrinter, 2, buffer.data(), needed, &needed)) { PPRINTER_INFO_2 info = reinterpret_cast<PPRINTER_INFO_2>(buffer.data()); - DEVMODE *devMode = info->pDevMode; + LPDEVMODE devMode = info->pDevMode; bool separateDevMode = false; if (!devMode) { // GetPrinter() didn't include the DEVMODE. Get it a different way. - LONG result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), - NULL, NULL, 0); - devMode = (DEVMODE *)malloc(result); - separateDevMode = true; - result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), - devMode, NULL, DM_OUT_BUFFER); - if (result != IDOK) { - free(devMode); + devMode = getDevmode(m_hPrinter, m_id); + if (!devMode) return margins; - } + separateDevMode = true; } HDC pDC = CreateDC(NULL, (LPWSTR)m_id.utf16(), NULL, devMode); @@ -297,23 +303,17 @@ int QWindowsPrintDevice::defaultResolution() const { int resolution = 72; // TODO Set a sensible default? - // Allocate the required DEVMODE buffer - DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0); - LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize); - - // Get the default DevMode - DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER); - - // Get the default resolution - if (result == IDOK && pDevMode->dmFields & DM_YRESOLUTION) { - if (pDevMode->dmPrintQuality > 0) - resolution = pDevMode->dmPrintQuality; - else - resolution = pDevMode->dmYResolution; + if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) { + // Get the default resolution + if (pDevMode->dmFields & DM_YRESOLUTION) { + if (pDevMode->dmPrintQuality > 0) + resolution = pDevMode->dmPrintQuality; + else + resolution = pDevMode->dmYResolution; + } + // Clean-up + free(pDevMode); } - - // Clean-up - free(pDevMode); return resolution; } @@ -346,26 +346,20 @@ QPrint::InputSlot QWindowsPrintDevice::defaultInputSlot() const { QPrint::InputSlot inputSlot = QPlatformPrintDevice::defaultInputSlot();; - // Allocate the required DEVMODE buffer - DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0); - LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize); - - // Get the default DevMode - DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER); - - // Get the default input slot - if (result == IDOK && pDevMode->dmFields & DM_DEFAULTSOURCE) { - QPrint::InputSlot tempSlot = paperBinToInputSlot(pDevMode->dmDefaultSource, QString()); - foreach (const QPrint::InputSlot &slot, supportedInputSlots()) { - if (slot.key == tempSlot.key) { - inputSlot = slot; - break; + if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) { + // Get the default input slot + if (pDevMode->dmFields & DM_DEFAULTSOURCE) { + QPrint::InputSlot tempSlot = paperBinToInputSlot(pDevMode->dmDefaultSource, QString()); + foreach (const QPrint::InputSlot &slot, supportedInputSlots()) { + if (slot.key == tempSlot.key) { + inputSlot = slot; + break; + } } } + // Clean-up + free(pDevMode); } - - // Clean-up - free(pDevMode); return inputSlot; } @@ -392,23 +386,17 @@ QPrint::DuplexMode QWindowsPrintDevice::defaultDuplexMode() const { QPrint::DuplexMode duplexMode = QPrint::DuplexNone; - // Allocate the required DEVMODE buffer - DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0); - LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize); - - // Get the default DevMode - DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER); - - // Get the default duplex mode - if (result == IDOK && pDevMode->dmFields & DM_DUPLEX) { - if (pDevMode->dmDuplex == DMDUP_VERTICAL) - duplexMode = QPrint::DuplexLongSide; - else if (pDevMode->dmDuplex == DMDUP_HORIZONTAL) - duplexMode = QPrint::DuplexShortSide; + if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) { + // Get the default duplex mode + if (pDevMode->dmFields & DM_DUPLEX) { + if (pDevMode->dmDuplex == DMDUP_VERTICAL) + duplexMode = QPrint::DuplexLongSide; + else if (pDevMode->dmDuplex == DMDUP_HORIZONTAL) + duplexMode = QPrint::DuplexShortSide; + } + // Clean-up + free(pDevMode); } - - // Clean-up - free(pDevMode); return duplexMode; } @@ -430,21 +418,13 @@ QPrint::ColorMode QWindowsPrintDevice::defaultColorMode() const QPrint::ColorMode colorMode = QPrint::GrayScale; - // Allocate the required DEVMODE buffer - DWORD dmSize = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), NULL, NULL, 0); - LPDEVMODE pDevMode = (LPDEVMODE)malloc(dmSize); - - // Get the default DevMode - DWORD result = DocumentProperties(NULL, m_hPrinter, (LPWSTR)m_id.utf16(), pDevMode, NULL, DM_OUT_BUFFER); - - // Get the default color mode - if (result == IDOK && pDevMode->dmFields & DM_COLOR) { - if (pDevMode->dmColor == DMCOLOR_COLOR) + if (LPDEVMODE pDevMode = getDevmode(m_hPrinter, m_id)) { + // Get the default color mode + if (pDevMode->dmFields & DM_COLOR && pDevMode->dmColor == DMCOLOR_COLOR) colorMode = QPrint::Color; + // Clean-up + free(pDevMode); } - - // Clean-up - free(pDevMode); return colorMode; } diff --git a/src/src.pro b/src/src.pro index fcececdeda..4ca1347f2b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -88,6 +88,9 @@ src_3rdparty_harfbuzzng.subdir = $$PWD/3rdparty/harfbuzz-ng src_3rdparty_harfbuzzng.target = sub-3rdparty-harfbuzzng src_3rdparty_harfbuzzng.depends = src_corelib # for the Qt atomics +src_3rdparty_libpng.subdir = $$PWD/3rdparty/libpng +src_3rdparty_libpng.target = sub-3rdparty-libpng + src_3rdparty_freetype.subdir = $$PWD/3rdparty/freetype src_3rdparty_freetype.target = sub-3rdparty-freetype @@ -132,6 +135,7 @@ src_android.subdir = $$PWD/android !contains(QT_CONFIG, system-zlib)|cross_compile { SUBDIRS += src_qtzlib !contains(QT_CONFIG, system-zlib) { + src_3rdparty_libpng.depends += src_corelib src_3rdparty_freetype.depends += src_corelib } } @@ -163,6 +167,11 @@ contains(QT_CONFIG, concurrent):SUBDIRS += src_concurrent SUBDIRS += src_angle src_gui.depends += src_angle } + contains(QT_CONFIG, png) { + SUBDIRS += src_3rdparty_libpng + src_3rdparty_freetype.depends += src_3rdparty_libpng + src_plugins.depends += src_3rdparty_libpng + } contains(QT_CONFIG, freetype):!contains(QT_CONFIG, system-freetype) { SUBDIRS += src_3rdparty_freetype src_platformsupport.depends += src_3rdparty_freetype diff --git a/src/testlib/doc/qttestlib.qdocconf b/src/testlib/doc/qttestlib.qdocconf index 0fafc733b1..899f94ec53 100644 --- a/src/testlib/doc/qttestlib.qdocconf +++ b/src/testlib/doc/qttestlib.qdocconf @@ -4,7 +4,7 @@ project = QtTestLib description = Qt Test Reference Documentation version = $QT_VERSION -examplesinstallpath = testlib +examplesinstallpath = qtestlib qhp.projects = QtTestLib diff --git a/src/testlib/doc/src/qttestlib-manual.qdoc b/src/testlib/doc/src/qttestlib-manual.qdoc index 62cc6c9654..fc8f3b747e 100644 --- a/src/testlib/doc/src/qttestlib-manual.qdoc +++ b/src/testlib/doc/src/qttestlib-manual.qdoc @@ -487,6 +487,7 @@ \nextpage {Chapter 2: Data Driven Testing}{Chapter 2} \title Chapter 1: Writing a Unit Test + \brief How to write a unit test. In this first chapter we will see how to write a simple unit test for a class, and how to execute it. @@ -562,6 +563,7 @@ \nextpage {Chapter 3: Simulating Gui Events}{Chapter 3} \title Chapter 2: Data Driven Testing + \brief How to create data driven tests. In this chapter we will demonstrate how to execute a test multiple times with different test data. @@ -667,6 +669,7 @@ \nextpage {Chapter 4: Replaying GUI Events}{Chapter 4} \title Chapter 3: Simulating GUI Events + \brief Howe to simulate GUI events. Qt Test features some mechanisms to test graphical user interfaces. Instead of simulating native window system events, @@ -727,6 +730,7 @@ \nextpage {Chapter 5: Writing a Benchmark}{Chapter 5} \title Chapter 4: Replaying GUI Events + \brief How to replay GUI events. In this chapter, we will show how to simulate a GUI event, and how to store a series of GUI events as well as replay them on @@ -806,6 +810,7 @@ \contentspage {Qt Test Tutorial}{Contents} \title Chapter 5: Writing a Benchmark + \brief How to write a benchmark. In this final chapter we will demonstrate how to write benchmarks using Qt Test. diff --git a/src/testlib/qtest.h b/src/testlib/qtest.h index 261c769c15..49a0c2104b 100644 --- a/src/testlib/qtest.h +++ b/src/testlib/qtest.h @@ -160,7 +160,7 @@ template<> inline char *toString(const QVariant &v) if (!v.isNull()) { vstring.append(','); if (v.canConvert(QVariant::String)) { - vstring.append(qvariant_cast<QString>(v).toLocal8Bit()); + vstring.append(v.toString().toLocal8Bit()); } else { vstring.append("<value not representable as string>"); diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp index 4435b509be..1fa76a692a 100644 --- a/src/testlib/qtestblacklist.cpp +++ b/src/testlib/qtestblacklist.cpp @@ -52,21 +52,38 @@ QT_BEGIN_NAMESPACE /* - The file format is simply a grouped listing of keywords - Ungrouped entries at the beginning apply to the whole testcase - Groups define testfunctions or specific test data to ignore. - After the groups come a list of entries (one per line) that define - for which platform/os combination to ignore the test result. - All keys in a single line have to match to blacklist the test. - - mac - [testFunction] - linux - windows 64bit - [testfunction2:testData] - msvc - - The known keys are listed below: + The BLACKLIST file format is a grouped listing of keywords. + + Blank lines and lines starting with # are simply ignored. An initial #-line + referring to this documentation is kind to readers. Comments can also be used + to indicate the reasons for ignoring particular cases. + + A key names a platform, O/S, distribution, tool-chain or architecture; a ! + prefix reverses what it checks. A version, joined to a key (at present, only + for distributions and for msvc) with a hyphen, limits the key to the specific + version. A keyword line matches if every key on it applies to the present + run. Successive lines are alternate conditions for ignoring a test. + + Ungrouped lines at the beginning of a file apply to the whole testcase. + A group starts with a [square-bracketed] identification of a test function, + optionally with (after a colon, the name of) a specific data set, to ignore. + Subsequent lines give conditions for ignoring this test. + + # See qtbase/src/testlib/qtestblacklist.cpp for format + osx + + # QTBUG-12345 + [testFunction] + linux + windows 64bit + + # Needs basic C++11 support + [testfunction2:testData] + msvc-2010 + + Keys are lower-case. Distribution name and version are supported if + QSysInfo's productType() and productVersion() return them. + The other known keys are listed below: */ static QSet<QByteArray> keywords() @@ -148,19 +165,30 @@ static QSet<QByteArray> keywords() return set; } -static bool checkCondition(const QByteArray &condition) +static QSet<QByteArray> activeConditions() { - static QSet<QByteArray> matchedConditions = keywords(); - QList<QByteArray> conds = condition.split(' '); + QSet<QByteArray> result = keywords(); QByteArray distributionName = QSysInfo::productType().toLower().toUtf8(); QByteArray distributionRelease = QSysInfo::productVersion().toLower().toUtf8(); if (!distributionName.isEmpty()) { - if (matchedConditions.find(distributionName) == matchedConditions.end()) - matchedConditions.insert(distributionName); - matchedConditions.insert(distributionName + "-" + distributionRelease); + if (result.find(distributionName) == result.end()) + result.insert(distributionName); + if (!distributionRelease.isEmpty()) { + QByteArray versioned = distributionName + "-" + distributionRelease; + if (result.find(versioned) == result.end()) + result.insert(versioned); + } } + return result; +} + +static bool checkCondition(const QByteArray &condition) +{ + static const QSet<QByteArray> matchedConditions = activeConditions(); + QList<QByteArray> conds = condition.split(' '); + for (int i = 0; i < conds.size(); ++i) { QByteArray c = conds.at(i); bool result = c.startsWith('!'); diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 73303ca28d..b6c70fdd86 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -116,7 +116,7 @@ static bool debuggerPresent() if (fd == -1) return false; char buffer[2048]; - ssize_t size = read(fd, buffer, sizeof(buffer)); + ssize_t size = read(fd, buffer, sizeof(buffer) - 1); if (size == -1) { close(fd); return false; diff --git a/src/widgets/dialogs/qdialog.cpp b/src/widgets/dialogs/qdialog.cpp index 74d138442a..464a1e139e 100644 --- a/src/widgets/dialogs/qdialog.cpp +++ b/src/widgets/dialogs/qdialog.cpp @@ -846,6 +846,12 @@ void QDialog::adjustPosition(QWidget* w) if (p.y() < desk.y()) p.setY(desk.y()); + // QTBUG-52735: Manually set the correct target screen since scaling in a + // subsequent call to QWindow::resize() may otherwise use the wrong factor + // if the screen changed notification is still in an event queue. + if (QWindow *window = windowHandle()) + window->setScreen(QGuiApplication::screens().at(scrn)); + move(p); } diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 0ab2e1860c..42e0cc7585 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -3671,6 +3671,9 @@ void QAbstractItemView::startDrag(Qt::DropActions supportedActions) defaultDropAction = Qt::CopyAction; if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction) d->clearOrRemove(); + // Reset the drop indicator + d->dropIndicatorRect = QRect(); + d->dropIndicatorPosition = OnItem; } } #endif // QT_NO_DRAGANDDROP diff --git a/src/widgets/kernel/qdesktopwidget.cpp b/src/widgets/kernel/qdesktopwidget.cpp index fceb061867..ece673337a 100644 --- a/src/widgets/kernel/qdesktopwidget.cpp +++ b/src/widgets/kernel/qdesktopwidget.cpp @@ -46,6 +46,21 @@ QT_BEGIN_NAMESPACE +QDesktopScreenWidget::QDesktopScreenWidget(QScreen *screen, const QRect &geometry) + : QWidget(Q_NULLPTR, Qt::Desktop), m_screen(screen) +{ + setVisible(false); + if (QWindow *winHandle = windowHandle()) + winHandle->setScreen(screen); + setScreenGeometry(geometry); +} + +void QDesktopScreenWidget::setScreenGeometry(const QRect &geometry) +{ + m_geometry = geometry; + setGeometry(geometry); +} + int QDesktopScreenWidget::screenNumber() const { const QDesktopWidgetPrivate *desktopWidgetP @@ -80,54 +95,76 @@ const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const return rect; } +QDesktopScreenWidget *QDesktopWidgetPrivate::widgetForScreen(QScreen *qScreen) const +{ + foreach (QDesktopScreenWidget *widget, screens) { + if (widget->screen() == qScreen) + return widget; + } + return Q_NULLPTR; +} + void QDesktopWidgetPrivate::_q_updateScreens() { Q_Q(QDesktopWidget); const QList<QScreen *> screenList = QGuiApplication::screens(); const int targetLength = screenList.length(); - const int oldLength = screens.length(); - - // Add or remove screen widgets as necessary - while (screens.size() > targetLength) - delete screens.takeLast(); - - for (int currentLength = screens.size(); currentLength < targetLength; ++currentLength) { - QScreen *qScreen = screenList.at(currentLength); - QDesktopScreenWidget *screenWidget = new QDesktopScreenWidget; - screenWidget->setGeometry(qScreen->geometry()); - QObject::connect(qScreen, SIGNAL(geometryChanged(QRect)), - q, SLOT(_q_updateScreens()), Qt::QueuedConnection); - QObject::connect(qScreen, SIGNAL(availableGeometryChanged(QRect)), - q, SLOT(_q_availableGeometryChanged()), Qt::QueuedConnection); - QObject::connect(qScreen, SIGNAL(destroyed()), - q, SLOT(_q_updateScreens()), Qt::QueuedConnection); - screens.append(screenWidget); - } + bool screenCountChanged = false; + // Re-build our screens list. This is the easiest way to later compute which signals to emit. + // Create new screen widgets as necessary. While iterating, keep the old list in place so + // that widgetForScreen works. + // Furthermore, we note which screens have changed, and compute the overall virtual geometry. + QList<QDesktopScreenWidget *> newScreens; + QList<int> changedScreens; QRegion virtualGeometry; - // update the geometry of each screen widget, determine virtual geometry, - // set the new screen for window handle and emit change signals afterwards. - QList<int> changedScreens; - for (int i = 0; i < screens.length(); i++) { - QDesktopScreenWidget *screenWidget = screens.at(i); + for (int i = 0; i < targetLength; ++i) { QScreen *qScreen = screenList.at(i); - QWindow *winHandle = screenWidget->windowHandle(); - if (winHandle && winHandle->screen() != qScreen) - winHandle->setScreen(qScreen); const QRect screenGeometry = qScreen->geometry(); - if (screenGeometry != screenWidget->geometry()) { - screenWidget->setGeometry(screenGeometry); - changedScreens.push_back(i); + QDesktopScreenWidget *screenWidget = widgetForScreen(qScreen); + if (screenWidget) { + // an old screen. update geometry and remember the index in the *new* list + if (screenGeometry != screenWidget->screenGeometry()) { + screenWidget->setScreenGeometry(screenGeometry); + changedScreens.push_back(i); + } + } else { + // a new screen, create a widget and connect the signals. + screenWidget = new QDesktopScreenWidget(qScreen, screenGeometry); + QObject::connect(qScreen, SIGNAL(geometryChanged(QRect)), + q, SLOT(_q_updateScreens()), Qt::QueuedConnection); + QObject::connect(qScreen, SIGNAL(availableGeometryChanged(QRect)), + q, SLOT(_q_availableGeometryChanged()), Qt::QueuedConnection); + QObject::connect(qScreen, SIGNAL(destroyed()), + q, SLOT(_q_updateScreens()), Qt::QueuedConnection); + screenCountChanged = true; } + // record all the screens and the overall geometry. + newScreens.push_back(screenWidget); virtualGeometry += screenGeometry; } + // Now we apply the accumulated updates. + screens.swap(newScreens); // now [newScreens] is the old screen list + Q_ASSERT(screens.size() == targetLength); q->setGeometry(virtualGeometry.boundingRect()); - if (oldLength != targetLength) - emit q->screenCountChanged(targetLength); + // Delete the QDesktopScreenWidget that are not used any more. + foreach (QDesktopScreenWidget *screen, newScreens) { + if (!screens.contains(screen)) { + delete screen; + screenCountChanged = true; + } + } + // Finally, emit the signals. + if (screenCountChanged) { + // Notice that we trigger screenCountChanged even if a screen was removed and another one added, + // in which case the total number of screens did not change. This is the only way for applications + // to notice that a screen was swapped out against another one. + emit q->screenCountChanged(targetLength); + } foreach (int changedScreen, changedScreens) emit q->resized(changedScreen); } diff --git a/src/widgets/kernel/qdesktopwidget_p.h b/src/widgets/kernel/qdesktopwidget_p.h index 7c68ad9b31..a590024b7c 100644 --- a/src/widgets/kernel/qdesktopwidget_p.h +++ b/src/widgets/kernel/qdesktopwidget_p.h @@ -61,12 +61,19 @@ QT_BEGIN_NAMESPACE class QDesktopScreenWidget : public QWidget { Q_OBJECT public: - QDesktopScreenWidget() : QWidget(Q_NULLPTR, Qt::Desktop) - { - setVisible(false); - } + explicit QDesktopScreenWidget(QScreen *screen, const QRect &geometry); int screenNumber() const; + void setScreenGeometry(const QRect &geometry); + + QScreen *screen() const { return m_screen.data(); } + QRect screenGeometry() const { return m_geometry; } + +private: + // The widget updates its screen and geometry automatically. We need to save them separately + // to detect changes, and trigger the appropriate signals. + const QPointer<QScreen> m_screen; + QRect m_geometry; }; class QDesktopWidgetPrivate : public QWidgetPrivate { @@ -76,6 +83,7 @@ public: ~QDesktopWidgetPrivate() { qDeleteAll(screens); } void _q_updateScreens(); void _q_availableGeometryChanged(); + QDesktopScreenWidget *widgetForScreen(QScreen *qScreen) const; QList<QDesktopScreenWidget *> screens; }; diff --git a/src/widgets/kernel/qopenglwidget.cpp b/src/widgets/kernel/qopenglwidget.cpp index 5071c56763..124c8c000a 100644 --- a/src/widgets/kernel/qopenglwidget.cpp +++ b/src/widgets/kernel/qopenglwidget.cpp @@ -910,8 +910,10 @@ void QOpenGLWidgetPrivate::resizeViewportFramebuffer() if (!initialized) return; - if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) + if (!fbo || q->size() * q->devicePixelRatioF() != fbo->size()) { recreateFbo(); + q->update(); + } } /*! diff --git a/src/widgets/kernel/qwidgetbackingstore.cpp b/src/widgets/kernel/qwidgetbackingstore.cpp index 7c9ac5571c..ecaba584f2 100644 --- a/src/widgets/kernel/qwidgetbackingstore.cpp +++ b/src/widgets/kernel/qwidgetbackingstore.cpp @@ -992,8 +992,18 @@ static QPlatformTextureList *widgetTexturesFor(QWidget *tlw, QWidget *widget) static bool switchableWidgetComposition = QGuiApplicationPrivate::instance()->platformIntegration() ->hasCapability(QPlatformIntegration::SwitchableWidgetComposition); - if (!switchableWidgetComposition) + if (!switchableWidgetComposition +// The Windows compositor handles fullscreen OpenGL window specially. Besides +// having trouble with popups, it also has issues with flip-flopping between +// OpenGL-based and normal flushing. Therefore, stick with GL for fullscreen +// windows. (QTBUG-53515) +#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE) + || tlw->windowState().testFlag(Qt::WindowFullScreen) +#endif + ) + { return qt_dummy_platformTextureList(); + } } return 0; @@ -1192,10 +1202,20 @@ void QWidgetBackingStore::doSync() // We know for sure that the widget isn't overlapped if 'isMoved' is true. if (!wd->isMoved) wd->subtractOpaqueSiblings(wd->dirty, &hasDirtySiblingsAbove); + + // Make a copy of the widget's dirty region, to restore it in case there is an opaque + // render-to-texture child that completely covers the widget, because otherwise the + // render-to-texture child won't be visible, due to its parent widget not being redrawn + // with a proper blending mask. + const QRegion dirtyBeforeSubtractedOpaqueChildren = wd->dirty; + // Scrolled and moved widgets must draw all children. if (!wd->isScrolled && !wd->isMoved) wd->subtractOpaqueChildren(wd->dirty, w->rect()); + if (wd->dirty.isEmpty() && wd->textureChildSeen) + wd->dirty = dirtyBeforeSubtractedOpaqueChildren; + if (wd->dirty.isEmpty()) { resetWidget(w); continue; diff --git a/src/widgets/kernel/qwidgetbackingstore_p.h b/src/widgets/kernel/qwidgetbackingstore_p.h index a7dbfafc05..dc20446047 100644 --- a/src/widgets/kernel/qwidgetbackingstore_p.h +++ b/src/widgets/kernel/qwidgetbackingstore_p.h @@ -116,7 +116,7 @@ public: inline bool isDirty() const { - return !(dirtyWidgets.isEmpty() && dirty.isEmpty()); + return !(dirtyWidgets.isEmpty() && dirty.isEmpty() && dirtyRenderToTextureWidgets.isEmpty()); } // ### Qt 4.6: Merge into a template function (after MSVC isn't supported anymore). diff --git a/src/widgets/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp index 675d54f6b4..2a4f31babf 100644 --- a/src/widgets/kernel/qwidgetwindow.cpp +++ b/src/widgets/kernel/qwidgetwindow.cpp @@ -883,14 +883,8 @@ void QWidgetWindow::handleExposeEvent(QExposeEvent *event) { if (isExposed()) { m_widget->setAttribute(Qt::WA_Mapped); - if (!event->region().isNull()) { - // Exposed native widgets need to be marked dirty to get them repainted correctly. - if (m_widget->internalWinId() && !m_widget->isWindow() && m_widget->isVisible() && m_widget->updatesEnabled()) { - if (QWidgetBackingStore *bs = m_widget->d_func()->maybeBackingStore()) - bs->markDirty(event->region(), m_widget); - } + if (!event->region().isNull()) m_widget->d_func()->syncBackingStore(event->region()); - } } else { m_widget->setAttribute(Qt::WA_Mapped, false); } diff --git a/src/widgets/styles/qfusionstyle.cpp b/src/widgets/styles/qfusionstyle.cpp index 1ac28f548b..06c3101643 100644 --- a/src/widgets/styles/qfusionstyle.cpp +++ b/src/widgets/styles/qfusionstyle.cpp @@ -2389,8 +2389,7 @@ void QFusionStyle::drawComplexControl(ComplexControl control, const QStyleOption if (!titleBar->icon.isNull()) { titleBar->icon.paint(painter, iconRect); } else { - QStyleOption tool(0); - tool.palette = titleBar->palette; + QStyleOption tool = *titleBar; QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget).pixmap(16, 16); tool.rect = iconRect; painter->save(); diff --git a/src/widgets/styles/qmacstyle_mac.mm b/src/widgets/styles/qmacstyle_mac.mm index deb2fb4da0..56531b10de 100644 --- a/src/widgets/styles/qmacstyle_mac.mm +++ b/src/widgets/styles/qmacstyle_mac.mm @@ -5951,12 +5951,10 @@ void QMacStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComplex #ifndef QT_NO_ACCESSIBILITY if (QStyleHelper::hasAncestor(opt->styleObject, QAccessible::ToolBar)) { if (tb->subControls & SC_ToolButtonMenu) { - QStyleOption arrowOpt(0); + QStyleOption arrowOpt = *tb; arrowOpt.rect = proxy()->subControlRect(cc, tb, SC_ToolButtonMenu, widget); arrowOpt.rect.setY(arrowOpt.rect.y() + arrowOpt.rect.height() / 2); arrowOpt.rect.setHeight(arrowOpt.rect.height() / 2); - arrowOpt.state = tb->state; - arrowOpt.palette = tb->palette; proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget); } else if ((tb->features & QStyleOptionToolButton::HasMenu) && (tb->toolButtonStyle != Qt::ToolButtonTextOnly && !tb->icon.isNull())) { diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 7ce9bbc273..b41ad4249e 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -2131,9 +2131,8 @@ void QWindowsStyle::drawComplexControl(ComplexControl cc, const QStyleOptionComp if (sunkenArrow) flags |= State_Sunken; - QStyleOption arrowOpt(0); + QStyleOption arrowOpt = *cmb; arrowOpt.rect = ar.adjusted(1, 1, -1, -1); - arrowOpt.palette = cmb->palette; arrowOpt.state = flags; proxy()->drawPrimitive(PE_IndicatorArrowDown, &arrowOpt, p, widget); } diff --git a/src/widgets/styles/qwindowsvistastyle.cpp b/src/widgets/styles/qwindowsvistastyle.cpp index 83820016aa..6009b5d1f8 100644 --- a/src/widgets/styles/qwindowsvistastyle.cpp +++ b/src/widgets/styles/qwindowsvistastyle.cpp @@ -1059,7 +1059,7 @@ void QWindowsVistaStyle::drawControl(ControlElement element, const QStyleOption QPainter imagePainter(&image); theme.painter = &imagePainter; theme.partId = vertical ? PP_FILLVERT : PP_FILL; - theme.rect = QRect(QPoint(0,0), theme.rect.size()); + theme.rect = QRect(QPoint(0,0), animRect.size()); QLinearGradient alphaGradient(0, 0, vertical ? 0 : image.width(), vertical ? image.height() : 0); alphaGradient.setColorAt(0, QColor(0, 0, 0, 0)); diff --git a/src/widgets/styles/qwindowsxpstyle.cpp b/src/widgets/styles/qwindowsxpstyle.cpp index 916210ad09..2fbc40dc11 100644 --- a/src/widgets/styles/qwindowsxpstyle.cpp +++ b/src/widgets/styles/qwindowsxpstyle.cpp @@ -2866,8 +2866,7 @@ void QWindowsXPStyle::drawComplexControl(ComplexControl cc, const QStyleOptionCo } } - QStyleOption tool(0); - tool.palette = toolbutton->palette; + QStyleOption tool = *toolbutton; if (toolbutton->subControls & SC_ToolButton) { if (flags & (State_Sunken | State_On | State_Raised) || !autoRaise) { if (toolbutton->features & QStyleOptionToolButton::MenuButtonPopup && autoRaise) { diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index c03c96333a..cb99b58d97 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -2744,10 +2744,15 @@ QMenu::event(QEvent *e) return true; } } break; - case QEvent::ContextMenu: - if (d->delayState.timer.isActive()) { - d->delayState.stop(); - internalDelayedPopup(); + case QEvent::MouseButtonPress: + case QEvent::ContextMenu: { + bool canPopup = true; + if (e->type() == QEvent::MouseButtonPress) + canPopup = (static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton); + if (canPopup && d->delayState.timer.isActive()) { + d->delayState.stop(); + internalDelayedPopup(); + } } break; case QEvent::Resize: { diff --git a/src/widgets/widgets/qwidgetlinecontrol.cpp b/src/widgets/widgets/qwidgetlinecontrol.cpp index 23d52b278d..66f17dbe33 100644 --- a/src/widgets/widgets/qwidgetlinecontrol.cpp +++ b/src/widgets/widgets/qwidgetlinecontrol.cpp @@ -717,7 +717,7 @@ bool QWidgetLineControl::finishChange(int validateFromState, bool update, bool e if (m_transactions.count()) return false; internalUndo(validateFromState); - m_history.resize(m_undoState); + m_history.erase(m_history.begin() + m_undoState, m_history.end()); if (m_modifiedState > m_undoState) m_modifiedState = -1; m_validInput = true; @@ -796,14 +796,14 @@ void QWidgetLineControl::internalSetText(const QString &txt, int pos, bool edite */ void QWidgetLineControl::addCommand(const Command &cmd) { - if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) { - m_history.resize(m_undoState + 2); - m_history[m_undoState++] = Command(Separator, m_cursor, 0, m_selstart, m_selend); - } else { - m_history.resize(m_undoState + 1); - } + m_history.erase(m_history.begin() + m_undoState, m_history.end()); + + if (m_separator && m_undoState && m_history[m_undoState - 1].type != Separator) + m_history.push_back(Command(Separator, m_cursor, 0, m_selstart, m_selend)); + m_separator = false; - m_history[m_undoState++] = cmd; + m_history.push_back(cmd); + m_undoState = int(m_history.size()); } /*! @@ -1563,6 +1563,7 @@ void QWidgetLineControl::processShortcutOverrideEvent(QKeyEvent *ke) if (ke == QKeySequence::Copy || ke == QKeySequence::MoveToNextWord || ke == QKeySequence::MoveToPreviousWord + || ke == QKeySequence::MoveToStartOfLine || ke == QKeySequence::MoveToEndOfLine || ke == QKeySequence::MoveToStartOfDocument || ke == QKeySequence::MoveToEndOfDocument @@ -1957,7 +1958,7 @@ bool QWidgetLineControl::isRedoAvailable() const // Same as with undo. Disabled for password modes. return !m_readOnly && m_echoMode == QLineEdit::Normal - && m_undoState < m_history.size(); + && m_undoState < int(m_history.size()); } QT_END_NAMESPACE diff --git a/src/widgets/widgets/qwidgetlinecontrol_p.h b/src/widgets/widgets/qwidgetlinecontrol_p.h index 34d19d1e77..5e52e29a51 100644 --- a/src/widgets/widgets/qwidgetlinecontrol_p.h +++ b/src/widgets/widgets/qwidgetlinecontrol_p.h @@ -67,6 +67,8 @@ #include "qplatformdefs.h" +#include <vector> + #ifdef DrawText # undef DrawText #endif @@ -469,7 +471,6 @@ private: // undo/redo handling enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection, SetSelection }; struct Command { - inline Command() {} inline Command(CommandType t, int p, QChar c, int ss, int se) : type(t),uc(c),pos(p),selStart(ss),selEnd(se) {} uint type : 4; QChar uc; @@ -477,7 +478,7 @@ private: }; int m_modifiedState; int m_undoState; - QVector<Command> m_history; + std::vector<Command> m_history; void addCommand(const Command& cmd); inline void separate() { m_separator = true; } |