diff options
29 files changed, 369 insertions, 156 deletions
diff --git a/examples/widgets/itemviews/spreadsheet/printview.cpp b/examples/widgets/itemviews/spreadsheet/printview.cpp index 7db1a6bad9..7700b4ed6a 100644 --- a/examples/widgets/itemviews/spreadsheet/printview.cpp +++ b/examples/widgets/itemviews/spreadsheet/printview.cpp @@ -50,8 +50,12 @@ #include "printview.h" -#ifndef QT_NO_PRINTER -#include <QPrinter> +#if defined(QT_PRINTSUPPORT_LIB) +# include <QtPrintSupport/qtprintsupportglobal.h> + +# if QT_CONFIG(printer) +# include <QPrinter> +# endif #endif PrintView::PrintView() @@ -62,9 +66,11 @@ PrintView::PrintView() void PrintView::print(QPrinter *printer) { -#ifndef QT_NO_PRINTER +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) resize(printer->width(), printer->height()); render(printer); +#else + Q_UNUSED(printer) #endif } diff --git a/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp b/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp index fc7fbb872c..ac8ea7d437 100644 --- a/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp +++ b/examples/widgets/itemviews/spreadsheet/spreadsheet.cpp @@ -638,7 +638,7 @@ QString encode_pos(int row, int col) void SpreadSheet::print() { -#if QT_CONFIG(printpreviewdialog) +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printpreviewdialog) QPrinter printer(QPrinter::ScreenResolution); QPrintPreviewDialog dlg(&printer); PrintView view; diff --git a/examples/widgets/richtext/textedit/textedit.cpp b/examples/widgets/richtext/textedit/textedit.cpp index 7708b25a24..c9173bcb99 100644 --- a/examples/widgets/richtext/textedit/textedit.cpp +++ b/examples/widgets/richtext/textedit/textedit.cpp @@ -197,7 +197,7 @@ void TextEdit::setupFileActions() a->setPriority(QAction::LowPriority); menu->addSeparator(); -#ifndef QT_NO_PRINTER +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) const QIcon printIcon = QIcon::fromTheme("document-print", QIcon(rsrcPath + "/fileprint.png")); a = menu->addAction(printIcon, tr("&Print..."), this, &TextEdit::filePrint); a->setPriority(QAction::LowPriority); @@ -559,7 +559,7 @@ void TextEdit::filePrint() void TextEdit::filePrintPreview() { -#if QT_CONFIG(printpreviewdialog) +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printpreviewdialog) QPrinter printer(QPrinter::HighResolution); QPrintPreviewDialog preview(&printer, this); connect(&preview, &QPrintPreviewDialog::paintRequested, this, &TextEdit::printPreview); @@ -569,17 +569,17 @@ void TextEdit::filePrintPreview() void TextEdit::printPreview(QPrinter *printer) { -#ifdef QT_NO_PRINTER - Q_UNUSED(printer); -#else +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) textEdit->print(printer); +#else + Q_UNUSED(printer) #endif } void TextEdit::filePrintPdf() { -#ifndef QT_NO_PRINTER +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) //! [0] QFileDialog fileDialog(this, tr("Export PDF")); fileDialog.setAcceptMode(QFileDialog::AcceptSave); diff --git a/examples/widgets/tutorials/notepad/notepad.pro b/examples/widgets/tutorials/notepad/notepad.pro index 6451f22735..efe16fc2a2 100644 --- a/examples/widgets/tutorials/notepad/notepad.pro +++ b/examples/widgets/tutorials/notepad/notepad.pro @@ -1,6 +1,8 @@ TEMPLATE = app TARGET = notepad +QT += widgets + qtHaveModule(printsupport): QT += printsupport requires(qtConfig(fontdialog)) diff --git a/examples/widgets/widgets/imageviewer/imageviewer.cpp b/examples/widgets/widgets/imageviewer/imageviewer.cpp index 7a0f49308b..7de0c7c45b 100644 --- a/examples/widgets/widgets/imageviewer/imageviewer.cpp +++ b/examples/widgets/widgets/imageviewer/imageviewer.cpp @@ -69,10 +69,11 @@ #include <QStatusBar> #if defined(QT_PRINTSUPPORT_LIB) -#include <QtPrintSupport/qtprintsupportglobal.h> -#if QT_CONFIG(printdialog) -#include <QPrintDialog> -#endif +# include <QtPrintSupport/qtprintsupportglobal.h> + +# if QT_CONFIG(printdialog) +# include <QPrintDialog> +# endif #endif //! [0] diff --git a/examples/widgets/widgets/imageviewer/imageviewer.h b/examples/widgets/widgets/imageviewer/imageviewer.h index 49c7ac205b..9c8388d470 100644 --- a/examples/widgets/widgets/imageviewer/imageviewer.h +++ b/examples/widgets/widgets/imageviewer/imageviewer.h @@ -53,8 +53,12 @@ #include <QMainWindow> #include <QImage> -#ifndef QT_NO_PRINTER -#include <QPrinter> +#if defined(QT_PRINTSUPPORT_LIB) +# include <QtPrintSupport/qtprintsupportglobal.h> + +# if QT_CONFIG(printer) +# include <QPrinter> +# endif #endif QT_BEGIN_NAMESPACE @@ -100,7 +104,7 @@ private: QScrollArea *scrollArea; double scaleFactor = 1; -#ifndef QT_NO_PRINTER +#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer) QPrinter printer; #endif diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 61d37d5062..122b95ed57 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -1949,8 +1949,9 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved( example.) If you are working with large amounts of filtering and have to invoke - invalidateFilter() repeatedly, using reset() may be more efficient, - depending on the implementation of your model. However, reset() returns the + invalidateFilter() repeatedly, using beginResetModel() / endResetModel() may + be more efficient, depending on the implementation of your model. However, + beginResetModel() / endResetModel() returns the proxy model to its original state, losing selection information, and will cause the proxy model to be repopulated. diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 99452eb606..21254108e3 100644 --- a/src/corelib/kernel/qmetatype.cpp +++ b/src/corelib/kernel/qmetatype.cpp @@ -615,7 +615,8 @@ QMetaTypeComparatorRegistry; typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int> QMetaTypeDebugStreamRegistry; -Q_STATIC_ASSERT(std::is_pod<QMetaTypeInterface>::value); +Q_STATIC_ASSERT(std::is_trivial<QMetaTypeInterface>::value); +Q_STATIC_ASSERT(std::is_standard_layout<QMetaTypeInterface>::value); Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE); Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes) diff --git a/src/corelib/plugin/qfactoryloader.cpp b/src/corelib/plugin/qfactoryloader.cpp index 14de8db1c6..400c8bf05f 100644 --- a/src/corelib/plugin/qfactoryloader.cpp +++ b/src/corelib/plugin/qfactoryloader.cpp @@ -389,15 +389,10 @@ QObject *QFactoryLoader::instance(int index) const QMutexLocker lock(&d->mutex); if (index < d->libraryList.size()) { QLibraryPrivate *library = d->libraryList.at(index); - if (library->instance || library->loadPlugin()) { - if (!library->inst) - library->inst = library->instance(); - QObject *obj = library->inst.data(); - if (obj) { - if (!obj->parent()) - obj->moveToThread(QCoreApplicationPrivate::mainThread()); - return obj; - } + if (QObject *obj = library->pluginInstance()) { + if (!obj->parent()) + obj->moveToThread(QCoreApplicationPrivate::mainThread()); + return obj; } return nullptr; } diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index b3a95d4f26..595f9097c1 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -407,7 +407,7 @@ inline void QLibraryStore::cleanup() QLibraryPrivate *lib = it.value(); if (lib->libraryRefCount.loadRelaxed() == 1) { if (lib->libraryUnloadCount.loadRelaxed() > 0) { - Q_ASSERT(lib->pHnd); + Q_ASSERT(lib->pHnd.loadRelaxed()); lib->libraryUnloadCount.storeRelaxed(1); #ifdef __GLIBC__ // glibc has a bug in unloading from global destructors @@ -498,8 +498,7 @@ inline void QLibraryStore::releaseLibrary(QLibraryPrivate *lib) } QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints) - : pHnd(nullptr), fileName(canonicalFileName), fullVersion(version), instance(nullptr), - libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin) + : fileName(canonicalFileName), fullVersion(version), pluginState(MightBeAPlugin) { loadHintsInt.storeRelaxed(loadHints); if (canonicalFileName.isEmpty()) @@ -519,7 +518,7 @@ QLibraryPrivate::~QLibraryPrivate() void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh) { // if the library is already loaded, we can't change the load hints - if (pHnd) + if (pHnd.loadRelaxed()) return; loadHintsInt.storeRelaxed(lh); @@ -527,7 +526,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh) QFunctionPointer QLibraryPrivate::resolve(const char *symbol) { - if (!pHnd) + if (!pHnd.loadRelaxed()) return nullptr; return resolve_sys(symbol); } @@ -539,9 +538,36 @@ void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh) mergeLoadHints(lh); } +QObject *QLibraryPrivate::pluginInstance() +{ + // first, check if the instance is cached and hasn't been deleted + QObject *obj = (QMutexLocker(&mutex), inst.data()); + if (obj) + return obj; + + // We need to call the plugin's factory function. Is that cached? + // skip increasing the reference count (why? -Thiago) + QtPluginInstanceFunction factory = instanceFactory.loadAcquire(); + if (!factory) + factory = loadPlugin(); + + if (!factory) + return nullptr; + + obj = factory(); + + // cache again + QMutexLocker locker(&mutex); + if (inst) + obj = inst; + else + inst = obj; + return obj; +} + bool QLibraryPrivate::load() { - if (pHnd) { + if (pHnd.loadRelaxed()) { libraryUnloadCount.ref(); return true; } @@ -550,7 +576,9 @@ bool QLibraryPrivate::load() Q_TRACE(QLibraryPrivate_load_entry, fileName); + mutex.lock(); bool ret = load_sys(); + mutex.unlock(); if (qt_debug_component()) { if (ret) { qDebug() << "loaded library" << fileName; @@ -573,9 +601,10 @@ bool QLibraryPrivate::load() bool QLibraryPrivate::unload(UnloadFlag flag) { - if (!pHnd) + if (!pHnd.loadRelaxed()) return false; if (libraryUnloadCount.loadRelaxed() > 0 && !libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to + QMutexLocker locker(&mutex); delete inst.data(); if (flag == NoUnloadSys || unload_sys()) { if (qt_debug_component()) @@ -584,12 +613,13 @@ bool QLibraryPrivate::unload(UnloadFlag flag) //when the library is unloaded, we release the reference on it so that 'this' //can get deleted libraryRefCount.deref(); - pHnd = nullptr; - instance = nullptr; + pHnd.storeRelaxed(nullptr); + instanceFactory.storeRelaxed(nullptr); + return true; } } - return (pHnd == nullptr); + return false; } void QLibraryPrivate::release() @@ -597,22 +627,23 @@ void QLibraryPrivate::release() QLibraryStore::releaseLibrary(this); } -bool QLibraryPrivate::loadPlugin() +QtPluginInstanceFunction QLibraryPrivate::loadPlugin() { - if (instance) { + if (auto ptr = instanceFactory.loadAcquire()) { libraryUnloadCount.ref(); - return true; + return ptr; } if (pluginState == IsNotAPlugin) - return false; + return nullptr; if (load()) { - instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance"); - return instance; + auto ptr = reinterpret_cast<QtPluginInstanceFunction>(resolve("qt_plugin_instance")); + instanceFactory.storeRelease(ptr); // two threads may store the same value + return ptr; } if (qt_debug_component()) qWarning() << "QLibraryPrivate::loadPlugin failed on" << fileName << ":" << errorString; pluginState = IsNotAPlugin; - return false; + return nullptr; } /*! @@ -719,6 +750,7 @@ bool QLibraryPrivate::isPlugin() void QLibraryPrivate::updatePluginState() { + QMutexLocker locker(&mutex); errorString.clear(); if (pluginState != MightBeAPlugin) return; @@ -739,7 +771,7 @@ void QLibraryPrivate::updatePluginState() } #endif - if (!pHnd) { + if (!pHnd.loadRelaxed()) { // scan for the plugin metadata without loading success = findPatternUnloaded(fileName, this); } else { @@ -803,7 +835,7 @@ bool QLibrary::load() if (!d) return false; if (did_load) - return d->pHnd; + return d->pHnd.loadRelaxed(); did_load = true; return d->load(); } @@ -839,7 +871,7 @@ bool QLibrary::unload() */ bool QLibrary::isLoaded() const { - return d && d->pHnd; + return d && d->pHnd.loadRelaxed(); } @@ -950,8 +982,10 @@ void QLibrary::setFileName(const QString &fileName) QString QLibrary::fileName() const { - if (d) + if (d) { + QMutexLocker locker(&d->mutex); return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName; + } return QString(); } @@ -1092,7 +1126,12 @@ QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &versi */ QString QLibrary::errorString() const { - return (!d || d->errorString.isEmpty()) ? tr("Unknown error") : d->errorString; + QString str; + if (d) { + QMutexLocker locker(&d->mutex); + str = d->errorString; + } + return str.isEmpty() ? tr("Unknown error") : str; } /*! diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h index a58547a2c3..3ca544b2de 100644 --- a/src/corelib/plugin/qlibrary_p.h +++ b/src/corelib/plugin/qlibrary_p.h @@ -54,10 +54,10 @@ #include <QtCore/private/qglobal_p.h> #include "QtCore/qlibrary.h" +#include "QtCore/qmutex.h" #include "QtCore/qpointer.h" #include "QtCore/qstringlist.h" #include "QtCore/qplugin.h" -#include "QtCore/qsharedpointer.h" #ifdef Q_OS_WIN # include "QtCore/qt_windows.h" #endif @@ -72,21 +72,18 @@ class QLibraryStore; class QLibraryPrivate { public: - #ifdef Q_OS_WIN - HINSTANCE + using Handle = HINSTANCE; #else - void * + using Handle = void *; #endif - pHnd; - enum UnloadFlag { UnloadSys, NoUnloadSys }; - QString fileName, qualifiedFileName; - QString fullVersion; + const QString fileName; + const QString fullVersion; bool load(); - bool loadPlugin(); // loads and resolves instance + QtPluginInstanceFunction loadPlugin(); // loads and resolves instance bool unload(UnloadFlag flag = UnloadSys); void release(); QFunctionPointer resolve(const char *); @@ -94,17 +91,22 @@ public: QLibrary::LoadHints loadHints() const { return QLibrary::LoadHints(loadHintsInt.loadRelaxed()); } void setLoadHints(QLibrary::LoadHints lh); + QObject *pluginInstance(); static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(), QLibrary::LoadHints loadHints = { }); static QStringList suffixes_sys(const QString &fullVersion); static QStringList prefixes_sys(); - QPointer<QObject> inst; - QtPluginInstanceFunction instance; - QJsonObject metaData; + QAtomicPointer<std::remove_pointer<QtPluginInstanceFunction>::type> instanceFactory; + QAtomicPointer<std::remove_pointer<Handle>::type> pHnd; + // the mutex protects the fields below + QMutex mutex; + QPointer<QObject> inst; // used by QFactoryLoader + QJsonObject metaData; QString errorString; + QString qualifiedFileName; void updatePluginState(); bool isPlugin(); diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 4a092abb3e..29813e5863 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -214,8 +214,9 @@ bool QLibraryPrivate::load_sys() #endif bool retry = true; - for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) { - for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) { + Handle hnd = nullptr; + for (int prefix = 0; retry && !hnd && prefix < prefixes.size(); prefix++) { + for (int suffix = 0; retry && !hnd && suffix < suffixes.size(); suffix++) { if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix))) continue; if (path.isEmpty() && prefixes.at(prefix).contains(QLatin1Char('/'))) @@ -232,7 +233,7 @@ bool QLibraryPrivate::load_sys() attempt = path + prefixes.at(prefix) + name + suffixes.at(suffix); } - pHnd = dlopen(QFile::encodeName(attempt), dlFlags); + hnd = dlopen(QFile::encodeName(attempt), dlFlags); #ifdef Q_OS_ANDROID if (!pHnd) { auto attemptFromBundle = attempt; @@ -248,7 +249,7 @@ bool QLibraryPrivate::load_sys() } #endif - if (!pHnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { + if (!hnd && fileName.startsWith(QLatin1Char('/')) && QFile::exists(attempt)) { // We only want to continue if dlopen failed due to that the shared library did not exist. // However, we are only able to apply this check for absolute filenames (since they are // not influenced by the content of LD_LIBRARY_PATH, /etc/ld.so.cache, DT_RPATH etc...) @@ -259,7 +260,7 @@ bool QLibraryPrivate::load_sys() } #ifdef Q_OS_MAC - if (!pHnd) { + if (!hnd) { QByteArray utf8Bundle = fileName.toUtf8(); QCFType<CFURLRef> bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast<const UInt8*>(utf8Bundle.data()), utf8Bundle.length(), true); QCFType<CFBundleRef> bundle = CFBundleCreate(NULL, bundleUrl); @@ -268,23 +269,24 @@ bool QLibraryPrivate::load_sys() char executableFile[FILENAME_MAX]; CFURLGetFileSystemRepresentation(url, true, reinterpret_cast<UInt8*>(executableFile), FILENAME_MAX); attempt = QString::fromUtf8(executableFile); - pHnd = dlopen(QFile::encodeName(attempt), dlFlags); + hnd = dlopen(QFile::encodeName(attempt), dlFlags); } } #endif - if (!pHnd) { + if (!hnd) { errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror()); } - if (pHnd) { + if (hnd) { qualifiedFileName = attempt; errorString.clear(); } - return (pHnd != nullptr); + pHnd.storeRelaxed(hnd); + return (hnd != nullptr); } bool QLibraryPrivate::unload_sys() { - if (dlclose(pHnd)) { + if (dlclose(pHnd.loadAcquire())) { #if defined (Q_OS_QNX) // Workaround until fixed in QNX; fixes crash in char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative" @@ -316,13 +318,7 @@ Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symb QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { - QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol)); - if (!address) { - errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( - QString::fromLatin1(symbol), fileName, qdlerror()); - } else { - errorString.clear(); - } + QFunctionPointer address = QFunctionPointer(dlsym(pHnd.loadAcquire(), symbol)); return address; } diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp index 05a93d467e..000bf76276 100644 --- a/src/corelib/plugin/qlibrary_win.cpp +++ b/src/corelib/plugin/qlibrary_win.cpp @@ -95,26 +95,27 @@ bool QLibraryPrivate::load_sys() attempts.prepend(QDir::rootPath() + fileName); #endif + Handle hnd = nullptr; for (const QString &attempt : qAsConst(attempts)) { #ifndef Q_OS_WINRT - pHnd = LoadLibrary(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(attempt).utf16())); + hnd = LoadLibrary(reinterpret_cast<const wchar_t*>(QDir::toNativeSeparators(attempt).utf16())); #else // Q_OS_WINRT QString path = QDir::toNativeSeparators(QDir::current().relativeFilePath(attempt)); - pHnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0); - if (pHnd) + hnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0); + if (hnd) qualifiedFileName = attempt; #endif // !Q_OS_WINRT // If we have a handle or the last error is something other than "unable // to find the module", then bail out - if (pHnd || ::GetLastError() != ERROR_MOD_NOT_FOUND) + if (hnd || ::GetLastError() != ERROR_MOD_NOT_FOUND) break; } #ifndef Q_OS_WINRT SetErrorMode(oldmode); #endif - if (!pHnd) { + if (!hnd) { errorString = QLibrary::tr("Cannot load library %1: %2").arg( QDir::toNativeSeparators(fileName), qt_error_string()); } else { @@ -123,7 +124,7 @@ bool QLibraryPrivate::load_sys() #ifndef Q_OS_WINRT wchar_t buffer[MAX_PATH]; - ::GetModuleFileName(pHnd, buffer, MAX_PATH); + ::GetModuleFileName(hnd, buffer, MAX_PATH); QString moduleFileName = QString::fromWCharArray(buffer); moduleFileName.remove(0, 1 + moduleFileName.lastIndexOf(QLatin1Char('\\'))); @@ -138,19 +139,20 @@ bool QLibraryPrivate::load_sys() HMODULE hmod; bool ok = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, - reinterpret_cast<const wchar_t *>(pHnd), + reinterpret_cast<const wchar_t *>(hnd), &hmod); - Q_ASSERT(!ok || hmod == pHnd); + Q_ASSERT(!ok || hmod == hnd); Q_UNUSED(ok); } #endif // !Q_OS_WINRT } - return (pHnd != 0); + pHnd.storeRelaxed(hnd); + return (pHnd != nullptr); } bool QLibraryPrivate::unload_sys() { - if (!FreeLibrary(pHnd)) { + if (!FreeLibrary(pHnd.loadAcquire())) { errorString = QLibrary::tr("Cannot unload library %1: %2").arg( QDir::toNativeSeparators(fileName), qt_error_string()); return false; @@ -161,13 +163,7 @@ bool QLibraryPrivate::unload_sys() QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { - FARPROC address = GetProcAddress(pHnd, symbol); - if (!address) { - errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( - QString::fromLatin1(symbol), QDir::toNativeSeparators(fileName), qt_error_string()); - } else { - errorString.clear(); - } + FARPROC address = GetProcAddress(pHnd.loadAcquire(), symbol); return QFunctionPointer(address); } QT_END_NAMESPACE diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp index f34578ea81..0a63b93762 100644 --- a/src/corelib/plugin/qpluginloader.cpp +++ b/src/corelib/plugin/qpluginloader.cpp @@ -196,9 +196,7 @@ QObject *QPluginLoader::instance() { if (!isLoaded() && !load()) return nullptr; - if (!d->inst && d->instance) - d->inst = d->instance(); - return d->inst.data(); + return d->pluginInstance(); } /*! @@ -233,7 +231,7 @@ bool QPluginLoader::load() if (!d || d->fileName.isEmpty()) return false; if (did_load) - return d->pHnd && d->instance; + return d->pHnd && d->instanceFactory.loadAcquire(); if (!d->isPlugin()) return false; did_load = true; @@ -275,7 +273,7 @@ bool QPluginLoader::unload() */ bool QPluginLoader::isLoaded() const { - return d && d->pHnd && d->instance; + return d && d->pHnd && d->instanceFactory.loadRelaxed(); } #if defined(QT_SHARED) diff --git a/src/corelib/serialization/qcborvalue_p.h b/src/corelib/serialization/qcborvalue_p.h index 48818e4c63..a74ac2ba10 100644 --- a/src/corelib/serialization/qcborvalue_p.h +++ b/src/corelib/serialization/qcborvalue_p.h @@ -115,7 +115,8 @@ struct ByteData QStringView asStringView() const{ return QStringView(utf16(), len / 2); } QString asQStringRaw() const { return QString::fromRawData(utf16(), len / 2); } }; -Q_STATIC_ASSERT(std::is_pod<ByteData>::value); +Q_STATIC_ASSERT(std::is_trivial<ByteData>::value); +Q_STATIC_ASSERT(std::is_standard_layout<ByteData>::value); } // namespace QtCbor Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE); diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 02c42eaf03..50faee4853 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1667,7 +1667,8 @@ namespace { QFontEngine *previousGlyphFontEngine; QFixed minw; - QFixed softHyphenWidth; + QFixed currentSoftHyphenWidth; + QFixed commitedSoftHyphenWidth; QFixed rightBearing; QFixed minimumRightBearing; @@ -1681,7 +1682,7 @@ namespace { QFixed calculateNewWidth(const QScriptLine &line) const { return line.textWidth + tmpData.textWidth + spaceData.textWidth - + softHyphenWidth + negativeRightBearing(); + + (line.textWidth > 0 ? currentSoftHyphenWidth : QFixed()) + negativeRightBearing(); } inline glyph_t currentGlyph() const @@ -1755,6 +1756,7 @@ inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs)) return true; + const QFixed oldTextWidth = line.textWidth; minw = qMax(minw, tmpData.textWidth); line += tmpData; line.textWidth += spaceData.textWidth; @@ -1765,6 +1767,11 @@ inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line) spaceData.textWidth = 0; spaceData.length = 0; + if (oldTextWidth != line.textWidth || currentSoftHyphenWidth > 0) { + commitedSoftHyphenWidth = currentSoftHyphenWidth; + currentSoftHyphenWidth = 0; + } + return false; } @@ -1837,7 +1844,6 @@ void QTextLine::layout_helper(int maxGlyphs) while (newItem < eng->layoutData->items.size()) { lbh.resetRightBearing(); - lbh.softHyphenWidth = 0; if (newItem != item) { item = newItem; const QScriptItem ¤t = eng->layoutData->items.at(item); @@ -1975,9 +1981,9 @@ void QTextLine::layout_helper(int maxGlyphs) } while (lbh.currentPosition < end); lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw); - if (lbh.currentPosition > 0 && lbh.currentPosition < end - && attributes[lbh.currentPosition].lineBreak - && eng->layoutData->string.at(lbh.currentPosition - 1).unicode() == QChar::SoftHyphen) { + if (lbh.currentPosition > 0 && lbh.currentPosition <= end + && (lbh.currentPosition == end || attributes[lbh.currentPosition].lineBreak) + && eng->layoutData->string.at(lbh.currentPosition - 1) == QChar::SoftHyphen) { // if we are splitting up a word because of // a soft hyphen then we ... // @@ -1994,10 +2000,7 @@ void QTextLine::layout_helper(int maxGlyphs) // want the soft-hyphen to slip into the next line // and thus become invisible again. // - if (line.length) - lbh.softHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; - else if (breakany) - lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; + lbh.currentSoftHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]]; } if (sb_or_ws|breakany) { @@ -2023,6 +2026,7 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.calculateRightBearing(); if (lbh.checkFullOtherwiseExtend(line)) { + // We are too wide to accept the next glyph with its bearing, so we restore the // right bearing to that of the previous glyph (the one that was already accepted), // so that the bearing can be be applied to the final width of the text below. @@ -2031,9 +2035,7 @@ void QTextLine::layout_helper(int maxGlyphs) else lbh.calculateRightBearingForPreviousGlyph(); - if (!breakany) { - line.textWidth += lbh.softHyphenWidth; - } + line.textWidth += lbh.commitedSoftHyphenWidth; goto found; } @@ -2045,6 +2047,7 @@ void QTextLine::layout_helper(int maxGlyphs) } LB_DEBUG("reached end of line"); lbh.checkFullOtherwiseExtend(line); + line.textWidth += lbh.commitedSoftHyphenWidth; found: line.textAdvance = line.textWidth; diff --git a/src/gui/text/qtextmarkdownimporter_p.h b/src/gui/text/qtextmarkdownimporter_p.h index e3b4bcd0f2..f12b725d8e 100644 --- a/src/gui/text/qtextmarkdownimporter_p.h +++ b/src/gui/text/qtextmarkdownimporter_p.h @@ -56,6 +56,7 @@ #include <QtGui/qpalette.h> #include <QtGui/qtextdocument.h> #include <QtGui/qtextlist.h> +#include <QtCore/qpointer.h> #include <QtCore/qstack.h> QT_BEGIN_NAMESPACE diff --git a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp index 478fe61a44..9cf5c9096e 100644 --- a/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp +++ b/src/platformsupport/devicediscovery/qdevicediscovery_udev.cpp @@ -46,7 +46,11 @@ #include <QSocketNotifier> #include <QLoggingCategory> +#ifdef Q_OS_FREEBSD +#include <dev/evdev/input.h> +#else #include <linux/input.h> +#endif QT_BEGIN_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbatom.cpp b/src/plugins/platforms/xcb/qxcbatom.cpp index 79b5ba06e6..ff5c50b702 100644 --- a/src/plugins/platforms/xcb/qxcbatom.cpp +++ b/src/plugins/platforms/xcb/qxcbatom.cpp @@ -122,6 +122,7 @@ static const char *xcb_atomnames = { "_NET_WM_STATE_MODAL\0" "_NET_WM_STATE_STAYS_ON_TOP\0" "_NET_WM_STATE_DEMANDS_ATTENTION\0" + "_NET_WM_STATE_HIDDEN\0" "_NET_WM_USER_TIME\0" "_NET_WM_USER_TIME_WINDOW\0" diff --git a/src/plugins/platforms/xcb/qxcbatom.h b/src/plugins/platforms/xcb/qxcbatom.h index 233d2eadb7..80b5887395 100644 --- a/src/plugins/platforms/xcb/qxcbatom.h +++ b/src/plugins/platforms/xcb/qxcbatom.h @@ -123,6 +123,7 @@ public: _NET_WM_STATE_MODAL, _NET_WM_STATE_STAYS_ON_TOP, _NET_WM_STATE_DEMANDS_ATTENTION, + _NET_WM_STATE_HIDDEN, _NET_WM_USER_TIME, _NET_WM_USER_TIME_WINDOW, diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5be04a984a..40106bbeaf 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -903,6 +903,8 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates() result |= NetWmStateStaysOnTop; if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) result |= NetWmStateDemandsAttention; + if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_HIDDEN))) + result |= NetWmStateHidden; } else { qCDebug(lcQpaXcb, "getting net wm state (%x), empty\n", m_window); } @@ -1074,6 +1076,9 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow() states |= NetWmStateBelow; } + if (window()->windowStates() & Qt::WindowMinimized) + states |= NetWmStateHidden; + if (window()->windowStates() & Qt::WindowFullScreen) states |= NetWmStateFullScreen; @@ -1107,6 +1112,8 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow() atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW))) atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW)); + if (states & NetWmStateHidden && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_HIDDEN))) + atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_HIDDEN)); if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN))) atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)); if (states & NetWmStateMaximizedHorz && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))) @@ -2204,10 +2211,16 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized)); } } - if (m_minimized) - newState = Qt::WindowMinimized; const NetWmStates states = netWmStates(); + // _NET_WM_STATE_HIDDEN should be set by the Window Manager to indicate that a window would + // not be visible on the screen if its desktop/viewport were active and its coordinates were + // within the screen bounds. The canonical example is that minimized windows should be in + // the _NET_WM_STATE_HIDDEN state. + if (m_minimized && (!connection()->wmSupport()->isSupportedByWM(NetWmStateHidden) + || states.testFlag(NetWmStateHidden))) + newState = Qt::WindowMinimized; + if (states & NetWmStateFullScreen) newState |= Qt::WindowFullScreen; if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert)) diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index d6f370eebe..0cdc40f82d 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -68,7 +68,8 @@ public: NetWmStateMaximizedVert = 0x10, NetWmStateModal = 0x20, NetWmStateStaysOnTop = 0x40, - NetWmStateDemandsAttention = 0x80 + NetWmStateDemandsAttention = 0x80, + NetWmStateHidden = 0x100 }; Q_DECLARE_FLAGS(NetWmStates, NetWmState) diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 58ed210d3b..2a9efaac95 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -546,12 +546,19 @@ void WriteInitialization::acceptUI(DomUI *node) m_output << m_option.indent << language::endFunctionDefinition("setupUi"); - if (!m_mainFormUsedInRetranslateUi && language::language() == Language::Cpp) { - // Mark varName as unused to avoid compiler warnings. - m_refreshInitialization += m_indent; - m_refreshInitialization += QLatin1String("(void)"); - m_refreshInitialization += varName ; - m_refreshInitialization += language::eol; + if (!m_mainFormUsedInRetranslateUi) { + if (language::language() == Language::Cpp) { + // Mark varName as unused to avoid compiler warnings. + m_refreshInitialization += m_indent; + m_refreshInitialization += QLatin1String("(void)"); + m_refreshInitialization += varName ; + m_refreshInitialization += language::eol; + } else if (language::language() == Language::Python) { + // output a 'pass' to have an empty function + m_refreshInitialization += m_indent; + m_refreshInitialization += QLatin1String("pass"); + m_refreshInitialization += language::eol; + } } m_output << m_option.indent diff --git a/src/xml/dom/qdom.cpp b/src/xml/dom/qdom.cpp index f63bf47e3e..29d31a20d5 100644 --- a/src/xml/dom/qdom.cpp +++ b/src/xml/dom/qdom.cpp @@ -65,6 +65,7 @@ #include <stdio.h> +#include <limits> QT_BEGIN_NAMESPACE @@ -4364,7 +4365,7 @@ void QDomElement::setAttribute(const QString& name, float value) if (!impl) return; QString x; - x.setNum(value); + x.setNum(value, 'g', 8); IMPL->setAttribute(name, x); } @@ -4378,7 +4379,7 @@ void QDomElement::setAttribute(const QString& name, double value) if (!impl) return; QString x; - x.setNum(value); + x.setNum(value, 'g', 17); IMPL->setAttribute(name, x); } @@ -4547,7 +4548,7 @@ void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, doub if (!impl) return; QString x; - x.setNum(value); + x.setNum(value, 'g', 17); IMPL->setAttributeNS(nsURI, qName, x); } diff --git a/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST b/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST deleted file mode 100644 index 2317cf886c..0000000000 --- a/tests/auto/corelib/kernel/qelapsedtimer/BLACKLIST +++ /dev/null @@ -1,3 +0,0 @@ -[elapsed] -macos -windows-10 diff --git a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp index e0d09b0813..50c4d9b467 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp @@ -368,7 +368,7 @@ void tst_QLibrary::errorString_data() QTest::newRow("bad load()") << (int)Load << QString("nosuchlib") << false << QString("Cannot load library nosuchlib: .*"); QTest::newRow("call errorString() on QLibrary with no d-pointer (crashtest)") << (int)(Load | DontSetFileName) << QString() << false << QString("Unknown error"); - QTest::newRow("bad resolve") << (int)Resolve << appDir + "/mylib" << false << QString("Cannot resolve symbol \"nosuchsymbol\" in \\S+: .*"); + QTest::newRow("bad resolve") << (int)Resolve << appDir + "/mylib" << false << QString("Unknown error"); QTest::newRow("good resolve") << (int)Resolve << appDir + "/mylib" << true << QString("Unknown error"); #ifdef Q_OS_WIN diff --git a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp index 2dcca0209e..8466305832 100644 --- a/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp +++ b/tests/auto/gui/text/qtextlayout/tst_qtextlayout.cpp @@ -62,6 +62,7 @@ private slots: void lineBreaking(); #ifdef QT_BUILD_INTERNAL void simpleBoundingRect(); + void threeLineBoundingRect_data(); void threeLineBoundingRect(); void boundingRectWithLongLineAndNoWrap(); void forcedBreaks(); @@ -140,6 +141,7 @@ private slots: void showLineAndParagraphSeparatorsCrash(); void koreanWordWrap(); void tooManyDirectionalCharctersCrash_qtbug77819(); + void softHyphens(); private: QFont testFont; @@ -315,18 +317,49 @@ void tst_QTextLayout::simpleBoundingRect() QCOMPARE(layout.boundingRect(), QRectF(0, 0, width, QFontMetrics(testFont).height())); } +void tst_QTextLayout::threeLineBoundingRect_data() +{ + QTest::addColumn<QChar>("wordBoundary1"); + QTest::addColumn<QChar>("wordBoundary2"); + QTest::newRow("2x' '") << QChar(' ') << QChar(' '); + QTest::newRow("2x'\\n'") << QChar('\n') << QChar('\n'); + QTest::newRow("' ' + '\\n'") << QChar(' ') << QChar('\n'); + QTest::newRow("'\\n' + ' '") << QChar('\n') << QChar(' '); + QTest::newRow("2x'\\t'") << QChar('\t') << QChar('\t'); + QTest::newRow("2xsoft hyphen") << QChar(0xad) << QChar(0xad); + QTest::newRow("2x'-'") << QChar('-') << QChar('-'); + QTest::newRow("2x'/'") << QChar('/') << QChar('/'); + QTest::newRow("soft hyphen + ' '") << QChar(0xad) << QChar(' '); + QTest::newRow("soft hyphen + '\\n'") << QChar(0xad) << QChar('\n'); + QTest::newRow("soft hyphen + '-'") << QChar(0xad) << QChar('-'); + QTest::newRow("' ' + soft hyphen") << QChar(' ') << QChar(0xad); + QTest::newRow("'\\n' + soft hyphen") << QChar('\n') << QChar(0xad); + QTest::newRow("'-' + soft hyphen") << QChar('-') << QChar(0xad); +} + void tst_QTextLayout::threeLineBoundingRect() { /* stricter check. break text into three lines */ + QFETCH(QChar, wordBoundary1); + QFETCH(QChar, wordBoundary2); QString firstWord("hello"); - QString secondWord("world"); - QString thirdWord("test"); - QString text(firstWord + ' ' + secondWord + ' ' + thirdWord); - - const int firstLineWidth = firstWord.length() * testFont.pixelSize(); - const int secondLineWidth = secondWord.length() * testFont.pixelSize(); - const int thirdLineWidth = thirdWord.length() * testFont.pixelSize(); + QString secondWord("test"); + QString thirdWord("world"); + QString text(firstWord + wordBoundary1 + secondWord + wordBoundary2 + thirdWord); + + int firstLineWidth = firstWord.length() * testFont.pixelSize(); + int secondLineWidth = secondWord.length() * testFont.pixelSize(); + int thirdLineWidth = thirdWord.length() * testFont.pixelSize(); + // Trailing spaces do not count to line width: + if (!wordBoundary1.isSpace()) + firstLineWidth += testFont.pixelSize(); + if (!wordBoundary2.isSpace()) + secondLineWidth += testFont.pixelSize(); + // But trailing spaces do count to line length: + const int firstLineLength = firstWord.length() + 1; + const int secondLineLength = secondWord.length() + 1; + const int thirdLineLength = thirdWord.length(); const int longestLine = qMax(firstLineWidth, qMax(secondLineWidth, thirdLineWidth)); @@ -339,8 +372,7 @@ void tst_QTextLayout::threeLineBoundingRect() line.setLineWidth(firstLineWidth); line.setPosition(QPoint(0, y)); QCOMPARE(line.textStart(), pos); - // + 1 for trailing space - QCOMPARE(line.textLength(), firstWord.length() + 1); + QCOMPARE(line.textLength(), firstLineLength); QCOMPARE(qRound(line.naturalTextWidth()), firstLineWidth); pos += line.textLength(); @@ -349,9 +381,8 @@ void tst_QTextLayout::threeLineBoundingRect() line = layout.createLine(); line.setLineWidth(secondLineWidth); line.setPosition(QPoint(0, y)); - // + 1 for trailing space QCOMPARE(line.textStart(), pos); - QCOMPARE(line.textLength(), secondWord.length() + 1); + QCOMPARE(line.textLength(), secondLineLength); QCOMPARE(qRound(line.naturalTextWidth()), secondLineWidth); pos += line.textLength(); @@ -360,9 +391,8 @@ void tst_QTextLayout::threeLineBoundingRect() line = layout.createLine(); line.setLineWidth(secondLineWidth); line.setPosition(QPoint(0, y)); - // no trailing space here! QCOMPARE(line.textStart(), pos); - QCOMPARE(line.textLength(), thirdWord.length()); + QCOMPARE(line.textLength(), thirdLineLength); QCOMPARE(qRound(line.naturalTextWidth()), thirdLineWidth); y += qRound(line.ascent() + line.descent()); @@ -2352,5 +2382,111 @@ void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819() tl.endLayout(); } +void tst_QTextLayout::softHyphens() +{ + QString text = QStringLiteral("xxxx\u00ad") + QStringLiteral("xxxx\u00ad"); + + QFont font; + font.setPixelSize(14); + font.setHintingPreference(QFont::PreferNoHinting); + const float xAdvance = QFontMetricsF(font).horizontalAdvance(QChar('x')); + const float shyAdvance = QFontMetricsF(font).horizontalAdvance(QChar::SoftHyphen); + if (xAdvance < (shyAdvance + 1.0f)) + QSKIP("Default font not suitable for this test."); + QTextLayout layout(text, font); + QTextOption option; + option.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + layout.setTextOption(option); + + // Loose fit + // xxxx- | + // xxxx- | + { + int pos = 0; + int y = 0; + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(qCeil(5 * xAdvance) + 1); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), 5); + QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); + + pos += line.textLength(); + y += qRound(line.ascent() + line.descent()); + + line = layout.createLine(); + line.setLineWidth(qCeil(5 * xAdvance) + 1); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), 5); + QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); + layout.endLayout(); + } + + // Tight fit + // xxxx-| + // xxxx-| + { + int pos = 0; + int y = 0; + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(qCeil(4 * xAdvance + shyAdvance) + 1); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), 5); + QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); + + pos += line.textLength(); + y += qRound(line.ascent() + line.descent()); + + line = layout.createLine(); + line.setLineWidth(qCeil(4 * xAdvance + shyAdvance) + 1); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), 5); + QVERIFY(qAbs(line.naturalTextWidth() - (4 * xAdvance + shyAdvance)) <= 1); + layout.endLayout(); + } + + // Very tight fit + // xxxx| + // xxxx| + // - | + { + int pos = 0; + int y = 0; + layout.beginLayout(); + QTextLine line = layout.createLine(); + line.setLineWidth(qCeil(4 * xAdvance) + 2); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), 4); + QVERIFY(qAbs(line.naturalTextWidth() - 4 * xAdvance) <= 1); + + pos += line.textLength(); + y += qRound(line.ascent() + line.descent()); + + line = layout.createLine(); + line.setLineWidth(qCeil(4 * xAdvance) + 2); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), 5); + QVERIFY(qAbs(line.naturalTextWidth() - 4 * xAdvance) <= 1); + + pos += line.textLength(); + y += qRound(line.ascent() + line.descent()); + + line = layout.createLine(); + line.setLineWidth(qCeil(4 * xAdvance) + 2); + line.setPosition(QPoint(0, y)); + QCOMPARE(line.textStart(), pos); + QCOMPARE(line.textLength(), 1); + QVERIFY(qAbs(line.naturalTextWidth() - shyAdvance) <= 1); + layout.endLayout(); + } +} + QTEST_MAIN(tst_QTextLayout) #include "tst_qtextlayout.moc" diff --git a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST index 39d7b695f6..d3bfaba433 100644 --- a/tests/auto/widgets/kernel/qwidget_window/BLACKLIST +++ b/tests/auto/widgets/kernel/qwidget_window/BLACKLIST @@ -2,7 +2,3 @@ # QTBUG-66345 opensuse-42.3 ubuntu-16.04 -[setWindowState] -ubuntu-18.04 -rhel-7.6 - diff --git a/tests/auto/xml/dom/qdom/tst_qdom.cpp b/tests/auto/xml/dom/qdom/tst_qdom.cpp index a2a5b22cad..1a26376456 100644 --- a/tests/auto/xml/dom/qdom/tst_qdom.cpp +++ b/tests/auto/xml/dom/qdom/tst_qdom.cpp @@ -38,6 +38,7 @@ #include <QtTest/QtTest> #include <QtXml> #include <QVariant> +#include <cmath> QT_FORWARD_DECLARE_CLASS(QDomDocument) QT_FORWARD_DECLARE_CLASS(QDomNode) @@ -419,7 +420,9 @@ void tst_QDom::setGetAttributes() const int intVal = std::numeric_limits<int>::min(); const uint uintVal = std::numeric_limits<uint>::max(); const float floatVal = 0.1234f; - const double doubleVal = 0.1234; + const double doubleVal1 = 1./6.; + const double doubleVal2 = std::nextafter(doubleVal1, 1.); + const double doubleVal3 = std::nextafter(doubleVal2, 1.); rootNode.setAttribute("qstringVal", qstringVal); rootNode.setAttribute("qlonglongVal", qlonglongVal); @@ -427,7 +430,9 @@ void tst_QDom::setGetAttributes() rootNode.setAttribute("intVal", intVal); rootNode.setAttribute("uintVal", uintVal); rootNode.setAttribute("floatVal", floatVal); - rootNode.setAttribute("doubleVal", doubleVal); + rootNode.setAttribute("doubleVal1", doubleVal1); + rootNode.setAttribute("doubleVal2", doubleVal2); + rootNode.setAttribute("doubleVal3", doubleVal3); QDomElement nsNode = doc.createElement("NS"); rootNode.appendChild(nsNode); @@ -437,7 +442,9 @@ void tst_QDom::setGetAttributes() nsNode.setAttributeNS("namespace", "intVal", intVal); nsNode.setAttributeNS("namespace", "uintVal", uintVal); nsNode.setAttributeNS("namespace", "floatVal", floatVal); // not available atm - nsNode.setAttributeNS("namespace", "doubleVal", doubleVal); + nsNode.setAttributeNS("namespace", "doubleVal1", doubleVal1); + nsNode.setAttributeNS("namespace", "doubleVal2", doubleVal2); + nsNode.setAttributeNS("namespace", "doubleVal3", doubleVal3); bool bOk; QCOMPARE(rootNode.attribute("qstringVal"), qstringVal); @@ -451,8 +458,10 @@ void tst_QDom::setGetAttributes() QVERIFY(bOk); QCOMPARE(rootNode.attribute("floatVal").toFloat(&bOk), floatVal); QVERIFY(bOk); - QCOMPARE(rootNode.attribute("doubleVal").toDouble(&bOk), doubleVal); - QVERIFY(bOk); + + QVERIFY(rootNode.attribute("doubleVal1").toDouble(&bOk) == doubleVal1 && bOk); + QVERIFY(rootNode.attribute("doubleVal2").toDouble(&bOk) == doubleVal2 && bOk); + QVERIFY(rootNode.attribute("doubleVal3").toDouble(&bOk) == doubleVal3 && bOk); QCOMPARE(nsNode.attributeNS("namespace", "qstringVal"), qstringVal); QCOMPARE(nsNode.attributeNS("namespace", "qlonglongVal").toLongLong(&bOk), qlonglongVal); @@ -465,8 +474,9 @@ void tst_QDom::setGetAttributes() QVERIFY(bOk); QCOMPARE(nsNode.attributeNS("namespace", "floatVal").toFloat(&bOk), floatVal); QVERIFY(bOk); - QCOMPARE(nsNode.attributeNS("namespace", "doubleVal").toDouble(&bOk), doubleVal); - QVERIFY(bOk); + QVERIFY(nsNode.attributeNS("namespace", "doubleVal1").toDouble(&bOk) == doubleVal1 && bOk); + QVERIFY(nsNode.attributeNS("namespace", "doubleVal2").toDouble(&bOk) == doubleVal2 && bOk); + QVERIFY(nsNode.attributeNS("namespace", "doubleVal3").toDouble(&bOk) == doubleVal3 && bOk); QLocale::setDefault(oldLocale); } |