diff --git a/src/corelib/serialization/qcborarray.cpp b/src/corelib/serialization/qcborarray.cpp index 506fb052be..05403795b0 100644 --- a/src/corelib/serialization/qcborarray.cpp +++ b/src/corelib/serialization/qcborarray.cpp @@ -1181,6 +1181,11 @@ void QCborArray::detach(qsizetype reserved) Returns the offset of this iterator relative to \a other. */ +uint qHash(const QCborArray &array, uint seed) +{ + return qHashRange(array.begin(), array.end(), seed); +} + #if !defined(QT_NO_DEBUG_STREAM) QDebug operator<<(QDebug dbg, const QCborArray &a) { diff --git a/src/corelib/serialization/qcborarray.h b/src/corelib/serialization/qcborarray.h index 4e9f7cf9b5..6b07b52a02 100644 --- a/src/corelib/serialization/qcborarray.h +++ b/src/corelib/serialization/qcborarray.h @@ -286,6 +286,8 @@ inline QCborArray QCborValueRef::toArray(const QCborArray &a) const return concrete().toArray(a); } +Q_CORE_EXPORT uint qHash(const QCborArray &array, uint seed = 0); + #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT QDebug operator<<(QDebug, const QCborArray &a); #endif diff --git a/src/corelib/serialization/qcbormap.cpp b/src/corelib/serialization/qcbormap.cpp index f9b000393c..b18945ded1 100644 --- a/src/corelib/serialization/qcbormap.cpp +++ b/src/corelib/serialization/qcbormap.cpp @@ -1734,6 +1734,11 @@ void QCborMap::detach(qsizetype reserved) \sa operator+=(), operator-() */ +uint qHash(const QCborMap &map, uint seed) +{ + return qHashRange(map.begin(), map.end(), seed); +} + #if !defined(QT_NO_DEBUG_STREAM) QDebug operator<<(QDebug dbg, const QCborMap &m) { diff --git a/src/corelib/serialization/qcbormap.h b/src/corelib/serialization/qcbormap.h index 2e9422cf94..c895abfa59 100644 --- a/src/corelib/serialization/qcbormap.h +++ b/src/corelib/serialization/qcbormap.h @@ -337,6 +337,8 @@ inline QCborMap QCborValueRef::toMap(const QCborMap &m) const return concrete().toMap(m); } +Q_CORE_EXPORT uint qHash(const QCborMap &map, uint seed = 0); + #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT QDebug operator<<(QDebug, const QCborMap &m); #endif diff --git a/src/corelib/serialization/qcborvalue.cpp b/src/corelib/serialization/qcborvalue.cpp index c1d78ef738..077a4754dc 100644 --- a/src/corelib/serialization/qcborvalue.cpp +++ b/src/corelib/serialization/qcborvalue.cpp @@ -2365,6 +2365,53 @@ inline QCborMap::QCborMap(QCborContainerPrivate &dd) noexcept { } +uint qHash(const QCborValue &value, uint seed) +{ + switch (value.type()) { + case QCborValue::Integer: + return qHash(value.toInteger(), seed); + case QCborValue::ByteArray: + return qHash(value.toByteArray(), seed); + case QCborValue::String: + return qHash(value.toString(), seed); + case QCborValue::Array: + return qHash(value.toArray(), seed); + case QCborValue::Map: + return qHash(value.toMap(), seed); + case QCborValue::Tag: { + QtPrivate::QHashCombine hash; + seed = hash(seed, value.tag()); + seed = hash(seed, value.taggedValue()); + return seed; + } + case QCborValue::SimpleType: + break; + case QCborValue::False: + return qHash(false, seed); + case QCborValue::True: + return qHash(true, seed); + case QCborValue::Null: + return qHash(nullptr, seed); + case QCborValue::Undefined: + return seed; + case QCborValue::Double: + return qHash(value.toDouble(), seed); + case QCborValue::DateTime: + return qHash(value.toDateTime(), seed); + case QCborValue::Url: + return qHash(value.toUrl(), seed); + case QCborValue::RegularExpression: + return qHash(value.toRegularExpression(), seed); + case QCborValue::Uuid: + return qHash(value.toUuid(), seed); + case QCborValue::Invalid: + return seed; + } + + Q_ASSERT(value.isSimpleType()); + return qHash(value.toSimpleType(), seed); +} + #if !defined(QT_NO_DEBUG_STREAM) static QDebug debugContents(QDebug &dbg, const QCborValue &v) { diff --git a/src/corelib/serialization/qcborvalue.h b/src/corelib/serialization/qcborvalue.h index f0bfa23392..6d9ed0810a 100644 --- a/src/corelib/serialization/qcborvalue.h +++ b/src/corelib/serialization/qcborvalue.h @@ -451,6 +451,8 @@ private: qsizetype i; }; +Q_CORE_EXPORT uint qHash(const QCborValue &value, uint seed = 0); + #if !defined(QT_NO_DEBUG_STREAM) Q_CORE_EXPORT QDebug operator<<(QDebug, const QCborValue &v); #endif diff --git a/src/corelib/serialization/qjsonarray.cpp b/src/corelib/serialization/qjsonarray.cpp index 8ee9ce0de7..1187bb03a3 100644 --- a/src/corelib/serialization/qjsonarray.cpp +++ b/src/corelib/serialization/qjsonarray.cpp @@ -1237,6 +1237,10 @@ void QJsonArray::compact() a = static_cast(d->header->root()); } +uint qHash(const QJsonArray &array, uint seed) +{ + return qHashRange(array.begin(), array.end(), seed); +} #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) QDebug operator<<(QDebug dbg, const QJsonArray &a) diff --git a/src/corelib/serialization/qjsonarray.h b/src/corelib/serialization/qjsonarray.h index 8d41138c97..5dff4a0aa9 100644 --- a/src/corelib/serialization/qjsonarray.h +++ b/src/corelib/serialization/qjsonarray.h @@ -265,6 +265,8 @@ private: Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonArray) +Q_CORE_EXPORT uint qHash(const QJsonArray &array, uint seed = 0); + #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonArray &); #endif diff --git a/src/corelib/serialization/qjsonobject.cpp b/src/corelib/serialization/qjsonobject.cpp index 4a316c8a6f..950bec535b 100644 --- a/src/corelib/serialization/qjsonobject.cpp +++ b/src/corelib/serialization/qjsonobject.cpp @@ -1292,6 +1292,17 @@ void QJsonObject::setValueAt(int i, const QJsonValue &val) insert(e->key(), val); } +uint qHash(const QJsonObject &object, uint seed) +{ + QtPrivate::QHashCombine hash; + for (auto it = object.begin(), end = object.end(); it != end; ++it) { + const QString key = it.key(); + const QJsonValue value = it.value(); + seed = hash(seed, std::pair(key, value)); + } + return seed; +} + #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) QDebug operator<<(QDebug dbg, const QJsonObject &o) { diff --git a/src/corelib/serialization/qjsonobject.h b/src/corelib/serialization/qjsonobject.h index 610bce694c..be42d3747a 100644 --- a/src/corelib/serialization/qjsonobject.h +++ b/src/corelib/serialization/qjsonobject.h @@ -262,6 +262,8 @@ private: Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonObject) +Q_CORE_EXPORT uint qHash(const QJsonObject &object, uint seed = 0); + #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonObject &); #endif diff --git a/src/corelib/serialization/qjsonvalue.cpp b/src/corelib/serialization/qjsonvalue.cpp index 4469302e31..2c04da4885 100644 --- a/src/corelib/serialization/qjsonvalue.cpp +++ b/src/corelib/serialization/qjsonvalue.cpp @@ -876,6 +876,28 @@ QJsonValue QJsonValueRef::toValue() const return o->valueAt(index); } +uint qHash(const QJsonValue &value, uint seed) +{ + switch (value.type()) { + case QJsonValue::Null: + return qHash(nullptr, seed); + case QJsonValue::Bool: + return qHash(value.toBool(), seed); + case QJsonValue::Double: + return qHash(value.toDouble(), seed); + case QJsonValue::String: + return qHash(value.toString(), seed); + case QJsonValue::Array: + return qHash(value.toArray(), seed); + case QJsonValue::Object: + return qHash(value.toObject(), seed); + case QJsonValue::Undefined: + return seed; + } + Q_UNREACHABLE(); + return 0; +} + #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) QDebug operator<<(QDebug dbg, const QJsonValue &o) { diff --git a/src/corelib/serialization/qjsonvalue.h b/src/corelib/serialization/qjsonvalue.h index 316d3fdf45..d8e121524d 100644 --- a/src/corelib/serialization/qjsonvalue.h +++ b/src/corelib/serialization/qjsonvalue.h @@ -247,6 +247,8 @@ public: Q_DECLARE_SHARED_NOT_MOVABLE_UNTIL_QT6(QJsonValue) +Q_CORE_EXPORT uint qHash(const QJsonValue &value, uint seed = 0); + #if !defined(QT_NO_DEBUG_STREAM) && !defined(QT_JSON_READONLY) Q_CORE_EXPORT QDebug operator<<(QDebug, const QJsonValue &); #endif diff --git a/src/corelib/tools/qhashfunctions.h b/src/corelib/tools/qhashfunctions.h index e6ae7a0b85..d013c26d66 100644 --- a/src/corelib/tools/qhashfunctions.h +++ b/src/corelib/tools/qhashfunctions.h @@ -104,6 +104,11 @@ Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(const QBitArray &key, uint seed = Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qHash(QLatin1String key, uint seed = 0) Q_DECL_NOTHROW; Q_CORE_EXPORT Q_DECL_PURE_FUNCTION uint qt_hash(QStringView key, uint chained = 0) Q_DECL_NOTHROW; +Q_DECL_CONST_FUNCTION inline uint qHash(std::nullptr_t, uint seed = 0) Q_DECL_NOTHROW +{ + return qHash(reinterpret_cast(nullptr), seed); +} + template inline uint qHash(const T *key, uint seed = 0) Q_DECL_NOTHROW { return qHash(reinterpret_cast(key), seed); diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp index 953e2bf6be..890792fa2f 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase.cpp @@ -799,9 +799,9 @@ enum PlatformFieldValue { PlatformId_Microsoft = 3 }; -FontNames qt_getCanonicalFontNames(const uchar *table, quint32 bytes) +QFontNames qt_getCanonicalFontNames(const uchar *table, quint32 bytes) { - FontNames out; + QFontNames out; const int NameRecordSize = 12; const int MS_LangIdEnglish = 0x009; @@ -947,7 +947,7 @@ QString qt_getEnglishName(const QString &familyName, bool includeStyle) goto error; { - const FontNames names = qt_getCanonicalFontNames(table, bytes); + const QFontNames names = qt_getCanonicalFontNames(table, bytes); i18n_name = names.name; if (includeStyle) i18n_name += QLatin1Char(' ') + names.style; @@ -963,9 +963,9 @@ error: } // Note this duplicates parts of qt_getEnglishName, we should try to unify the two functions. -FontNames qt_getCanonicalFontNames(const LOGFONT &lf) +QFontNames qt_getCanonicalFontNames(const LOGFONT &lf) { - FontNames fontNames; + QFontNames fontNames; HDC hdc = GetDC(0); HFONT hfont = CreateFontIndirect(&lf); @@ -1054,7 +1054,7 @@ static bool addFontToDatabase(QString familyName, QString subFamilyStyle; if (ttf) { // Look-up names registered in the font - FontNames canonicalNames = qt_getCanonicalFontNames(logFont); + QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) englishName = canonicalNames.name; if (!canonicalNames.preferredName.isEmpty()) { @@ -1488,7 +1488,7 @@ static void getFontTable(const uchar *fileBegin, const uchar *data, quint32 tag, } static void getFamiliesAndSignatures(const QByteArray &fontData, - QList *families, + QList *families, QVector *signatures) { const uchar *data = reinterpret_cast(fontData.constData()); @@ -1504,7 +1504,7 @@ static void getFamiliesAndSignatures(const QByteArray &fontData, getFontTable(data, font, MAKE_TAG('n', 'a', 'm', 'e'), &table, &length); if (!table) continue; - FontNames names = qt_getCanonicalFontNames(table, length); + QFontNames names = qt_getCanonicalFontNames(table, length); if (names.name.isEmpty()) continue; @@ -1535,7 +1535,7 @@ QStringList QWindowsFontDatabase::addApplicationFont(const QByteArray &fontData, WinApplicationFont font; font.fileName = fileName; QVector signatures; - QList families; + QList families; QStringList familyNames; if (!fontData.isEmpty()) { diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp index 299dfd40cd..f68ea54dcf 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_ft.cpp @@ -210,7 +210,7 @@ static bool addFontToDatabase(QString familyName, QString subFamilyStyle; if (ttf) { // Look-up names registered in the font - FontNames canonicalNames = qt_getCanonicalFontNames(logFont); + QFontNames canonicalNames = qt_getCanonicalFontNames(logFont); if (qt_localizedName(familyName) && !canonicalNames.name.isEmpty()) englishName = canonicalNames.name; if (!canonicalNames.preferredName.isEmpty()) { diff --git a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h index 30f5beefdf..9080d3ea9d 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/windows/qwindowsfontdatabase_p.h @@ -168,7 +168,8 @@ inline quint16 qt_getUShort(const unsigned char *p) return val; } -struct FontNames { +struct QFontNames +{ QString name; // e.g. "DejaVu Sans Condensed" QString style; // e.g. "Italic" QString preferredName; // e.g. "DejaVu Sans" @@ -177,7 +178,7 @@ struct FontNames { bool qt_localizedName(const QString &name); QString qt_getEnglishName(const QString &familyName, bool includeStyle = false); -FontNames qt_getCanonicalFontNames(const LOGFONT &lf); +QFontNames qt_getCanonicalFontNames(const LOGFONT &lf); QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index e29e5b8187..0df6264bcb 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -197,6 +197,7 @@ void QWindowsUser32DLL::init() enableMouseInPointer = (EnableMouseInPointer)library.resolve("EnableMouseInPointer"); getPointerType = (GetPointerType)library.resolve("GetPointerType"); getPointerInfo = (GetPointerInfo)library.resolve("GetPointerInfo"); + getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects"); getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo"); getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo"); getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo"); @@ -212,7 +213,8 @@ void QWindowsUser32DLL::init() bool QWindowsUser32DLL::supportsPointerApi() { - return enableMouseInPointer && getPointerType && getPointerInfo && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo; + return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects + && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo; } void QWindowsShcoreDLL::init() diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 3709d9deee..33bd42a669 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -89,6 +89,7 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *EnableMouseInPointer)(BOOL); typedef BOOL (WINAPI *GetPointerType)(UINT32, PVOID); typedef BOOL (WINAPI *GetPointerInfo)(UINT32, PVOID); + typedef BOOL (WINAPI *GetPointerDeviceRects)(HANDLE, RECT *, RECT *); typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID); typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID); typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID); @@ -105,6 +106,7 @@ struct QWindowsUser32DLL EnableMouseInPointer enableMouseInPointer = nullptr; GetPointerType getPointerType = nullptr; GetPointerInfo getPointerInfo = nullptr; + GetPointerDeviceRects getPointerDeviceRects = nullptr; GetPointerTouchInfo getPointerTouchInfo = nullptr; GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr; GetPointerPenInfo getPointerPenInfo = nullptr; diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index c11be972b0..abd4d56da0 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -428,9 +428,18 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin return false; // Let DefWindowProc() handle Non Client messages. POINTER_PEN_INFO *penInfo = static_cast(vPenInfo); + + RECT pRect, dRect; + if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) + return false; + const quint32 pointerId = penInfo->pointerInfo.pointerId; const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y); const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); + const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left) + / (pRect.right - pRect.left) * (dRect.right - dRect.left), + dRect.top + qreal(penInfo->pointerInfo.ptHimetricLocation.y - pRect.top) + / (pRect.bottom - pRect.top) * (dRect.bottom - dRect.top)); const qreal pressure = (penInfo->penMask & PEN_MASK_PRESSURE) ? qreal(penInfo->pressure) / 1024.0 : 0.5; const qreal rotation = (penInfo->penMask & PEN_MASK_ROTATION) ? qreal(penInfo->rotation) : 0.0; const qreal tangentialPressure = 0.0; @@ -438,6 +447,13 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin const int yTilt = (penInfo->penMask & PEN_MASK_TILT_Y) ? penInfo->tiltY : 0; const int z = 0; + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaEvents).noquote().nospace() << showbase + << __FUNCTION__ << " pointerId=" << pointerId + << " globalPos=" << globalPos << " localPos=" << localPos << " hiResGlobalPos=" << hiResGlobalPos + << " message=" << hex << msg.message + << " flags=" << hex << penInfo->pointerInfo.pointerFlags; + const QTabletEvent::TabletDevice device = QTabletEvent::Stylus; QTabletEvent::PointerType type; Qt::MouseButtons mouseButtons; @@ -491,16 +507,18 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin } const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); - QWindowSystemInterface::handleTabletEvent(target, localPos, globalPos, device, type, mouseButtons, + QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons, pressure, xTilt, yTilt, tangentialPressure, rotation, z, pointerId, keyModifiers); - QEvent::Type eventType; - Qt::MouseButton button; - getMouseEventInfo(msg.message, penInfo->pointerInfo.ButtonChangeType, globalPos, &eventType, &button); + if (!(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)) { + QEvent::Type eventType; + Qt::MouseButton button; + getMouseEventInfo(msg.message, penInfo->pointerInfo.ButtonChangeType, globalPos, &eventType, &button); - QWindowSystemInterface::handleMouseEvent(target, localPos, globalPos, mouseButtons, button, eventType, - keyModifiers, Qt::MouseEventSynthesizedByQt); + QWindowSystemInterface::handleMouseEvent(target, localPos, globalPos, mouseButtons, button, eventType, + keyModifiers, Qt::MouseEventSynthesizedByQt); + } break; } } diff --git a/src/printsupport/kernel/qprintengine_win.cpp b/src/printsupport/kernel/qprintengine_win.cpp index 6f263e5ea8..5ee93a46b3 100644 --- a/src/printsupport/kernel/qprintengine_win.cpp +++ b/src/printsupport/kernel/qprintengine_win.cpp @@ -1779,39 +1779,26 @@ static void draw_text_item_win(const QPointF &pos, const QTextItemInt &ti, HDC h QTransform matrix = QTransform::fromTranslate(baseline_pos.x(), baseline_pos.y()); ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, _glyphs, positions); - if (_glyphs.size() == 0) { + if (_glyphs.isEmpty()) { SelectObject(hdc, old_font); return; } - bool outputEntireItem = _glyphs.size() > 0; - - if (outputEntireItem) { - options |= ETO_PDY; - QVarLengthArray glyphDistances(_glyphs.size() * 2); - QVarLengthArray g(_glyphs.size()); - for (int i=0; i<_glyphs.size() - 1; ++i) { - glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x); - glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y); - g[i] = _glyphs[i]; - } - glyphDistances[(_glyphs.size() - 1) * 2] = 0; - glyphDistances[(_glyphs.size() - 1) * 2 + 1] = 0; - g[_glyphs.size() - 1] = _glyphs[_glyphs.size() - 1]; - ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, 0, - g.constData(), _glyphs.size(), - glyphDistances.data()); - } else { - int i = 0; - while(i < _glyphs.size()) { - wchar_t g = _glyphs[i]; - - ExtTextOut(hdc, qRound(positions[i].x), - qRound(positions[i].y), options, 0, - &g, 1, 0); - ++i; - } + options |= ETO_PDY; + QVarLengthArray glyphDistances(_glyphs.size() * 2); + QVarLengthArray g(_glyphs.size()); + const int lastGlyph = _glyphs.size() - 1; + for (int i = 0; i < lastGlyph; ++i) { + glyphDistances[i * 2] = qRound(positions[i + 1].x) - qRound(positions[i].x); + glyphDistances[i * 2 + 1] = qRound(positions[i + 1].y) - qRound(positions[i].y); + g[i] = _glyphs[i]; } + glyphDistances[lastGlyph * 2] = 0; + glyphDistances[lastGlyph * 2 + 1] = 0; + g[lastGlyph] = _glyphs[lastGlyph]; + ExtTextOut(hdc, qRound(positions[0].x), qRound(positions[0].y), options, nullptr, + g.constData(), _glyphs.size(), + glyphDistances.data()); } win_xform.eM11 = win_xform.eM22 = 1.0; diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp index 628bfa1880..daadcb8a0e 100644 --- a/src/sql/kernel/qsqlquery.cpp +++ b/src/sql/kernel/qsqlquery.cpp @@ -942,10 +942,12 @@ void QSqlQuery::clear() query. See the \l{QSqlQuery examples}{Detailed Description} for examples. - Portability note: Some databases choose to delay preparing a query + Portability notes: Some databases choose to delay preparing a query until it is executed the first time. In this case, preparing a syntactically wrong query succeeds, but every consecutive exec() will fail. + When the database does not support named placeholders directly, + the placeholder can only contain characters in the range [a-zA-Z0-9_]. For SQLite, the query string can contain only one statement at a time. If more than one statement is given, the function returns \c false. diff --git a/src/sql/models/qsqlquerymodel_p.h b/src/sql/models/qsqlquerymodel_p.h index 76aaf00c88..d5ca2f89cb 100644 --- a/src/sql/models/qsqlquerymodel_p.h +++ b/src/sql/models/qsqlquerymodel_p.h @@ -75,7 +75,7 @@ public: void initColOffsets(int size); int columnInQuery(int modelColumn) const; - mutable QSqlQuery query; + mutable QSqlQuery query = { QSqlQuery(0) }; mutable QSqlError error; QModelIndex bottom; QSqlRecord rec; diff --git a/src/sql/models/qsqltablemodel_p.h b/src/sql/models/qsqltablemodel_p.h index faa1b30803..bb568ab444 100644 --- a/src/sql/models/qsqltablemodel_p.h +++ b/src/sql/models/qsqltablemodel_p.h @@ -93,7 +93,7 @@ public: QSqlTableModel::EditStrategy strategy; bool busyInsertingRows; - QSqlQuery editQuery; + QSqlQuery editQuery = { QSqlQuery(0) }; QSqlIndex primaryIndex; QString tableName; QString filter; diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 70f8b28299..6857ccd8bb 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -3369,7 +3369,9 @@ void QHeaderViewPrivate::setupSectionIndicator(int section, int position) sectionIndicator->resize(w, h); #endif - QPixmap pm(w, h); + const qreal pixmapDevicePixelRatio = q->devicePixelRatioF(); + QPixmap pm(QSize(w, h) * pixmapDevicePixelRatio); + pm.setDevicePixelRatio(pixmapDevicePixelRatio); pm.fill(QColor(0, 0, 0, 45)); QRect rect(0, 0, w, h); diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 011515dcba..4bfaf23d22 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -2744,6 +2744,37 @@ void tst_QLocale::formattedDataSize_data() #undef ROWQ #undef ROWB } + + // Languages which don't use a Latin alphabet + + const QLocale::DataSizeFormats iecFormat = QLocale::DataSizeIecFormat; + const QLocale::DataSizeFormats traditionalFormat = QLocale::DataSizeTraditionalFormat; + const QLocale::DataSizeFormats siFormat = QLocale::DataSizeSIFormat; + const QLocale::Language lang = QLocale::Russian; + + QTest::newRow("Russian-IEC-0") << lang << 2 << iecFormat << 0 << QString("0 \u0431\u0430\u0439\u0442\u044B"); + QTest::newRow("Russian-IEC-10") << lang << 2 << iecFormat << 10 << QString("10 \u0431\u0430\u0439\u0442\u044B"); + // CLDR doesn't provide IEC prefixes (yet?) so they aren't getting translated + QTest::newRow("Russian-IEC-12Ki") << lang << 2 << iecFormat << 12345 << QString("12,06 KiB"); + QTest::newRow("Russian-IEC-16Ki") << lang << 2 << iecFormat << 16384 << QString("16,00 KiB"); + QTest::newRow("Russian-IEC-1235k") << lang << 2 << iecFormat << 1234567 << QString("1,18 MiB"); + QTest::newRow("Russian-IEC-1374k") << lang << 2 << iecFormat << 1374744 << QString("1,31 MiB"); + QTest::newRow("Russian-IEC-1234M") << lang << 2 << iecFormat << 1234567890 << QString("1,15 GiB"); + + QTest::newRow("Russian-Trad-0") << lang << 2 << traditionalFormat << 0 << QString("0 \u0431\u0430\u0439\u0442\u044B"); + QTest::newRow("Russian-Trad-10") << lang << 2 << traditionalFormat << 10 << QString("10 \u0431\u0430\u0439\u0442\u044B"); + QTest::newRow("Russian-Trad-12Ki") << lang << 2 << traditionalFormat << 12345 << QString("12,06 \u043A\u0411"); + QTest::newRow("Russian-Trad-16Ki") << lang << 2 << traditionalFormat << 16384 << QString("16,00 \u043A\u0411"); + QTest::newRow("Russian-Trad-1235k") << lang << 2 << traditionalFormat << 1234567 << QString("1,18 \u041C\u0411"); + QTest::newRow("Russian-Trad-1374k") << lang << 2 << traditionalFormat << 1374744 << QString("1,31 \u041C\u0411"); + QTest::newRow("Russian-Trad-1234M") << lang << 2 << traditionalFormat << 1234567890 << QString("1,15 \u0413\u0411"); + + QTest::newRow("Russian-Decimal-0") << lang << 2 << siFormat << 0 << QString("0 \u0431\u0430\u0439\u0442\u044B"); + QTest::newRow("Russian-Decimal-10") << lang << 2 << siFormat << 10 << QString("10 \u0431\u0430\u0439\u0442\u044B"); + QTest::newRow("Russian-Decimal-16Ki") << lang << 2 << siFormat << 16384 << QString("16,38 \u043A\u0411"); + QTest::newRow("Russian-Decimal-1234k") << lang << 2 << siFormat << 1234567 << QString("1,23 \u041C\u0411"); + QTest::newRow("Russian-Decimal-1374k") << lang << 2 << siFormat << 1374744 << QString("1,37 \u041C\u0411"); + QTest::newRow("Russian-Decimal-1234M") << lang << 2 << siFormat << 1234567890 << QString("1,23 \u0413\u0411"); } void tst_QLocale::formattedDataSize() diff --git a/tests/auto/other/gestures/BLACKLIST b/tests/auto/other/gestures/BLACKLIST index 7f36054c6e..ff6d2fa48e 100644 --- a/tests/auto/other/gestures/BLACKLIST +++ b/tests/auto/other/gestures/BLACKLIST @@ -1,5 +1,6 @@ [] rhel-7.4 +ubuntu-18.04 [customGesture] # QTBUG-67254 ubuntu diff --git a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp index 430fa981d5..da31f437d9 100644 --- a/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp +++ b/tests/auto/sql/models/qsqltablemodel/tst_qsqltablemodel.cpp @@ -31,11 +31,29 @@ #include "../../kernel/qsqldatabase/tst_databases.h" #include #include +#include const QString test(qTableName("test", __FILE__, QSqlDatabase())), test2(qTableName("test2", __FILE__, QSqlDatabase())), test3(qTableName("test3", __FILE__, QSqlDatabase())); +// In order to catch when the warning message occurs, indicating that the database belongs to another +// thread, we have to install our own message handler. To ensure that the test reporting still happens +// as before, we call the originating one. +// +// For now, this is only called inside the modelInAnotherThread() test +QtMessageHandler oldHandler = nullptr; + +void sqlTableModelMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + if (type == QtWarningMsg && + msg == "QSqlDatabasePrivate::database: requested database does not " + "belong to the calling thread.") { + QFAIL("Requested database does not belong to the calling thread."); + } + if (oldHandler) + oldHandler(type, context, msg); +} class tst_QSqlTableModel : public QObject { @@ -116,6 +134,7 @@ private slots: void sqlite_bigTable_data() { generic_data("QSQLITE"); } void sqlite_bigTable(); + void modelInAnotherThread(); // bug specific tests void insertRecordBeforeSelect_data() { generic_data(); } @@ -276,6 +295,10 @@ void tst_QSqlTableModel::init() void tst_QSqlTableModel::cleanup() { recreateTestTables(); + if (oldHandler) { + qInstallMessageHandler(oldHandler); + oldHandler = nullptr; + } } void tst_QSqlTableModel::select() @@ -2100,5 +2123,29 @@ void tst_QSqlTableModel::invalidFilterAndHeaderData() QVERIFY(!v.isValid()); } +class SqlThread : public QThread +{ +public: + SqlThread() : QThread() {} + void run() + { + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "non-default-connection"); + QSqlTableModel stm(nullptr, db); + isDone = true; + } + bool isDone = false; +}; + +void tst_QSqlTableModel::modelInAnotherThread() +{ + oldHandler = qInstallMessageHandler(sqlTableModelMessageHandler); + QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); + CHECK_DATABASE(db); + SqlThread t; + t.start(); + QTRY_VERIFY(t.isDone); + QVERIFY(t.isFinished()); +} + QTEST_MAIN(tst_QSqlTableModel) #include "tst_qsqltablemodel.moc"