diff options
author | Liang Qi <liang.qi@qt.io> | 2017-03-21 19:07:53 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-03-21 19:07:53 +0100 |
commit | 65faf4565595d91996ddec4af25af5e97c7f0317 (patch) | |
tree | a7415e90db3fa1e46f638e1c31d2f2b9a5d0ec4a | |
parent | a9383ef99a29c333a1edd32695ddc29ea0ba805d (diff) | |
parent | 26bc4ac5cb56ce8f2d3d10125fa9c6a72140573a (diff) |
Merge remote-tracking branch 'origin/5.8' into 5.9
Conflicts:
src/plugins/platforms/eglfs/eglfs-plugin.pro
Change-Id: Id76cdbb41b7758572a3b8ea4dcb40d49bac968db
42 files changed, 900 insertions, 514 deletions
diff --git a/qmake/Makefile.win32 b/qmake/Makefile.win32 index 559870ff0e..7639d09ffd 100644 --- a/qmake/Makefile.win32 +++ b/qmake/Makefile.win32 @@ -21,8 +21,7 @@ CFLAGS_EXTRA = -fms-compatibility-version=19.00.23506 -Wno-microsoft-enum-v !else CXX = cl LINKER = link -CFLAGS_EXTRA = /MP /D_CRT_SECURE_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS \ - /wd4577 $(CFLAGS_CRT) +CFLAGS_EXTRA = /MP /wd4577 $(CFLAGS_CRT) !endif # !win32-icc !if "$(QMAKESPEC)" != "win32-clang-msvc" @@ -37,6 +36,7 @@ CFLAGS_BARE = -c -Fo./ -Fdqmake.pdb \ -I$(INC_PATH) -I$(INC_PATH)\QtCore -I$(INC_PATH)\QtCore\$(QT_VERSION) -I$(INC_PATH)\QtCore\$(QT_VERSION)\QtCore \ -I$(BUILD_PATH)\src\corelib\global \ -I$(SOURCE_PATH)\mkspecs\$(QMAKESPEC) \ + -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS \ -DQT_VERSION_STR=\"$(QT_VERSION)\" -DQT_VERSION_MAJOR=$(QT_MAJOR_VERSION) -DQT_VERSION_MINOR=$(QT_MINOR_VERSION) -DQT_VERSION_PATCH=$(QT_PATCH_VERSION) \ -DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL \ -DQT_NO_FOREACH -DUNICODE diff --git a/src/corelib/arch/qatomic_cxx11.h b/src/corelib/arch/qatomic_cxx11.h index 63b23b71ab..484ec73e7f 100644 --- a/src/corelib/arch/qatomic_cxx11.h +++ b/src/corelib/arch/qatomic_cxx11.h @@ -278,7 +278,7 @@ template <typename X> struct QAtomicOps template <typename T> static bool testAndSetRelaxed(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = Q_NULLPTR) Q_DECL_NOTHROW { - bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_relaxed); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_relaxed, std::memory_order_relaxed); if (currentValue) *currentValue = expectedValue; return tmp; @@ -287,7 +287,7 @@ template <typename X> struct QAtomicOps template <typename T> static bool testAndSetAcquire(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = Q_NULLPTR) Q_DECL_NOTHROW { - bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acquire); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acquire, std::memory_order_acquire); if (currentValue) *currentValue = expectedValue; return tmp; @@ -296,7 +296,7 @@ template <typename X> struct QAtomicOps template <typename T> static bool testAndSetRelease(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = Q_NULLPTR) Q_DECL_NOTHROW { - bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_release); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_release, std::memory_order_relaxed); if (currentValue) *currentValue = expectedValue; return tmp; @@ -305,7 +305,7 @@ template <typename X> struct QAtomicOps template <typename T> static bool testAndSetOrdered(std::atomic<T> &_q_value, T expectedValue, T newValue, T *currentValue = Q_NULLPTR) Q_DECL_NOTHROW { - bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acq_rel); + bool tmp = _q_value.compare_exchange_strong(expectedValue, newValue, std::memory_order_acq_rel, std::memory_order_acquire); if (currentValue) *currentValue = expectedValue; return tmp; diff --git a/src/corelib/io/qfsfileengine_unix.cpp b/src/corelib/io/qfsfileengine_unix.cpp index ca5af924e9..e152b035e2 100644 --- a/src/corelib/io/qfsfileengine_unix.cpp +++ b/src/corelib/io/qfsfileengine_unix.cpp @@ -688,6 +688,19 @@ QDateTime QFSFileEngine::fileTime(FileTime time) const uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFlags flags) { +#if (defined(Q_OS_LINUX) || defined(Q_OS_ANDROID)) && Q_PROCESSOR_WORDSIZE == 4 + // The Linux mmap2 system call on 32-bit takes a page-shifted 32-bit + // integer so the maximum offset is 1 << (32+12) (the shift is always 12, + // regardless of the actual page size). Unfortunately, the mmap64() + // function is known to be broken in all Linux libcs (glibc, uclibc, musl + // and Bionic): all of them do the right shift, but don't confirm that the + // result fits into the 32-bit parameter to the kernel. + + static qint64 MaxFileOffset = (Q_INT64_C(1) << (32+12)) - 1; +#else + static qint64 MaxFileOffset = std::numeric_limits<QT_OFF_T>::max(); +#endif + Q_Q(QFSFileEngine); Q_UNUSED(flags); if (openMode == QIODevice::NotOpen) { @@ -695,7 +708,7 @@ uchar *QFSFileEnginePrivate::map(qint64 offset, qint64 size, QFile::MemoryMapFla return 0; } - if (offset < 0 || offset != qint64(QT_OFF_T(offset)) + if (offset < 0 || offset > MaxFileOffset || size < 0 || quint64(size) > quint64(size_t(-1))) { q->setError(QFile::UnspecifiedError, qt_error_string(int(EINVAL))); return 0; diff --git a/src/corelib/io/qlockfile.cpp b/src/corelib/io/qlockfile.cpp index cb1ff93ad3..48317d07e0 100644 --- a/src/corelib/io/qlockfile.cpp +++ b/src/corelib/io/qlockfile.cpp @@ -44,6 +44,7 @@ #include <QtCore/qthread.h> #include <QtCore/qdeadlinetimer.h> #include <QtCore/qdatetime.h> +#include <QtCore/qfileinfo.h> QT_BEGIN_NAMESPACE @@ -226,6 +227,8 @@ bool QLockFile::tryLock(int timeout) return false; case LockFailedError: if (!d->isLocked && d->isApparentlyStale()) { + if (Q_UNLIKELY(QFileInfo(d->fileName).lastModified() > QDateTime::currentDateTime())) + qInfo("QLockFile: Lock file '%ls' has a modification time in the future", qUtf16Printable(d->fileName)); // Stale lock from another thread/process // Ensure two processes don't remove it at the same time QLockFile rmlock(d->fileName + QLatin1String(".rmlock")); diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index 3a80014c00..5a02741727 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -247,7 +247,7 @@ bool QLockFilePrivate::isApparentlyStale() const } } const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); - return staleLockTime > 0 && age > staleLockTime; + return staleLockTime > 0 && qAbs(age) > staleLockTime; } QString QLockFilePrivate::processNameByPid(qint64 pid) diff --git a/src/corelib/io/qlockfile_win.cpp b/src/corelib/io/qlockfile_win.cpp index baaff8da17..4b43181686 100644 --- a/src/corelib/io/qlockfile_win.cpp +++ b/src/corelib/io/qlockfile_win.cpp @@ -160,7 +160,7 @@ bool QLockFilePrivate::isApparentlyStale() const Q_UNUSED(appname); #endif // Q_OS_WINRT const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime()); - return staleLockTime > 0 && age > staleLockTime; + return staleLockTime > 0 && qAbs(age) > staleLockTime; } QString QLockFilePrivate::processNameByPid(qint64 pid) diff --git a/src/corelib/io/qstandardpaths_mac.mm b/src/corelib/io/qstandardpaths_mac.mm index a293d4862f..e25339a7d1 100644 --- a/src/corelib/io/qstandardpaths_mac.mm +++ b/src/corelib/io/qstandardpaths_mac.mm @@ -204,13 +204,14 @@ QStringList QStandardPaths::standardLocations(StandardLocation type) CFBundleRef mainBundle = CFBundleGetMainBundle(); if (mainBundle) { CFURLRef bundleUrl = CFBundleCopyBundleURL(mainBundle); - CFStringRef cfBundlePath = CFURLCopyPath(bundleUrl); + CFStringRef cfBundlePath = CFURLCopyFileSystemPath(bundleUrl, kCFURLPOSIXPathStyle); QString bundlePath = QString::fromCFString(cfBundlePath); CFRelease(cfBundlePath); CFRelease(bundleUrl); CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(mainBundle); - CFStringRef cfResourcesPath = CFURLCopyPath(resourcesUrl); + CFStringRef cfResourcesPath = CFURLCopyFileSystemPath(resourcesUrl, + kCFURLPOSIXPathStyle); QString resourcesPath = QString::fromCFString(cfResourcesPath); CFRelease(cfResourcesPath); CFRelease(resourcesUrl); diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 18ad59f1cb..b5772b5ce2 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -4169,12 +4169,15 @@ QUrl QUrl::fromUserInput(const QString &userInput, const QString &workingDirecto return url; } + const QFileInfo fileInfo(QDir(workingDirectory), userInput); + if (fileInfo.exists()) { + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + } + QUrl url = QUrl(userInput, QUrl::TolerantMode); // Check both QUrl::isRelative (to detect full URLs) and QDir::isAbsolutePath (since on Windows drive letters can be interpreted as schemes) - if (url.isRelative() && !QDir::isAbsolutePath(userInput)) { - QFileInfo fileInfo(QDir(workingDirectory), userInput); - if ((options & AssumeLocalFile) || fileInfo.exists()) - return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + if ((options & AssumeLocalFile) && url.isRelative() && !QDir::isAbsolutePath(userInput)) { + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); } return fromUserInput(trimmedString); diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 79146dac34..74fa2d8d50 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -407,7 +407,9 @@ void QEventDispatcherWin32Private::unregisterTimer(WinTimerInfo *t) } else if (internalHwnd) { KillTimer(internalHwnd, t->timerId); } - delete t; + t->timerId = -1; + if (!t->inTimerEvent) + delete t; } void QEventDispatcherWin32Private::sendTimerEvent(int timerId) @@ -424,8 +426,9 @@ void QEventDispatcherWin32Private::sendTimerEvent(int timerId) QCoreApplication::sendEvent(t->obj, &e); // timer could have been removed - t = timerDict.value(timerId); - if (t) { + if (t->timerId == -1) { + delete t; + } else { t->inTimerEvent = false; } } @@ -1013,8 +1016,10 @@ bool QEventDispatcherWin32::event(QEvent *e) QTimerEvent te(zte->timerId()); QCoreApplication::sendEvent(t->obj, &te); - t = d->timerDict.value(zte->timerId()); - if (t) { + // timer could have been removed + if (t->timerId == -1) { + delete t; + } else { if (t->interval == 0 && t->inTimerEvent) { // post the next zero timer event as long as the timer was not restarted QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId())); diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 38e0d6055c..fc8d7dcfea 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -1341,7 +1341,6 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data) case QMetaType::UnknownType: case QMetaType::Void: case QMetaType::VoidStar: - case QMetaType::Nullptr: case QMetaType::QObjectStar: case QMetaType::QModelIndex: case QMetaType::QPersistentModelIndex: @@ -1350,6 +1349,8 @@ bool QMetaType::save(QDataStream &stream, int type, const void *data) case QMetaType::QJsonArray: case QMetaType::QJsonDocument: return false; + case QMetaType::Nullptr: + return true; case QMetaType::Long: stream << qlonglong(*static_cast<const long *>(data)); break; @@ -1563,7 +1564,6 @@ bool QMetaType::load(QDataStream &stream, int type, void *data) case QMetaType::UnknownType: case QMetaType::Void: case QMetaType::VoidStar: - case QMetaType::Nullptr: case QMetaType::QObjectStar: case QMetaType::QModelIndex: case QMetaType::QPersistentModelIndex: @@ -1572,6 +1572,8 @@ bool QMetaType::load(QDataStream &stream, int type, void *data) case QMetaType::QJsonArray: case QMetaType::QJsonDocument: return false; + case QMetaType::Nullptr: + return true; case QMetaType::Long: { qlonglong l; stream >> l; diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 5d5ea4c8a1..1d3293e85e 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -624,9 +624,9 @@ QT_BEGIN_NAMESPACE Constructs a QChar corresponding to ASCII/Latin-1 character \a ch. \note This constructor is not available when \c QT_NO_CAST_FROM_ASCII - is defined. + or QT_RESTRICTED_CAST_FROM_ASCII is defined. - \sa QT_NO_CAST_FROM_ASCII + \sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII */ /*! diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index a83e5e6f98..81ef67d116 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -578,17 +578,21 @@ Q_DECL_CONSTEXPR inline bool operator>=(QChar c1, QChar c2) Q_DECL_NOTHROW { ret Q_DECL_CONSTEXPR inline bool operator> (QChar c1, QChar c2) Q_DECL_NOTHROW { return operator< (c2, c1); } Q_DECL_CONSTEXPR inline bool operator<=(QChar c1, QChar c2) Q_DECL_NOTHROW { return !operator< (c2, c1); } -// disambiguate QChar == int (but only that, so constrain template to exactly 'int'): -template <typename T> -Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead") -Q_DECL_CONSTEXPR inline -typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, int>::value, bool>::type -operator==(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs == QChar(rhs); } -template <typename T> -Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead") -Q_DECL_CONSTEXPR inline -typename std::enable_if<std::is_same<typename std::remove_cv<T>::type, int>::value, bool>::type -operator!=(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs != QChar(rhs); } + +Q_DECL_CONSTEXPR inline bool operator==(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return lhs.isNull(); } +Q_DECL_CONSTEXPR inline bool operator< (QChar, std::nullptr_t) Q_DECL_NOTHROW { return false; } +Q_DECL_CONSTEXPR inline bool operator==(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return rhs.isNull(); } +Q_DECL_CONSTEXPR inline bool operator< (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !rhs.isNull(); } + +Q_DECL_CONSTEXPR inline bool operator!=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator==(lhs, nullptr); } +Q_DECL_CONSTEXPR inline bool operator>=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (lhs, nullptr); } +Q_DECL_CONSTEXPR inline bool operator> (QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return operator< (nullptr, lhs); } +Q_DECL_CONSTEXPR inline bool operator<=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (nullptr, lhs); } + +Q_DECL_CONSTEXPR inline bool operator!=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator==(nullptr, rhs); } +Q_DECL_CONSTEXPR inline bool operator>=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (nullptr, rhs); } +Q_DECL_CONSTEXPR inline bool operator> (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return operator< (rhs, nullptr); } +Q_DECL_CONSTEXPR inline bool operator<=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (rhs, nullptr); } #ifndef QT_NO_DATASTREAM Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QChar); diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index c8aa4fbc89..62dd25e072 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -1243,6 +1243,49 @@ end: #endif // QT_NO_DATESTRING #ifndef QT_NO_TEXTDATE + +/* + \internal + \brief Returns the index in \a entries with the best prefix match to \a text + + Scans \a entries looking for an entry overlapping \a text as much as possible + (an exact match beats any prefix match; a match of the full entry as prefix of + text beats any entry but one matching a longer prefix; otherwise, the match of + longest prefix wins, earlier entries beating later on a draw). Records the + length of overlap in *used (if \a used is non-NULL) and the first entry that + overlapped this much in *usedText (if \a usedText is non-NULL). + */ +static int findTextEntry(const QString &text, const QVector<QString> &entries, QString *usedText, int *used) +{ + if (text.isEmpty()) + return -1; + + int bestMatch = -1; + int bestCount = 0; + for (int n = 0; n < entries.size(); ++n) + { + const QString &name = entries.at(n); + + const int limit = qMin(text.size(), name.size()); + int i = 0; + while (i < limit && text.at(i) == name.at(i).toLower()) + ++i; + // Full match beats an equal prefix match: + if (i > bestCount || (i == bestCount && i == name.size())) { + bestCount = i; + bestMatch = n; + if (i == name.size() && i == text.size()) + break; // Exact match, name == text, wins. + } + } + if (usedText && bestMatch != -1) + *usedText = entries.at(bestMatch); + if (used) + *used = bestCount; + + return bestMatch; +} + /*! \internal finds the first possible monthname that \a str1 can @@ -1252,99 +1295,40 @@ end: int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionIndex, QString *usedMonth, int *used) const { - int bestMatch = -1; - int bestCount = 0; - if (!str1.isEmpty()) { - const SectionNode &sn = sectionNode(sectionIndex); - if (sn.type != MonthSection) { - qWarning("QDateTimeParser::findMonth Internal error"); - return -1; - } - - QLocale::FormatType type = sn.count == 3 ? QLocale::ShortFormat : QLocale::LongFormat; - QLocale l = locale(); + const SectionNode &sn = sectionNode(sectionIndex); + if (sn.type != MonthSection) { + qWarning("QDateTimeParser::findMonth Internal error"); + return -1; + } - for (int month=startMonth; month<=12; ++month) { - const QString monthName = l.monthName(month, type); - QString str2 = monthName.toLower(); + QLocale::FormatType type = sn.count == 3 ? QLocale::ShortFormat : QLocale::LongFormat; + QLocale l = locale(); + QVector<QString> monthNames; + monthNames.reserve(13 - startMonth); + for (int month = startMonth; month <= 12; ++month) + monthNames.append(l.monthName(month, type)); - if (str1.startsWith(str2)) { - if (used) { - QDTPDEBUG << "used is set to" << str2.size(); - *used = str2.size(); - } - if (usedMonth) - *usedMonth = monthName; - - return month; - } - if (context == FromString) - continue; - - const int limit = qMin(str1.size(), str2.size()); - - QDTPDEBUG << "limit is" << limit << str1 << str2; - bool equal = true; - for (int i=0; i<limit; ++i) { - if (str1.at(i) != str2.at(i)) { - equal = false; - if (i > bestCount) { - bestCount = i; - bestMatch = month; - } - break; - } - } - if (equal) { - if (used) - *used = limit; - if (usedMonth) - *usedMonth = monthName; - return month; - } - } - if (usedMonth && bestMatch != -1) - *usedMonth = l.monthName(bestMatch, type); - } - if (used) { - QDTPDEBUG << "used is set to" << bestCount; - *used = bestCount; - } - return bestMatch; + const int index = findTextEntry(str1, monthNames, usedMonth, used); + return index < 0 ? index : index + startMonth; } int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex, QString *usedDay, int *used) const { - int bestMatch = -1; - int bestCount = 0; - if (!str1.isEmpty()) { - const SectionNode &sn = sectionNode(sectionIndex); - if (!(sn.type & DaySectionMask)) { - qWarning("QDateTimeParser::findDay Internal error"); - return -1; - } - const QLocale l = locale(); - for (int day=startDay; day<=7; ++day) { - const QString dayName = l.dayName(day, sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat); - const QString str2 = dayName.toLower(); - - const int limit = qMin(str1.size(), str2.size()); - int i = 0; - while (i < limit && str1.at(i) == str2.at(i)) - ++i; - if (i > bestCount) { - bestCount = i; - bestMatch = day; - } - } - if (usedDay && bestMatch != -1) { - *usedDay = l.dayName(bestMatch, sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat); - } + const SectionNode &sn = sectionNode(sectionIndex); + if (!(sn.type & DaySectionMask)) { + qWarning("QDateTimeParser::findDay Internal error"); + return -1; } - if (used) - *used = bestCount; - return bestMatch; + QLocale::FormatType type = sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat; + QLocale l = locale(); + QVector<QString> daysOfWeek; + daysOfWeek.reserve(8 - startDay); + for (int day = startDay; day <= 7; ++day) + daysOfWeek.append(l.dayName(day, type)); + + const int index = findTextEntry(str1, daysOfWeek, usedDay, used); + return index < 0 ? index : index + startDay; } #endif // QT_NO_TEXTDATE diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index c94ea0922a..d44bfabc04 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -2697,26 +2697,29 @@ void QWindowPrivate::setCursor(const QCursor *newCursor) cursor = QCursor(Qt::ArrowCursor); hasCursor = false; } - // Only attempt to set cursor and emit signal if there is an actual platform cursor - QScreen* screen = q->screen(); - if (screen && screen->handle()->cursor()) { - applyCursor(); + // Only attempt to emit signal if there is an actual platform cursor + if (applyCursor()) { QEvent event(QEvent::CursorChange); QGuiApplication::sendEvent(q, &event); } } -void QWindowPrivate::applyCursor() +// Apply the cursor and returns true iff the platform cursor exists +bool QWindowPrivate::applyCursor() { Q_Q(QWindow); - if (platformWindow) { - if (QPlatformCursor *platformCursor = q->screen()->handle()->cursor()) { + if (QScreen *screen = q->screen()) { + if (QPlatformCursor *platformCursor = screen->handle()->cursor()) { + if (!platformWindow) + return true; QCursor *c = QGuiApplication::overrideCursor(); if (!c && hasCursor) c = &cursor; platformCursor->changeCursor(c, q); + return true; } } + return false; } #endif // QT_NO_CURSOR diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index 59016e4551..dd282a671d 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -118,7 +118,7 @@ public: void maybeQuitOnLastWindowClosed(); #ifndef QT_NO_CURSOR void setCursor(const QCursor *c = 0); - void applyCursor(); + bool applyCursor(); #endif void deliverUpdateRequest(); diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index c2458152a3..72feffda8c 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -82,27 +82,31 @@ QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(const QString &host : state(RunningState), networkLayerState(Unknown), hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true) + , activeChannelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2 #ifndef QT_NO_SSL -, channelCount((type == QHttpNetworkConnection::ConnectionTypeSPDY || type == QHttpNetworkConnection::ConnectionTypeHTTP2) - ? 1 : defaultHttpChannelCount) -#else -, channelCount(type == QHttpNetworkConnection::ConnectionTypeHTTP2 ? 1 : defaultHttpChannelCount) -#endif // QT_NO_SSL + || type == QHttpNetworkConnection::ConnectionTypeSPDY +#endif + ? 1 : defaultHttpChannelCount) + , channelCount(defaultHttpChannelCount) #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif , preConnectRequests(0) , connectionType(type) { + // We allocate all 6 channels even if it's SPDY or HTTP/2 enabled + // connection: in case the protocol negotiation via NPN/ALPN fails, + // we will have normally working HTTP/1.1. + Q_ASSERT(channelCount >= activeChannelCount); channels = new QHttpNetworkConnectionChannel[channelCount]; } -QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 channelCount, const QString &hostName, +QHttpNetworkConnectionPrivate::QHttpNetworkConnectionPrivate(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt, QHttpNetworkConnection::ConnectionType type) : state(RunningState), networkLayerState(Unknown), hostName(hostName), port(port), encrypt(encrypt), delayIpv4(true), - channelCount(channelCount) + activeChannelCount(connectionCount), channelCount(connectionCount) #ifndef QT_NO_NETWORKPROXY , networkProxy(QNetworkProxy::NoProxy) #endif @@ -147,7 +151,7 @@ void QHttpNetworkConnectionPrivate::pauseConnection() state = PausedState; // Disable all socket notifiers - for (int i = 0; i < channelCount; i++) { + for (int i = 0; i < activeChannelCount; i++) { if (channels[i].socket) { #ifndef QT_NO_SSL if (encrypt) @@ -163,7 +167,7 @@ void QHttpNetworkConnectionPrivate::resumeConnection() { state = RunningState; // Enable all socket notifiers - for (int i = 0; i < channelCount; i++) { + for (int i = 0; i < activeChannelCount; i++) { if (channels[i].socket) { #ifndef QT_NO_SSL if (encrypt) @@ -184,7 +188,7 @@ void QHttpNetworkConnectionPrivate::resumeConnection() int QHttpNetworkConnectionPrivate::indexOf(QAbstractSocket *socket) const { - for (int i = 0; i < channelCount; ++i) + for (int i = 0; i < activeChannelCount; ++i) if (channels[i].socket == socket) return i; @@ -210,7 +214,7 @@ bool QHttpNetworkConnectionPrivate::shouldEmitChannelError(QAbstractSocket *sock channels[otherSocket].ensureConnection(); } - if (channelCount == 1) { + if (activeChannelCount < channelCount) { if (networkLayerState == HostLookupPending || networkLayerState == IPv4or6) networkLayerState = QHttpNetworkConnectionPrivate::Unknown; channels[0].close(); @@ -405,7 +409,7 @@ void QHttpNetworkConnectionPrivate::copyCredentials(int fromChannel, QAuthentica // select another channel QAuthenticator* otherAuth = 0; - for (int i = 0; i < channelCount; ++i) { + for (int i = 0; i < activeChannelCount; ++i) { if (i == fromChannel) continue; if (isProxy) @@ -900,7 +904,7 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply) Q_Q(QHttpNetworkConnection); // check if the reply is currently being processed or it is pipelined in - for (int i = 0; i < channelCount; ++i) { + for (int i = 0; i < activeChannelCount; ++i) { // is the reply associated the currently processing of this channel? if (channels[i].reply == reply) { channels[i].reply = 0; @@ -1003,7 +1007,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() return; //resend the necessary ones. - for (int i = 0; i < channelCount; ++i) { + for (int i = 0; i < activeChannelCount; ++i) { if (channels[i].resendCurrent && (channels[i].state != QHttpNetworkConnectionChannel::ClosingState)) { channels[i].resendCurrent = false; @@ -1023,7 +1027,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() return; // try to get a free AND connected socket - for (int i = 0; i < channelCount; ++i) { + for (int i = 0; i < activeChannelCount; ++i) { if (channels[i].socket) { if (!channels[i].reply && !channels[i].isSocketBusy() && channels[i].socket->state() == QAbstractSocket::ConnectedState) { if (dequeueRequest(channels[i].socket)) @@ -1061,7 +1065,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() // return fast if there is nothing to pipeline if (highPriorityQueue.isEmpty() && lowPriorityQueue.isEmpty()) return; - for (int i = 0; i < channelCount; i++) + for (int i = 0; i < activeChannelCount; i++) if (channels[i].socket && channels[i].socket->state() == QAbstractSocket::ConnectedState) fillPipeline(channels[i].socket); @@ -1077,7 +1081,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() int normalRequests = queuedRequests - preConnectRequests; neededOpenChannels = qMax(normalRequests, preConnectRequests); } - for (int i = 0; i < channelCount && neededOpenChannels > 0; ++i) { + for (int i = 0; i < activeChannelCount && neededOpenChannels > 0; ++i) { bool connectChannel = false; if (channels[i].socket) { if ((channels[i].socket->state() == QAbstractSocket::ConnectingState) @@ -1107,7 +1111,7 @@ void QHttpNetworkConnectionPrivate::_q_startNextRequest() void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply) { - for (int i = 0 ; i < channelCount; ++i) { + for (int i = 0 ; i < activeChannelCount; ++i) { if (channels[i].reply == reply) { // emulate a readyRead() from the socket QMetaObject::invokeMethod(&channels[i], "_q_readyRead", Qt::QueuedConnection); @@ -1226,7 +1230,7 @@ void QHttpNetworkConnectionPrivate::_q_hostLookupFinished(const QHostInfo &info) // connection will then be disconnected. void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup() { - if (channelCount > 1) { + if (activeChannelCount > 1) { // At this time all channels should be unconnected. Q_ASSERT(!channels[0].isSocketBusy()); Q_ASSERT(!channels[1].isSocketBusy()); @@ -1264,7 +1268,7 @@ void QHttpNetworkConnectionPrivate::startNetworkLayerStateLookup() void QHttpNetworkConnectionPrivate::networkLayerDetected(QAbstractSocket::NetworkLayerProtocol protocol) { - for (int i = 0 ; i < channelCount; ++i) { + for (int i = 0 ; i < activeChannelCount; ++i) { if ((channels[i].networkLayerPreference != protocol) && (channels[i].state == QHttpNetworkConnectionChannel::ConnectingState)) { channels[i].close(); } @@ -1361,7 +1365,7 @@ void QHttpNetworkConnection::setCacheProxy(const QNetworkProxy &networkProxy) d->networkProxy = networkProxy; // update the authenticator if (!d->networkProxy.user().isEmpty()) { - for (int i = 0; i < d->channelCount; ++i) { + for (int i = 0; i < d->activeChannelCount; ++i) { d->channels[i].proxyAuthenticator.setUser(d->networkProxy.user()); d->channels[i].proxyAuthenticator.setPassword(d->networkProxy.password()); } @@ -1377,7 +1381,7 @@ QNetworkProxy QHttpNetworkConnection::cacheProxy() const void QHttpNetworkConnection::setTransparentProxy(const QNetworkProxy &networkProxy) { Q_D(QHttpNetworkConnection); - for (int i = 0; i < d->channelCount; ++i) + for (int i = 0; i < d->activeChannelCount; ++i) d->channels[i].setProxy(networkProxy); } @@ -1409,7 +1413,7 @@ void QHttpNetworkConnection::setSslConfiguration(const QSslConfiguration &config return; // set the config on all channels - for (int i = 0; i < d->channelCount; ++i) + for (int i = 0; i < d->activeChannelCount; ++i) d->channels[i].setSslConfiguration(config); } @@ -1432,7 +1436,7 @@ void QHttpNetworkConnection::ignoreSslErrors(int channel) return; if (channel == -1) { // ignore for all channels - for (int i = 0; i < d->channelCount; ++i) { + for (int i = 0; i < d->activeChannelCount; ++i) { d->channels[i].ignoreSslErrors(); } @@ -1448,7 +1452,7 @@ void QHttpNetworkConnection::ignoreSslErrors(const QList<QSslError> &errors, int return; if (channel == -1) { // ignore for all channels - for (int i = 0; i < d->channelCount; ++i) { + for (int i = 0; i < d->activeChannelCount; ++i) { d->channels[i].ignoreSslErrors(errors); } diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index 430c715717..3dd9bde9bd 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -243,6 +243,9 @@ public: bool encrypt; bool delayIpv4; + // Number of channels we are trying to use at the moment: + int activeChannelCount; + // The total number of channels we reserved: const int channelCount; QTimer delayedConnectionTimer; QHttpNetworkConnectionChannel *channels; // parallel connections to the server diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 668409a988..c86cc9d8c9 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -1083,12 +1083,36 @@ void QHttpNetworkConnectionChannel::_q_encrypted() } } Q_FALLTHROUGH(); - case QSslConfiguration::NextProtocolNegotiationNone: + case QSslConfiguration::NextProtocolNegotiationNone: { protocolHandler.reset(new QHttpProtocolHandler(this)); + + QList<QByteArray> protocols = sslConfiguration.allowedNextProtocols(); + const int nProtocols = protocols.size(); + // Clear the protocol that we failed to negotiate, so we do not try + // it again on other channels that our connection can create/open. + if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeHTTP2) + protocols.removeAll(QSslConfiguration::ALPNProtocolHTTP2); + else if (connection->connectionType() == QHttpNetworkConnection::ConnectionTypeSPDY) + protocols.removeAll(QSslConfiguration::NextProtocolSpdy3_0); + + if (nProtocols > protocols.size()) { + sslConfiguration.setAllowedNextProtocols(protocols); + const int channelCount = connection->d_func()->channelCount; + for (int i = 0; i < channelCount; ++i) + connection->d_func()->channels[i].setSslConfiguration(sslConfiguration); + } + connection->setConnectionType(QHttpNetworkConnection::ConnectionTypeHTTP); - // re-queue requests from SPDY queue to HTTP queue, if any - requeueSpdyRequests(); + // We use only one channel for SPDY or HTTP/2, but normally six for + // HTTP/1.1 - let's restore this number to the reserved number of + // channels: + if (connection->d_func()->activeChannelCount < connection->d_func()->channelCount) { + connection->d_func()->activeChannelCount = connection->d_func()->channelCount; + // re-queue requests from SPDY queue to HTTP queue, if any + requeueSpdyRequests(); + } break; + } default: emitFinishedWithError(QNetworkReply::SslHandshakeFailedError, "detected unknown Next Protocol Negotiation protocol"); diff --git a/src/network/network.pro b/src/network/network.pro index 75105bd681..98fbf82275 100644 --- a/src/network/network.pro +++ b/src/network/network.pro @@ -22,16 +22,18 @@ include(ssl/ssl.pri) QMAKE_LIBS += $$QMAKE_LIBS_NETWORK -ANDROID_BUNDLED_JAR_DEPENDENCIES = \ - jar/QtAndroidBearer-bundled.jar -ANDROID_JAR_DEPENDENCIES = \ - jar/QtAndroidBearer.jar -ANDROID_LIB_DEPENDENCIES = \ - plugins/bearer/libqandroidbearer.so -MODULE_PLUGIN_TYPES = \ - bearer -ANDROID_PERMISSIONS += \ - android.permission.ACCESS_NETWORK_STATE +qtConfig(bearermanagement) { + ANDROID_BUNDLED_JAR_DEPENDENCIES = \ + jar/QtAndroidBearer-bundled.jar + ANDROID_JAR_DEPENDENCIES = \ + jar/QtAndroidBearer.jar + ANDROID_LIB_DEPENDENCIES = \ + plugins/bearer/libqandroidbearer.so + MODULE_PLUGIN_TYPES = \ + bearer + ANDROID_PERMISSIONS += \ + android.permission.ACCESS_NETWORK_STATE +} MODULE_WINRT_CAPABILITIES = \ internetClient \ diff --git a/src/plugins/bearer/generic/generic.pro b/src/plugins/bearer/generic/generic.pro index 02b3e96bfa..f30bdc4951 100644 --- a/src/plugins/bearer/generic/generic.pro +++ b/src/plugins/bearer/generic/generic.pro @@ -12,7 +12,7 @@ SOURCES += qgenericengine.cpp \ OTHER_FILES += generic.json -win32:!winrt:LIBS += -lIphlpapi +win32:!winrt:LIBS += -liphlpapi PLUGIN_TYPE = bearer PLUGIN_CLASS_NAME = QGenericEnginePlugin diff --git a/src/plugins/platforms/android/androidjniaccessibility.cpp b/src/plugins/platforms/android/androidjniaccessibility.cpp index 3b1ce6d21d..eeaecd53b4 100644 --- a/src/plugins/platforms/android/androidjniaccessibility.cpp +++ b/src/plugins/platforms/android/androidjniaccessibility.cpp @@ -49,6 +49,7 @@ #include <QtCore/qmath.h> #include <QtCore/private/qjnihelpers_p.h> #include <QtCore/private/qjni_p.h> +#include <QtGui/private/qhighdpiscaling_p.h> #include "qdebug.h" @@ -137,7 +138,7 @@ namespace QtAndroidAccessibility QRect rect; QAccessibleInterface *iface = interfaceFromId(objectId); if (iface && iface->isValid()) { - rect = iface->rect(); + rect = QHighDpi::toNativePixels(iface->rect(), iface->window()); } jclass rectClass = env->FindClass("android/graphics/Rect"); @@ -150,11 +151,13 @@ namespace QtAndroidAccessibility { QAccessibleInterface *root = interfaceFromId(-1); if (root) { - QAccessibleInterface *child = root->childAt((int)x, (int)y); + QPoint pos = QHighDpi::fromNativePixels(QPoint(int(x), int(y)), root->window()); + + QAccessibleInterface *child = root->childAt(pos.x(), pos.y()); QAccessibleInterface *lastChild = 0; while (child && (child != lastChild)) { lastChild = child; - child = child->childAt((int)x, (int)y); + child = child->childAt(pos.x(), pos.y()); } if (lastChild) return QAccessible::uniqueId(lastChild); diff --git a/src/plugins/platforms/eglfs/eglfs-plugin.pro b/src/plugins/platforms/eglfs/eglfs-plugin.pro index 3844328ee0..ec229796e5 100644 --- a/src/plugins/platforms/eglfs/eglfs-plugin.pro +++ b/src/plugins/platforms/eglfs/eglfs-plugin.pro @@ -4,6 +4,9 @@ QT += eglfsdeviceintegration-private CONFIG += egl +# Avoid X11 header collision, use generic EGL native types +DEFINES += QT_EGL_NO_X11 + SOURCES += $$PWD/qeglfsmain.cpp OTHER_FILES += $$PWD/eglfs.json diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 3f0493669f..f6fa903ec2 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -898,19 +898,17 @@ void QXcbWindow::hide() } } -static QWindow *tlWindow(QWindow *window) -{ - if (window && window->parent()) - return tlWindow(window->parent()); - return window; -} - bool QXcbWindow::relayFocusToModalWindow() const { - QWindow *w = tlWindow(static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver()); - QWindow *modal_window = 0; - if (QGuiApplicationPrivate::instance()->isWindowBlocked(w,&modal_window) && modal_window != w) { - modal_window->requestActivate(); + QWindow *w = static_cast<QWindowPrivate *>(QObjectPrivate::get(window()))->eventReceiver(); + // get top-level window + while (w && w->parent()) + w = w->parent(); + + QWindow *modalWindow = 0; + const bool blocked = QGuiApplicationPrivate::instance()->isWindowBlocked(w, &modalWindow); + if (blocked && modalWindow != w) { + modalWindow->requestActivate(); connection()->flush(); return true; } diff --git a/src/plugins/sqldrivers/psql/qsql_psql.cpp b/src/plugins/sqldrivers/psql/qsql_psql.cpp index e0f9222902..19de9a8003 100644 --- a/src/plugins/sqldrivers/psql/qsql_psql.cpp +++ b/src/plugins/sqldrivers/psql/qsql_psql.cpp @@ -50,7 +50,7 @@ #include <qsqlquery.h> #include <qsocketnotifier.h> #include <qstringlist.h> -#include <qmutex.h> +#include <qlocale.h> #include <QtSql/private/qsqlresult_p.h> #include <QtSql/private/qsqldriver_p.h> @@ -618,13 +618,10 @@ static QString qCreateParamString(const QVector<QVariant> &boundValues, const QS return params; } -Q_GLOBAL_STATIC(QMutex, qMutex) QString qMakePreparedStmtId() { - qMutex()->lock(); - static unsigned int qPreparedStmtCount = 0; - QString id = QLatin1String("qpsqlpstmt_") + QString::number(++qPreparedStmtCount, 16); - qMutex()->unlock(); + static QBasicAtomicInt qPreparedStmtCount = Q_BASIC_ATOMIC_INITIALIZER(0); + QString id = QLatin1String("qpsqlpstmt_") + QString::number(qPreparedStmtCount.fetchAndAddRelaxed(1) + 1, 16); return id; } @@ -1311,7 +1308,9 @@ QString QPSQLDriver::formatValue(const QSqlField &field, bool trimStrings) const // we force the value to be considered with a timezone information, and we force it to be UTC // this is safe since postgresql stores only the UTC value and not the timezone offset (only used // while parsing), so we have correct behavior in both case of with timezone and without tz - r = QLatin1String("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + field.value().toDateTime().toUTC().toString(QLatin1String("yyyy-MM-ddThh:mm:ss.zzz")) + QLatin1Char('Z') + QLatin1Char('\''); + r = QLatin1String("TIMESTAMP WITH TIME ZONE ") + QLatin1Char('\'') + + QLocale::c().toString(field.value().toDateTime().toUTC(), QLatin1String("yyyy-MM-ddThh:mm:ss.zzz")) + + QLatin1Char('Z') + QLatin1Char('\''); } else { r = QLatin1String("NULL"); } diff --git a/src/printsupport/configure.json b/src/printsupport/configure.json index 93d345840f..cd775644c9 100644 --- a/src/printsupport/configure.json +++ b/src/printsupport/configure.json @@ -48,7 +48,7 @@ "label": "QPrinter", "purpose": "Provides a printer backend of QPainter.", "section": "Painting", - "condition": "!config.android && !config.uikit && !config.winrt && features.picture && features.temporaryfile && features.pdf", + "condition": "!config.uikit && !config.winrt && features.picture && features.temporaryfile && features.pdf", "output": [ "publicFeature", "feature" ] }, "printpreviewwidget": { diff --git a/src/testlib/qtestsystem.h b/src/testlib/qtestsystem.h index 4c611aab6b..f38a156936 100644 --- a/src/testlib/qtestsystem.h +++ b/src/testlib/qtestsystem.h @@ -114,14 +114,14 @@ namespace QTest #endif #ifdef QT_WIDGETS_LIB - inline static bool qWaitForWindowActive(QWidget *widget, int timeout = 1000) + inline static bool qWaitForWindowActive(QWidget *widget, int timeout = 5000) { if (QWindow *window = widget->window()->windowHandle()) return qWaitForWindowActive(window, timeout); return false; } - inline static bool qWaitForWindowExposed(QWidget *widget, int timeout = 1000) + inline static bool qWaitForWindowExposed(QWidget *widget, int timeout = 5000) { if (QWindow *window = widget->window()->windowHandle()) return qWaitForWindowExposed(window, timeout); @@ -131,7 +131,7 @@ namespace QTest #if QT_DEPRECATED_SINCE(5, 0) # ifdef QT_WIDGETS_LIB - QT_DEPRECATED inline static bool qWaitForWindowShown(QWidget *widget, int timeout = 1000) + QT_DEPRECATED inline static bool qWaitForWindowShown(QWidget *widget, int timeout = 5000) { return qWaitForWindowExposed(widget, timeout); } diff --git a/src/tools/qlalr/cppgenerator.cpp b/src/tools/qlalr/cppgenerator.cpp index efceb8c520..ed0f53d43e 100644 --- a/src/tools/qlalr/cppgenerator.cpp +++ b/src/tools/qlalr/cppgenerator.cpp @@ -36,6 +36,29 @@ #include <QtCore/qfile.h> #include <QtCore/qmap.h> +namespace { + +void generateSeparator(int i, QTextStream &out) +{ + if (!(i % 10)) { + if (i) + out << ","; + out << endl << " "; + } else { + out << ", "; + } +} + +void generateList(const QVector<int> &list, QTextStream &out) +{ + for (int i = 0; i < list.size(); ++i) { + generateSeparator(i, out); + + out << list[i]; + } +} + +} QString CppGenerator::copyrightHeader() const { @@ -47,7 +70,7 @@ QString CppGenerator::copyrightHeader() const "**\n" "** This file is part of the Qt Toolkit.\n" "**\n" - "** $QT_BEGIN_LICENSE:LGPL$\n" + "** $QT_BEGIN_LICENSE:GPL-EXCEPT$\n" "** Commercial License Usage\n" "** Licensees holding valid commercial Qt licenses may use this file in\n" "** accordance with the commercial license agreement provided with the\n" @@ -56,24 +79,13 @@ QString CppGenerator::copyrightHeader() const "** and conditions see https://www.qt.io/terms-conditions. For further\n" "** information use the contact form at https://www.qt.io/contact-us.\n" "**\n" - "** GNU Lesser General Public License Usage\n" - "** Alternatively, this file may be used under the terms of the GNU Lesser\n" - "** General Public License version 3 as published by the Free Software\n" - "** Foundation and appearing in the file LICENSE.LGPL3 included in the\n" - "** packaging of this file. Please review the following information to\n" - "** ensure the GNU Lesser General Public License version 3 requirements\n" - "** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.\n" - "**\n" "** GNU General Public License Usage\n" "** Alternatively, this file may be used under the terms of the GNU\n" - "** General Public License version 2.0 or (at your option) the GNU General\n" - "** Public license version 3 or any later version approved by the KDE Free\n" - "** Qt Foundation. The licenses are as published by the Free Software\n" - "** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3\n" + "** General Public License version 3 as published by the Free Software\n" + "** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT\n" "** included in the packaging of this file. Please review the following\n" "** information to ensure the GNU General Public License requirements will\n" - "** be met: https://www.gnu.org/licenses/gpl-2.0.html and\n" - "** https://www.gnu.org/licenses/gpl-3.0.html.\n" + "** be met: https://www.gnu.org/licenses/gpl-3.0.html.\n" "**\n" "** $QT_END_LICENSE$\n" "**\n" @@ -446,7 +458,7 @@ void CppGenerator::generateDecl (QTextStream &out) out << "class " << grammar.table_name << endl << "{" << endl << "public:" << endl - << " enum VariousConstants {" << endl; + << " enum VariousConstants {" << endl; for (Name t : qAsConst(grammar.terminals)) { @@ -462,59 +474,59 @@ void CppGenerator::generateDecl (QTextStream &out) else name.prepend (grammar.token_prefix); - out << " " << name << " = " << value << "," << endl; + out << " " << name << " = " << value << "," << endl; } out << endl - << " ACCEPT_STATE = " << accept_state << "," << endl - << " RULE_COUNT = " << grammar.rules.size () << "," << endl - << " STATE_COUNT = " << state_count << "," << endl - << " TERMINAL_COUNT = " << terminal_count << "," << endl - << " NON_TERMINAL_COUNT = " << non_terminal_count << "," << endl + << " ACCEPT_STATE = " << accept_state << "," << endl + << " RULE_COUNT = " << grammar.rules.size () << "," << endl + << " STATE_COUNT = " << state_count << "," << endl + << " TERMINAL_COUNT = " << terminal_count << "," << endl + << " NON_TERMINAL_COUNT = " << non_terminal_count << "," << endl << endl - << " GOTO_INDEX_OFFSET = " << compressed_action.index.size () << "," << endl - << " GOTO_INFO_OFFSET = " << compressed_action.info.size () << "," << endl - << " GOTO_CHECK_OFFSET = " << compressed_action.check.size () << endl - << " };" << endl + << " GOTO_INDEX_OFFSET = " << compressed_action.index.size () << "," << endl + << " GOTO_INFO_OFFSET = " << compressed_action.info.size () << "," << endl + << " GOTO_CHECK_OFFSET = " << compressed_action.check.size () << endl + << " };" << endl << endl - << " static const char *const spell [];" << endl - << " static const short lhs [];" << endl - << " static const short rhs [];" << endl; + << " static const char *const spell[];" << endl + << " static const short lhs[];" << endl + << " static const short rhs[];" << endl; if (debug_info) { QString prot = debugInfoProt(); out << endl << "#ifndef " << prot << endl - << " static const int rule_index [];" << endl - << " static const int rule_info [];" << endl + << " static const int rule_index[];" << endl + << " static const int rule_info[];" << endl << "#endif // " << prot << endl << endl; } - out << " static const short goto_default [];" << endl - << " static const short action_default [];" << endl - << " static const short action_index [];" << endl - << " static const short action_info [];" << endl - << " static const short action_check [];" << endl + out << " static const short goto_default[];" << endl + << " static const short action_default[];" << endl + << " static const short action_index[];" << endl + << " static const short action_info[];" << endl + << " static const short action_check[];" << endl << endl - << " static inline int nt_action (int state, int nt)" << endl - << " {" << endl - << " const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;" << endl - << " if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)" << endl - << " return goto_default [nt];" << endl + << " static inline int nt_action (int state, int nt)" << endl + << " {" << endl + << " const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt;" << endl + << " if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt)" << endl + << " return goto_default [nt];" << endl << endl - << " return action_info [GOTO_INFO_OFFSET + yyn];" << endl - << " }" << endl + << " return action_info [GOTO_INFO_OFFSET + yyn];" << endl + << " }" << endl << endl - << " static inline int t_action (int state, int token)" << endl - << " {" << endl - << " const int yyn = action_index [state] + token;" << endl + << " static inline int t_action (int state, int token)" << endl + << " {" << endl + << " const int yyn = action_index [state] + token;" << endl << endl - << " if (yyn < 0 || action_check [yyn] != token)" << endl - << " return - action_default [state];" << endl + << " if (yyn < 0 || action_check [yyn] != token)" << endl + << " return - action_default [state];" << endl << endl - << " return action_info [yyn];" << endl - << " }" << endl + << " return action_info [yyn];" << endl + << " }" << endl << "};" << endl << endl << endl; @@ -539,11 +551,7 @@ void CppGenerator::generateImpl (QTextStream &out) name_ids.insert (t, idx); - if (idx) - out << ", "; - - if (! (idx % 10)) - out << endl << " "; + generateSeparator(idx, out); if (terminal) { @@ -569,35 +577,27 @@ void CppGenerator::generateImpl (QTextStream &out) if (debug_info) out << endl << "#endif // " << debugInfoProt() << endl; - out << "};" << endl << endl; + out << endl << "};" << endl << endl; out << "const short " << grammar.table_name << "::lhs [] = {"; idx = 0; for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx) { - if (idx) - out << ", "; - - if (! (idx % 10)) - out << endl << " "; + generateSeparator(idx, out); out << aut.id (rule->lhs); } - out << "};" << endl << endl; + out << endl << "};" << endl << endl; out << "const short " << grammar.table_name << "::rhs [] = {"; idx = 0; for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx) { - if (idx) - out << ", "; - - if (! (idx % 10)) - out << endl << " "; + generateSeparator(idx, out); out << rule->rhs.size (); } - out << "};" << endl << endl; + out << endl << "};" << endl << endl; if (debug_info) { @@ -608,35 +608,26 @@ void CppGenerator::generateImpl (QTextStream &out) idx = 0; for (auto rule = grammar.rules.cbegin (); rule != grammar.rules.cend (); ++rule, ++idx) { - out << endl << " "; - - if (idx) - out << ", "; - else - out << " "; + generateSeparator(idx, out); out << name_ids.value(rule->lhs); for (const Name &n : rule->rhs) out << ", " << name_ids.value (n); } - out << "};" << endl << endl; + out << endl << "};" << endl << endl; out << "const int " << grammar.table_name << "::rule_index [] = {"; idx = 0; int offset = 0; for (RulePointer rule = grammar.rules.begin (); rule != grammar.rules.end (); ++rule, ++idx) { - if (idx) - out << ", "; - - if (! (idx % 10)) - out << endl << " "; + generateSeparator(idx, out); out << offset; offset += rule->rhs.size () + 1; } - out << "};" << endl + out << endl << "};" << endl << "#endif // " << prot << endl << endl; } @@ -644,92 +635,34 @@ void CppGenerator::generateImpl (QTextStream &out) idx = 0; for (StatePointer state = aut.states.begin (); state != aut.states.end (); ++state, ++idx) { - if (state != aut.states.begin ()) - out << ", "; - - if (! (idx % 10)) - out << endl << " "; + generateSeparator(idx, out); if (state->defaultReduce != grammar.rules.end ()) out << aut.id (state->defaultReduce); else out << "0"; } - out << "};" << endl << endl; + out << endl << "};" << endl << endl; out << "const short " << grammar.table_name << "::goto_default [] = {"; - for (int i = 0; i < defgoto.size (); ++i) - { - if (i) - out << ", "; - - if (! (i % 10)) - out << endl << " "; - - out << defgoto [i]; - } - out << "};" << endl << endl; + generateList(defgoto, out); + out << endl << "};" << endl << endl; out << "const short " << grammar.table_name << "::action_index [] = {"; - for (int i = 0; i < compressed_action.index.size (); ++i) - { - if (! (i % 10)) - out << endl << " "; - - out << compressed_action.index [i] << ", "; - } - out << endl; - for (int i = 0; i < compressed_goto.index.size (); ++i) - { - if (i) - out << ", "; - - if (! (i % 10)) - out << endl << " "; - - out << compressed_goto.index [i]; - } - out << "};" << endl << endl; + generateList(compressed_action.index, out); + out << "," << endl; + generateList(compressed_goto.index, out); + out << endl << "};" << endl << endl; out << "const short " << grammar.table_name << "::action_info [] = {"; - for (int i = 0; i < compressed_action.info.size (); ++i) - { - if (! (i % 10)) - out << endl << " "; - - out << compressed_action.info [i] << ", "; - } - out << endl; - for (int i = 0; i < compressed_goto.info.size (); ++i) - { - if (i) - out << ", "; - - if (! (i % 10)) - out << endl << " "; - - out << compressed_goto.info [i]; - } - out << "};" << endl << endl; + generateList(compressed_action.info, out); + out << "," << endl; + generateList(compressed_goto.info, out); + out << endl << "};" << endl << endl; out << "const short " << grammar.table_name << "::action_check [] = {"; - for (int i = 0; i < compressed_action.check.size (); ++i) - { - if (! (i % 10)) - out << endl << " "; - - out << compressed_action.check [i] << ", "; - } - out << endl; - for (int i = 0; i < compressed_goto.check.size (); ++i) - { - if (i) - out << ", "; - - if (! (i % 10)) - out << endl << " "; - - out << compressed_goto.check [i]; - } - out << "};" << endl << endl; + generateList(compressed_action.check, out); + out << "," << endl; + generateList(compressed_goto.check, out); + out << endl << "};" << endl << endl; } diff --git a/src/tools/qlalr/grammar.cpp b/src/tools/qlalr/grammar.cpp index 1891a54860..f633962815 100644 --- a/src/tools/qlalr/grammar.cpp +++ b/src/tools/qlalr/grammar.cpp @@ -32,83 +32,89 @@ QT_BEGIN_NAMESPACE const char *const grammar::spell [] = { - "end of file", "identifier", "string literal", "%decl", "%expect", "%expect-lr", "%impl", "%left", "%merged_output", "%nonassoc", - "%parser", "%prec", "%right", "%start", "%token", "%token_prefix", ":", "|", ";", 0, - 0, 0}; + "end of file", "identifier", "string literal", "%decl", "%expect", "%expect-lr", "%impl", "%left", "%merged_output", "%nonassoc", + "%parser", "%prec", "%right", "%start", "%token", "%token_prefix", ":", "|", ";", 0, + 0, 0 +}; const short grammar::lhs [] = { - 22, 23, 23, 29, 25, 28, 28, 28, 28, 28, - 28, 28, 24, 24, 31, 32, 32, 33, 33, 34, - 34, 34, 31, 35, 35, 36, 37, 37, 38, 38, - 30, 30, 26, 26, 40, 39, 41, 41, 44, 43, - 43, 42, 42, 27, 45}; + 22, 23, 23, 29, 25, 28, 28, 28, 28, 28, + 28, 28, 24, 24, 31, 32, 32, 33, 33, 34, + 34, 34, 31, 35, 35, 36, 37, 37, 38, 38, + 30, 30, 26, 26, 40, 39, 41, 41, 44, 43, + 43, 42, 42, 27, 45 +}; const short grammar::rhs [] = { - 4, 1, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, - 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, - 0, 1, 1, 2, 2, 4, 3, 6, 0, 0, - 2, 1, 2, 0, 2}; + 4, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 1, 2, 2, 1, 2, 2, 2, 1, + 1, 1, 2, 1, 2, 1, 1, 1, 1, 2, + 0, 1, 1, 2, 2, 4, 3, 6, 0, 0, + 2, 1, 2, 0, 2 +}; const short grammar::action_default [] = { - 44, 2, 44, 0, 0, 0, 0, 13, 0, 0, - 3, 0, 0, 0, 8, 10, 11, 9, 7, 6, - 12, 20, 22, 0, 21, 0, 44, 31, 0, 14, - 26, 24, 23, 25, 4, 33, 1, 0, 34, 44, - 35, 42, 39, 40, 0, 31, 44, 40, 43, 0, - 31, 41, 29, 27, 28, 32, 38, 30, 36, 31, - 37, 5, 44, 16, 15, 18, 19, 17, 45}; + 44, 2, 44, 0, 0, 0, 0, 13, 0, 0, + 3, 0, 0, 0, 8, 10, 11, 9, 7, 6, + 12, 20, 22, 0, 21, 0, 44, 31, 0, 14, + 26, 24, 23, 25, 4, 33, 1, 0, 34, 44, + 35, 42, 39, 40, 0, 31, 44, 40, 43, 0, + 31, 41, 29, 27, 28, 32, 38, 30, 36, 31, + 37, 5, 44, 16, 15, 18, 19, 17, 45 +}; const short grammar::goto_default [] = { - 3, 2, 13, 26, 36, 41, 10, 27, 61, 29, - 64, 63, 23, 32, 31, 52, 55, 38, 39, 42, - 43, 59, 44, 0}; + 3, 2, 13, 26, 36, 41, 10, 27, 61, 29, + 64, 63, 23, 32, 31, 52, 55, 38, 39, 42, + 43, 59, 44, 0 +}; const short grammar::action_index [] = { - -22, -22, 54, 1, 5, 15, 20, -22, -1, 6, - -22, 3, 2, 35, -22, -22, -22, -22, -22, -22, - -22, -22, -22, 10, -22, 7, -22, 14, 9, -22, - -22, -22, 8, -22, -22, -22, 11, -2, -22, -22, - -22, -22, -3, 16, 13, 14, -22, 17, -22, 4, - 14, -22, -22, -22, -22, 14, -22, -22, -22, 14, - -22, -22, 0, -22, 12, -22, -22, -22, -22, + -22, -22, 30, 1, 2, 3, 4, -22, 5, 6, + -22, 8, -1, 35, -22, -22, -22, -22, -22, -22, + -22, -22, -22, 13, -22, 7, -22, -2, 20, -22, + -22, -22, 11, -22, -22, -22, 15, -6, -22, -22, + -22, -22, -3, 19, -4, 12, -22, 18, -22, 10, + -2, -22, -22, -22, -22, -2, -22, -22, -22, -2, + -22, -22, 0, -22, 20, -22, -22, -22, -22, - 2, -24, -2, -24, -24, -24, -24, -24, -24, -24, - -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, - -24, -24, -24, -24, -24, -24, -4, -24, -24, -24, - -24, -24, -14, -24, -24, -24, -24, -24, -24, -24, - -24, -24, -24, -24, -24, 0, -16, -15, -24, -24, - 15, -24, -24, -24, -24, -10, -24, -24, -24, 1, - -24, -24, -3, -24, -1, -24, -24, -24, -24}; + 0, -24, 3, -24, -24, -24, -24, -24, -24, -24, + -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, + -24, -24, -24, -24, -24, -24, -2, -24, -24, -24, + -24, -24, -7, -24, -24, -24, -24, -24, -24, -24, + -24, -24, -24, -24, -24, 17, -19, -11, -24, -24, + 1, -24, -24, -24, -24, -15, -24, -24, -24, -6, + -24, -24, -1, -24, -5, -24, -24, -24, -24 +}; const short grammar::action_info [] = { - 17, 68, 66, 20, 19, 51, 14, 18, 34, 30, - 62, 30, 37, 62, 40, 45, 15, 48, 48, 0, - 0, 16, 0, 0, 0, 0, 0, 49, 49, 0, - 46, 0, 0, 53, 54, 0, 0, 0, 0, 0, - 0, 0, 21, 0, 22, 0, 0, 24, 25, 28, - 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, - 8, 0, 9, 0, 11, 0, 0, 0, 0, 12, - 0, 0, 0, 0, 0, 0, + 20, 68, 66, 14, 15, 16, 17, 18, 34, 19, + 40, 51, 30, 46, 30, 45, 37, 53, 54, 48, + 48, 62, 0, 0, 0, 0, 0, 0, 0, 49, + 49, 53, 54, 4, 5, 6, 8, 0, 9, 0, + 11, 0, 21, 0, 22, 12, 0, 24, 25, 28, + 0, 0, 0, 0, 0, 0, 0, - 33, 35, 65, 7, 47, 57, 50, 1, 58, 60, - 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0}; + 57, 47, 60, 35, 65, 1, 67, 33, 7, 56, + 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 58, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0 +}; const short grammar::action_check [] = { - 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 16, 18, 1, 1, 1, -1, - -1, 1, -1, -1, -1, -1, -1, 11, 11, -1, - 17, -1, -1, 19, 20, -1, -1, -1, -1, -1, - -1, -1, 7, -1, 9, -1, -1, 12, 13, 14, - -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, - 6, -1, 8, -1, 10, -1, -1, -1, -1, 15, - -1, -1, -1, -1, -1, -1, + 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, + 16, 1, 1, 17, 1, 18, 1, 19, 20, 1, + 1, 1, -1, -1, -1, -1, -1, -1, -1, 11, + 11, 19, 20, 3, 4, 5, 6, -1, 8, -1, + 10, -1, 7, -1, 9, 15, -1, 12, 13, 14, + -1, -1, -1, -1, -1, -1, -1, - 14, 5, 5, 5, 20, 15, 21, 5, 8, 8, - 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; + 15, 20, 8, 5, 5, 5, 11, 14, 5, 8, + 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1 +}; QT_END_NAMESPACE diff --git a/src/tools/qlalr/grammar_p.h b/src/tools/qlalr/grammar_p.h index 1230a29b1c..8482f9bfe1 100644 --- a/src/tools/qlalr/grammar_p.h +++ b/src/tools/qlalr/grammar_p.h @@ -48,68 +48,68 @@ QT_BEGIN_NAMESPACE class grammar { public: - enum VariousConstants { - EOF_SYMBOL = 0, - COLON = 16, - DECL = 19, - DECL_FILE = 3, - ERROR = 21, - EXPECT = 4, - EXPECT_RR = 5, - ID = 1, - IMPL = 20, - IMPL_FILE = 6, - LEFT = 7, - MERGED_OUTPUT = 8, - NONASSOC = 9, - OR = 17, - PARSER = 10, - PREC = 11, - RIGHT = 12, - SEMICOLON = 18, - START = 13, - STRING_LITERAL = 2, - TOKEN = 14, - TOKEN_PREFIX = 15, - - ACCEPT_STATE = 68, - RULE_COUNT = 45, - STATE_COUNT = 69, - TERMINAL_COUNT = 22, - NON_TERMINAL_COUNT = 24, - - GOTO_INDEX_OFFSET = 69, - GOTO_INFO_OFFSET = 76, - GOTO_CHECK_OFFSET = 76 - }; - - static const char *const spell []; - static const short lhs []; - static const short rhs []; - static const short goto_default []; - static const short action_default []; - static const short action_index []; - static const short action_info []; - static const short action_check []; - - static inline int nt_action (int state, int nt) - { - const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; - if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) - return goto_default [nt]; - - return action_info [GOTO_INFO_OFFSET + yyn]; - } - - static inline int t_action (int state, int token) - { - const int yyn = action_index [state] + token; - - if (yyn < 0 || action_check [yyn] != token) - return - action_default [state]; - - return action_info [yyn]; - } + enum VariousConstants { + EOF_SYMBOL = 0, + COLON = 16, + DECL = 19, + DECL_FILE = 3, + ERROR = 21, + EXPECT = 4, + EXPECT_RR = 5, + ID = 1, + IMPL = 20, + IMPL_FILE = 6, + LEFT = 7, + MERGED_OUTPUT = 8, + NONASSOC = 9, + OR = 17, + PARSER = 10, + PREC = 11, + RIGHT = 12, + SEMICOLON = 18, + START = 13, + STRING_LITERAL = 2, + TOKEN = 14, + TOKEN_PREFIX = 15, + + ACCEPT_STATE = 68, + RULE_COUNT = 45, + STATE_COUNT = 69, + TERMINAL_COUNT = 22, + NON_TERMINAL_COUNT = 24, + + GOTO_INDEX_OFFSET = 69, + GOTO_INFO_OFFSET = 57, + GOTO_CHECK_OFFSET = 57 + }; + + static const char *const spell[]; + static const short lhs[]; + static const short rhs[]; + static const short goto_default[]; + static const short action_default[]; + static const short action_index[]; + static const short action_info[]; + static const short action_check[]; + + static inline int nt_action (int state, int nt) + { + const int yyn = action_index [GOTO_INDEX_OFFSET + state] + nt; + if (yyn < 0 || action_check [GOTO_CHECK_OFFSET + yyn] != nt) + return goto_default [nt]; + + return action_info [GOTO_INFO_OFFSET + yyn]; + } + + static inline int t_action (int state, int token) + { + const int yyn = action_index [state] + token; + + if (yyn < 0 || action_check [yyn] != token) + return - action_default [state]; + + return action_info [yyn]; + } }; diff --git a/src/tools/qlalr/lalr.g b/src/tools/qlalr/lalr.g index 65a63f8312..5e335c5a3b 100644 --- a/src/tools/qlalr/lalr.g +++ b/src/tools/qlalr/lalr.g @@ -61,8 +61,7 @@ %start Specification -/: -/**************************************************************************** +/:/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ @@ -163,8 +162,7 @@ protected: }; :/ -/. -/**************************************************************************** +/./**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ @@ -194,6 +192,8 @@ protected: #include "recognizer.h" +#include <QtCore/qdir.h> + #include <cstdlib> #include <cstring> #include <cctype> @@ -344,7 +344,8 @@ int Recognizer::nextToken() text.clear (); if (! _M_no_lines) - text += QLatin1String ("\n#line ") + QString::number (_M_action_line) + " \"" + _M_input_file + "\"\n"; + text += QLatin1String("\n#line ") + QString::number(_M_action_line) + + QLatin1String(" \"") + QDir::fromNativeSeparators(_M_input_file) + QLatin1String("\"\n"); inp (); // skip ':' forever @@ -381,7 +382,8 @@ int Recognizer::nextToken() text.clear (); if (! _M_no_lines) - text += QLatin1String ("\n#line ") + QString::number (_M_action_line) + " \"" + _M_input_file + "\"\n"; + text += QLatin1String("\n#line ") + QString::number(_M_action_line) + + QLatin1String(" \"") + QDir::fromNativeSeparators(_M_input_file) + QLatin1String("\"\n"); inp (); // skip ':' diff --git a/src/tools/qlalr/recognizer.cpp b/src/tools/qlalr/recognizer.cpp index 69dad1a6c1..8c7665f1b9 100644 --- a/src/tools/qlalr/recognizer.cpp +++ b/src/tools/qlalr/recognizer.cpp @@ -28,6 +28,8 @@ #include "recognizer.h" +#include <QtCore/qdir.h> + #include <cstdlib> #include <cstring> #include <cctype> @@ -178,8 +180,8 @@ int Recognizer::nextToken() text.clear (); if (! _M_no_lines) - text += QLatin1String("\n#line ") + QString::number (_M_action_line) - + QLatin1String(" \"") + _M_input_file + QLatin1String("\"\n"); + text += QLatin1String("\n#line ") + QString::number(_M_action_line) + + QLatin1String(" \"") + QDir::fromNativeSeparators(_M_input_file) + QLatin1String("\"\n"); inp (); // skip ':' forever @@ -216,8 +218,8 @@ int Recognizer::nextToken() text.clear (); if (! _M_no_lines) - text += QLatin1String ("\n#line ") + QString::number (_M_action_line) + - QLatin1String(" \"") + _M_input_file + QLatin1String("\"\n"); + text += QLatin1String("\n#line ") + QString::number(_M_action_line) + + QLatin1String(" \"") + QDir::fromNativeSeparators(_M_input_file) + QLatin1String("\"\n"); inp (); // skip ':' diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index 939e2a3d79..20002b1f82 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -1703,6 +1703,7 @@ bool QAbstractItemView::viewportEvent(QEvent *event) d->viewportEnteredNeeded = true; break; case QEvent::Leave: + d->setHoverIndex(QModelIndex()); // If we've left, no hover should be needed anymore #ifndef QT_NO_STATUSTIP if (d->shouldClearStatusTip && d->parent) { QString empty; diff --git a/src/widgets/widgets/qtoolbox.cpp b/src/widgets/widgets/qtoolbox.cpp index 2c74b5fa9d..8413827e30 100644 --- a/src/widgets/widgets/qtoolbox.cpp +++ b/src/widgets/widgets/qtoolbox.cpp @@ -117,7 +117,7 @@ public: void _q_buttonClicked(); void _q_widgetDestroyed(QObject*); - const Page *page(QWidget *widget) const; + const Page *page(const QObject *widget) const; const Page *page(int index) const; Page *page(int index); @@ -129,7 +129,7 @@ public: Page *currentPage; }; -const QToolBoxPrivate::Page *QToolBoxPrivate::page(QWidget *widget) const +const QToolBoxPrivate::Page *QToolBoxPrivate::page(const QObject *widget) const { if (!widget) return 0; @@ -449,11 +449,9 @@ void QToolBoxPrivate::relayout() void QToolBoxPrivate::_q_widgetDestroyed(QObject *object) { Q_Q(QToolBox); - // no verification - vtbl corrupted already - QWidget *p = (QWidget*)object; - const QToolBoxPrivate::Page *c = page(p); - if (!p || !c) + const QToolBoxPrivate::Page * const c = page(object); + if (!c) return; layout->removeWidget(c->sv); diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp index f5672bd87a..dacb4806ce 100644 --- a/src/widgets/widgets/qwidgettextcontrol.cpp +++ b/src/widgets/widgets/qwidgettextcontrol.cpp @@ -2052,16 +2052,59 @@ void QWidgetTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) preeditCursor = a.start; hideCursor = !a.length; } else if (a.type == QInputMethodEvent::TextFormat) { - QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat(); + QTextCharFormat f = cursor.charFormat(); + f.merge(qvariant_cast<QTextFormat>(a.value).toCharFormat()); if (f.isValid()) { QTextLayout::FormatRange o; o.start = a.start + cursor.position() - block.position(); o.length = a.length; o.format = f; - overrides.append(o); + + // Make sure list is sorted by start index + QVector<QTextLayout::FormatRange>::iterator it = overrides.end(); + while (it != overrides.begin()) { + QVector<QTextLayout::FormatRange>::iterator previous = it - 1; + if (o.start >= previous->start) { + overrides.insert(it, o); + break; + } + it = previous; + } + + if (it == overrides.begin()) + overrides.prepend(o); } } } + + if (cursor.charFormat().isValid()) { + int start = cursor.position() - block.position(); + int end = start + e->preeditString().length(); + + QVector<QTextLayout::FormatRange>::iterator it = overrides.begin(); + while (it != overrides.end()) { + QTextLayout::FormatRange range = *it; + int rangeStart = range.start; + if (rangeStart > start) { + QTextLayout::FormatRange o; + o.start = start; + o.length = rangeStart - start; + o.format = cursor.charFormat(); + it = overrides.insert(it, o) + 1; + } + + ++it; + start = range.start + range.length; + } + + if (start < end) { + QTextLayout::FormatRange o; + o.start = start; + o.length = end - start; + o.format = cursor.charFormat(); + overrides.append(o); + } + } layout->setFormats(overrides); cursor.endEditBlock(); diff --git a/tests/auto/corelib/animation/qpauseanimation/BLACKLIST b/tests/auto/corelib/animation/qpauseanimation/BLACKLIST index 3b2cd84749..8fc1b07502 100644 --- a/tests/auto/corelib/animation/qpauseanimation/BLACKLIST +++ b/tests/auto/corelib/animation/qpauseanimation/BLACKLIST @@ -2,3 +2,5 @@ osx-10.9 [pauseAndPropertyAnimations] * +[multipleSequentialGroups] +osx diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp index a13ff0358a..d2f345feb5 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp @@ -34,6 +34,7 @@ #include <qsysinfo.h> #if defined(Q_OS_UNIX) && !defined(Q_OS_VXWORKS) #include <unistd.h> +#include <sys/time.h> #elif defined(Q_OS_WIN) && !defined(Q_OS_WINRT) # include <qt_windows.h> #endif @@ -59,6 +60,7 @@ private slots: void noPermissions(); void noPermissionsWindows(); void corruptedLockFile(); + void corruptedLockFileInTheFuture(); private: static bool overwritePidInLockFile(const QString &filePath, qint64 pid); @@ -521,6 +523,32 @@ void tst_QLockFile::corruptedLockFile() QCOMPARE(int(secondLock.error()), int(QLockFile::NoError)); } +void tst_QLockFile::corruptedLockFileInTheFuture() +{ +#if !defined(Q_OS_UNIX) + QSKIP("This tests needs utimes"); +#else + // This test is the same as the previous one, but the corruption was so there is a corrupted + // .rmlock whose timestamp is in the future + + const QString fileName = dir.path() + "/corruptedLockFile.rmlock"; + + { + QFile file(fileName); + QVERIFY(file.open(QFile::WriteOnly)); + } + + struct timeval times[2]; + gettimeofday(times, 0); + times[1].tv_sec = (times[0].tv_sec += 600); + times[1].tv_usec = times[0].tv_usec; + utimes(fileName.toLocal8Bit(), times); + + QTest::ignoreMessage(QtInfoMsg, "QLockFile: Lock file '" + fileName.toUtf8() + "' has a modification time in the future"); + corruptedLockFile(); +#endif +} + bool tst_QLockFile::overwritePidInLockFile(const QString &filePath, qint64 pid) { QFile f(filePath); diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index ee18151e4a..ebc240c285 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -3088,7 +3088,11 @@ void tst_QUrl::fromUserInputWithCwd_data() } // Existing files - for (const char *fileName : {"file.txt", "file#a.txt", "file .txt", "file.txt "}) { + for (const char *fileName : {"file.txt", "file#a.txt", "file .txt", "file.txt " +#ifndef Q_OS_WIN + , "file:colon.txt" +#endif + }) { const QString filePath = base + '/' + fileName; QFile file(filePath); QVERIFY2(file.open(QIODevice::WriteOnly), qPrintable(filePath)); diff --git a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp index f693d14029..143bf2f95d 100644 --- a/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp +++ b/tests/auto/corelib/kernel/qmetatype/tst_qmetatype.cpp @@ -1563,7 +1563,6 @@ DECLARE_NONSTREAMABLE(QJsonArray) DECLARE_NONSTREAMABLE(QJsonDocument) DECLARE_NONSTREAMABLE(QObject*) DECLARE_NONSTREAMABLE(QWidget*) -DECLARE_NONSTREAMABLE(std::nullptr_t) #define DECLARE_GUI_CLASS_NONSTREAMABLE(MetaTypeName, MetaTypeId, RealType) \ DECLARE_NONSTREAMABLE(RealType) @@ -1602,7 +1601,10 @@ void tst_QMetaType::saveAndLoadBuiltin() if (isStreamable) { QVERIFY(QMetaType::load(stream, type, value)); // Hmmm, shouldn't it return false? - QCOMPARE(stream.status(), QDataStream::ReadPastEnd); + + // std::nullptr_t is nullary: it doesn't actually read anything + if (type != QMetaType::Nullptr) + QCOMPARE(stream.status(), QDataStream::ReadPastEnd); } stream.device()->seek(0); @@ -1612,7 +1614,10 @@ void tst_QMetaType::saveAndLoadBuiltin() if (isStreamable) { QVERIFY(QMetaType::load(stream, type, value)); // Hmmm, shouldn't it return false? - QCOMPARE(stream.status(), QDataStream::ReadPastEnd); + + // std::nullptr_t is nullary: it doesn't actually read anything + if (type != QMetaType::Nullptr) + QCOMPARE(stream.status(), QDataStream::ReadPastEnd); } QMetaType::destroy(type, value); diff --git a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp index 02ba987ccd..280e3f77a4 100644 --- a/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp +++ b/tests/auto/corelib/mimetypes/qmimedatabase/tst_qmimedatabase.cpp @@ -861,7 +861,7 @@ void tst_QMimeDatabase::fromThreads() #if QT_CONFIG(process) enum { - UpdateMimeDatabaseTimeout = 120 * 1000 // 2min + UpdateMimeDatabaseTimeout = 4 * 60 * 1000 // 4min }; static bool runUpdateMimeDatabase(const QString &path) // TODO make it a QMimeDatabase method? diff --git a/tests/auto/corelib/tools/qchar/tst_qchar.cpp b/tests/auto/corelib/tools/qchar/tst_qchar.cpp index 13898ace7b..e5a6e953d3 100644 --- a/tests/auto/corelib/tools/qchar/tst_qchar.cpp +++ b/tests/auto/corelib/tools/qchar/tst_qchar.cpp @@ -36,7 +36,7 @@ class tst_QChar : public QObject { Q_OBJECT private slots: - void operator_eqeq_int(); + void operator_eqeq_null(); void operators_data(); void operators(); void toUpper(); @@ -72,35 +72,54 @@ private slots: void unicodeVersion(); }; -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - -void tst_QChar::operator_eqeq_int() +void tst_QChar::operator_eqeq_null() { { const QChar ch = QLatin1Char(' '); - QVERIFY(ch != 0); - QVERIFY(!(ch == 0)); - - QVERIFY(ch == 0x20); - QVERIFY(!(ch != 0x20)); - QVERIFY(0x20 == ch); - QVERIFY(!(0x20 != ch)); +#define CHECK(NUL) \ + do { \ + QVERIFY(!(ch == NUL)); \ + QVERIFY( ch != NUL ); \ + QVERIFY(!(ch < NUL)); \ + QVERIFY( ch > NUL ); \ + QVERIFY(!(ch <= NUL)); \ + QVERIFY( ch >= NUL ); \ + QVERIFY(!(NUL == ch )); \ + QVERIFY( NUL != ch ); \ + QVERIFY( NUL < ch ); \ + QVERIFY(!(NUL > ch )); \ + QVERIFY( NUL <= ch ); \ + QVERIFY(!(NUL >= ch )); \ + } while (0) + + CHECK(0); + CHECK('\0'); +#undef CHECK } { const QChar ch = QLatin1Char('\0'); - QVERIFY(ch == 0); - QVERIFY(!(ch != 0)); - - QVERIFY(ch != 0x20); - QVERIFY(!(ch == 0x20)); - QVERIFY(0x20 != ch); - QVERIFY(!(0x20 == ch)); +#define CHECK(NUL) \ + do { \ + QVERIFY( ch == NUL ); \ + QVERIFY(!(ch != NUL)); \ + QVERIFY(!(ch < NUL)); \ + QVERIFY(!(ch > NUL)); \ + QVERIFY( ch <= NUL ); \ + QVERIFY( ch >= NUL ); \ + QVERIFY( NUL == ch ); \ + QVERIFY(!(NUL != ch )); \ + QVERIFY(!(NUL < ch )); \ + QVERIFY(!(NUL > ch )); \ + QVERIFY( NUL <= ch ); \ + QVERIFY( NUL >= ch ); \ + } while (0) + + CHECK(0); + CHECK('\0'); +#undef CHECK } } -QT_WARNING_POP - void tst_QChar::operators_data() { QTest::addColumn<QChar>("lhs"); diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index d241296a6b..f2cf78e8ac 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -45,6 +45,7 @@ #include <qpushbutton.h> #include <qscrollbar.h> #include <qboxlayout.h> +#include <qitemdelegate.h> #include <qlineedit.h> #include <qscreen.h> #include <qscopedpointer.h> @@ -151,6 +152,7 @@ private slots: void testSelectionModelInSyncWithView(); void testClickToSelect(); void testDialogAsEditor(); + void QTBUG46785_mouseout_hover_state(); }; class MyAbstractItemDelegate : public QAbstractItemDelegate @@ -2213,5 +2215,56 @@ void tst_QAbstractItemView::testDialogAsEditor() QCOMPARE(delegate.result, QDialog::Accepted); } +class HoverItemDelegate : public QItemDelegate +{ +public: + HoverItemDelegate() + : QItemDelegate() + , m_paintedWithoutHover(false) + { } + + void paint(QPainter *painter, const QStyleOptionViewItem &opt, const QModelIndex &index) const override + { + Q_UNUSED(painter); + + if (!(opt.state & QStyle::State_MouseOver)) { + + // We don't want to set m_paintedWithoutHover for any item so check for the item at 0,0 + if (index.row() == 0 && index.column() == 0) { + m_paintedWithoutHover = true; + } + } + } + + mutable bool m_paintedWithoutHover; +}; + +void tst_QAbstractItemView::QTBUG46785_mouseout_hover_state() +{ + HoverItemDelegate delegate; + + QTableWidget table(5, 5); + table.verticalHeader()->hide(); + table.horizontalHeader()->hide(); + table.setMouseTracking(true); + table.setItemDelegate(&delegate); + centerOnScreen(&table); + table.show(); + QVERIFY(QTest::qWaitForWindowActive(&table)); + + QModelIndex item = table.model()->index(0, 0); + QRect itemRect = table.visualRect(item); + + // Move the mouse into the center of the item at 0,0 to cause a paint event to occur + QTest::mouseMove(table.viewport(), itemRect.center()); + QTest::mouseClick(table.viewport(), Qt::LeftButton, 0, itemRect.center()); + + delegate.m_paintedWithoutHover = false; + + QTest::mouseMove(table.viewport(), QPoint(-50, 0)); + + QTRY_VERIFY(delegate.m_paintedWithoutHover); +} + QTEST_MAIN(tst_QAbstractItemView) #include "tst_qabstractitemview.moc" diff --git a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp index b9ea310d80..bc94e2a05b 100644 --- a/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp +++ b/tests/auto/widgets/widgets/qtextedit/tst_qtextedit.cpp @@ -46,6 +46,7 @@ #include <qcommonstyle.h> #include <qlayout.h> #include <qdir.h> +#include <qpaintengine.h> #include <qabstracttextdocumentlayout.h> #include <qtextdocumentfragment.h> @@ -60,6 +61,8 @@ typedef QPair<Qt::Key, Qt::KeyboardModifier> keyPairType; typedef QList<keyPairType> pairListType; Q_DECLARE_METATYPE(keyPairType); +Q_DECLARE_METATYPE(QList<QInputMethodEvent::Attribute>); + QT_FORWARD_DECLARE_CLASS(QTextEdit) class tst_QTextEdit : public QObject @@ -200,6 +203,9 @@ private slots: void wheelEvent(); #endif + void preeditCharFormat_data(); + void preeditCharFormat(); + private: void createSelection(); int blockCount() const; @@ -2594,5 +2600,235 @@ void tst_QTextEdit::wheelEvent() #endif +namespace { + class MyPaintEngine : public QPaintEngine + { + public: + bool begin(QPaintDevice *) + { + return true; + } + + bool end() + { + return true; + } + + void updateState(const QPaintEngineState &) + { + } + + void drawPixmap(const QRectF &, const QPixmap &, const QRectF &) + { + } + + void drawTextItem(const QPointF &, const QTextItem &textItem) Q_DECL_OVERRIDE + { + itemFonts.append(qMakePair(textItem.text(), textItem.font())); + } + + Type type() const { return User; } + + + QList<QPair<QString, QFont> > itemFonts; + }; + + class MyPaintDevice : public QPaintDevice + { + public: + MyPaintDevice() : m_paintEngine(new MyPaintEngine) + { + } + + + QPaintEngine *paintEngine () const + { + return m_paintEngine; + } + + int metric (QPaintDevice::PaintDeviceMetric metric) const { + switch (metric) { + case QPaintDevice::PdmWidth: + case QPaintDevice::PdmHeight: + case QPaintDevice::PdmWidthMM: + case QPaintDevice::PdmHeightMM: + case QPaintDevice::PdmNumColors: + return INT_MAX; + case QPaintDevice::PdmDepth: + return 32; + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiX: + case QPaintDevice::PdmPhysicalDpiY: + return 72; + case QPaintDevice::PdmDevicePixelRatio: + case QPaintDevice::PdmDevicePixelRatioScaled: + ; // fall through + } + return 0; + } + + MyPaintEngine *m_paintEngine; + }; +} + +void tst_QTextEdit::preeditCharFormat_data() +{ + QTest::addColumn<QList<QInputMethodEvent::Attribute> >("imeAttributes"); + QTest::addColumn<QStringList>("substrings"); + QTest::addColumn<QList<bool> >("boldnessList"); + QTest::addColumn<QList<bool> >("italicnessList"); + QTest::addColumn<QList<int> >("pointSizeList"); + + { + QList<QInputMethodEvent::Attribute> attributes; + { + QTextCharFormat tcf; + tcf.setFontPointSize(13); + tcf.setFontItalic(true); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 1, 1, tcf)); + } + + { + QTextCharFormat tcf; + tcf.setFontPointSize(8); + tcf.setFontWeight(QFont::Normal); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 4, 2, tcf)); + } + + QTest::newRow("Two formats, middle, in order") + << attributes + << (QStringList() << "P" << "r" << "eE" << "di" << "tText") + << (QList<bool>() << true << true << true << false << true) + << (QList<bool>() << false << true << false << false << false) + << (QList<int>() << 20 << 13 << 20 << 8 << 20); + } + + { + QList<QInputMethodEvent::Attribute> attributes; + { + QTextCharFormat tcf; + tcf.setFontPointSize(8); + tcf.setFontWeight(QFont::Normal); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 4, 2, tcf)); + } + + { + QTextCharFormat tcf; + tcf.setFontPointSize(13); + tcf.setFontItalic(true); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 1, 1, tcf)); + } + + QTest::newRow("Two formats, middle, out of order") + << attributes + << (QStringList() << "P" << "r" << "eE" << "di" << "tText") + << (QList<bool>() << true << true << true << false << true) + << (QList<bool>() << false << true << false << false << false) + << (QList<int>() << 20 << 13 << 20 << 8 << 20); + } + + { + QList<QInputMethodEvent::Attribute> attributes; + { + QTextCharFormat tcf; + tcf.setFontPointSize(13); + tcf.setFontItalic(true); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, 1, tcf)); + } + + { + QTextCharFormat tcf; + tcf.setFontPointSize(8); + tcf.setFontWeight(QFont::Normal); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 4, 2, tcf)); + } + + QTest::newRow("Two formats, front, in order") + << attributes + << (QStringList() << "P" << "reE" << "di" << "tText") + << (QList<bool>() << true << true << false << true) + << (QList<bool>() << true << false << false << false) + << (QList<int>() << 13 << 20 << 8 << 20); + } + + { + QList<QInputMethodEvent::Attribute> attributes; + { + QTextCharFormat tcf; + tcf.setFontPointSize(8); + tcf.setFontWeight(QFont::Normal); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 4, 2, tcf)); + } + + { + QTextCharFormat tcf; + tcf.setFontPointSize(13); + tcf.setFontItalic(true); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, 1, tcf)); + } + + QTest::newRow("Two formats, front, out of order") + << attributes + << (QStringList() << "P" << "reE" << "di" << "tText") + << (QList<bool>() << true << true << false << true) + << (QList<bool>() << true << false << false << false) + << (QList<int>() << 13 << 20 << 8 << 20); + } +} + +void tst_QTextEdit::preeditCharFormat() +{ + QFETCH(QList<QInputMethodEvent::Attribute>, imeAttributes); + QFETCH(QStringList, substrings); + QFETCH(QList<bool>, boldnessList); + QFETCH(QList<bool>, italicnessList); + QFETCH(QList<int>, pointSizeList); + + QTextEdit *w = new QTextEdit; + w->show(); + QVERIFY(QTest::qWaitForWindowExposed(w)); + + // Set main char format + { + QTextCharFormat tcf; + tcf.setFontPointSize(20); + tcf.setFontWeight(QFont::Bold); + w->mergeCurrentCharFormat(tcf); + } + + QList<QInputMethodEvent::Attribute> attributes; + attributes.prepend(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, + w->textCursor().position(), + 0, + QVariant())); + + attributes += imeAttributes; + + QInputMethodEvent event("PreEditText", attributes); + QApplication::sendEvent(w, &event); + + MyPaintDevice device; + { + QPainter p(&device); + w->document()->drawContents(&p); + } + + QCOMPARE(device.m_paintEngine->itemFonts.size(), substrings.size()); + for (int i = 0; i < substrings.size(); ++i) + QCOMPARE(device.m_paintEngine->itemFonts.at(i).first, substrings.at(i)); + + for (int i = 0; i < substrings.size(); ++i) + QCOMPARE(device.m_paintEngine->itemFonts.at(i).second.bold(), boldnessList.at(i)); + + for (int i = 0; i < substrings.size(); ++i) + QCOMPARE(device.m_paintEngine->itemFonts.at(i).second.italic(), italicnessList.at(i)); + + for (int i = 0; i < substrings.size(); ++i) + QCOMPARE(device.m_paintEngine->itemFonts.at(i).second.pointSize(), pointSizeList.at(i)); + + delete w; +} + QTEST_MAIN(tst_QTextEdit) #include "tst_qtextedit.moc" |