Merge remote-tracking branch 'origin/5.14' into 5.15

Conflicts:
	src/corelib/plugin/qlibrary.cpp
	src/corelib/plugin/qlibrary_unix.cpp
	src/corelib/plugin/qpluginloader.cpp

Change-Id: I866feaaa2a4936ee5389679724c8471a5b4b583d
This commit is contained in:
Qt Forward Merge Bot 2020-03-11 01:00:24 +01:00 committed by Edward Welbourne
commit 116d68f105
29 changed files with 368 additions and 155 deletions

View File

@ -50,8 +50,12 @@
#include "printview.h" #include "printview.h"
#ifndef QT_NO_PRINTER #if defined(QT_PRINTSUPPORT_LIB)
#include <QPrinter> # include <QtPrintSupport/qtprintsupportglobal.h>
# if QT_CONFIG(printer)
# include <QPrinter>
# endif
#endif #endif
PrintView::PrintView() PrintView::PrintView()
@ -62,9 +66,11 @@ PrintView::PrintView()
void PrintView::print(QPrinter *printer) void PrintView::print(QPrinter *printer)
{ {
#ifndef QT_NO_PRINTER #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
resize(printer->width(), printer->height()); resize(printer->width(), printer->height());
render(printer); render(printer);
#else
Q_UNUSED(printer)
#endif #endif
} }

View File

@ -638,7 +638,7 @@ QString encode_pos(int row, int col)
void SpreadSheet::print() void SpreadSheet::print()
{ {
#if QT_CONFIG(printpreviewdialog) #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printpreviewdialog)
QPrinter printer(QPrinter::ScreenResolution); QPrinter printer(QPrinter::ScreenResolution);
QPrintPreviewDialog dlg(&printer); QPrintPreviewDialog dlg(&printer);
PrintView view; PrintView view;

View File

@ -197,7 +197,7 @@ void TextEdit::setupFileActions()
a->setPriority(QAction::LowPriority); a->setPriority(QAction::LowPriority);
menu->addSeparator(); 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")); const QIcon printIcon = QIcon::fromTheme("document-print", QIcon(rsrcPath + "/fileprint.png"));
a = menu->addAction(printIcon, tr("&Print..."), this, &TextEdit::filePrint); a = menu->addAction(printIcon, tr("&Print..."), this, &TextEdit::filePrint);
a->setPriority(QAction::LowPriority); a->setPriority(QAction::LowPriority);
@ -559,7 +559,7 @@ void TextEdit::filePrint()
void TextEdit::filePrintPreview() void TextEdit::filePrintPreview()
{ {
#if QT_CONFIG(printpreviewdialog) #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printpreviewdialog)
QPrinter printer(QPrinter::HighResolution); QPrinter printer(QPrinter::HighResolution);
QPrintPreviewDialog preview(&printer, this); QPrintPreviewDialog preview(&printer, this);
connect(&preview, &QPrintPreviewDialog::paintRequested, this, &TextEdit::printPreview); connect(&preview, &QPrintPreviewDialog::paintRequested, this, &TextEdit::printPreview);
@ -569,17 +569,17 @@ void TextEdit::filePrintPreview()
void TextEdit::printPreview(QPrinter *printer) void TextEdit::printPreview(QPrinter *printer)
{ {
#ifdef QT_NO_PRINTER #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
Q_UNUSED(printer);
#else
textEdit->print(printer); textEdit->print(printer);
#else
Q_UNUSED(printer)
#endif #endif
} }
void TextEdit::filePrintPdf() void TextEdit::filePrintPdf()
{ {
#ifndef QT_NO_PRINTER #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
//! [0] //! [0]
QFileDialog fileDialog(this, tr("Export PDF")); QFileDialog fileDialog(this, tr("Export PDF"));
fileDialog.setAcceptMode(QFileDialog::AcceptSave); fileDialog.setAcceptMode(QFileDialog::AcceptSave);

View File

@ -1,6 +1,8 @@
TEMPLATE = app TEMPLATE = app
TARGET = notepad TARGET = notepad
QT += widgets
qtHaveModule(printsupport): QT += printsupport qtHaveModule(printsupport): QT += printsupport
requires(qtConfig(fontdialog)) requires(qtConfig(fontdialog))

View File

@ -69,10 +69,11 @@
#include <QStatusBar> #include <QStatusBar>
#if defined(QT_PRINTSUPPORT_LIB) #if defined(QT_PRINTSUPPORT_LIB)
#include <QtPrintSupport/qtprintsupportglobal.h> # include <QtPrintSupport/qtprintsupportglobal.h>
#if QT_CONFIG(printdialog)
#include <QPrintDialog> # if QT_CONFIG(printdialog)
#endif # include <QPrintDialog>
# endif
#endif #endif
//! [0] //! [0]

View File

@ -53,8 +53,12 @@
#include <QMainWindow> #include <QMainWindow>
#include <QImage> #include <QImage>
#ifndef QT_NO_PRINTER #if defined(QT_PRINTSUPPORT_LIB)
#include <QPrinter> # include <QtPrintSupport/qtprintsupportglobal.h>
# if QT_CONFIG(printer)
# include <QPrinter>
# endif
#endif #endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -100,7 +104,7 @@ private:
QScrollArea *scrollArea; QScrollArea *scrollArea;
double scaleFactor = 1; double scaleFactor = 1;
#ifndef QT_NO_PRINTER #if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printer)
QPrinter printer; QPrinter printer;
#endif #endif

View File

@ -1949,8 +1949,9 @@ void QSortFilterProxyModelPrivate::_q_sourceColumnsMoved(
example.) example.)
If you are working with large amounts of filtering and have to invoke If you are working with large amounts of filtering and have to invoke
invalidateFilter() repeatedly, using reset() may be more efficient, invalidateFilter() repeatedly, using beginResetModel() / endResetModel() may
depending on the implementation of your model. However, reset() returns the 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 proxy model to its original state, losing selection information, and will
cause the proxy model to be repopulated. cause the proxy model to be repopulated.

View File

@ -615,7 +615,8 @@ QMetaTypeComparatorRegistry;
typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int> typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int>
QMetaTypeDebugStreamRegistry; 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_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE);
Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes) Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes)

View File

@ -389,16 +389,11 @@ QObject *QFactoryLoader::instance(int index) const
QMutexLocker lock(&d->mutex); QMutexLocker lock(&d->mutex);
if (index < d->libraryList.size()) { if (index < d->libraryList.size()) {
QLibraryPrivate *library = d->libraryList.at(index); QLibraryPrivate *library = d->libraryList.at(index);
if (library->instance || library->loadPlugin()) { if (QObject *obj = library->pluginInstance()) {
if (!library->inst)
library->inst = library->instance();
QObject *obj = library->inst.data();
if (obj) {
if (!obj->parent()) if (!obj->parent())
obj->moveToThread(QCoreApplicationPrivate::mainThread()); obj->moveToThread(QCoreApplicationPrivate::mainThread());
return obj; return obj;
} }
}
return nullptr; return nullptr;
} }
index -= d->libraryList.size(); index -= d->libraryList.size();

View File

@ -407,7 +407,7 @@ inline void QLibraryStore::cleanup()
QLibraryPrivate *lib = it.value(); QLibraryPrivate *lib = it.value();
if (lib->libraryRefCount.loadRelaxed() == 1) { if (lib->libraryRefCount.loadRelaxed() == 1) {
if (lib->libraryUnloadCount.loadRelaxed() > 0) { if (lib->libraryUnloadCount.loadRelaxed() > 0) {
Q_ASSERT(lib->pHnd); Q_ASSERT(lib->pHnd.loadRelaxed());
lib->libraryUnloadCount.storeRelaxed(1); lib->libraryUnloadCount.storeRelaxed(1);
#ifdef __GLIBC__ #ifdef __GLIBC__
// glibc has a bug in unloading from global destructors // 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) QLibraryPrivate::QLibraryPrivate(const QString &canonicalFileName, const QString &version, QLibrary::LoadHints loadHints)
: pHnd(nullptr), fileName(canonicalFileName), fullVersion(version), instance(nullptr), : fileName(canonicalFileName), fullVersion(version), pluginState(MightBeAPlugin)
libraryRefCount(0), libraryUnloadCount(0), pluginState(MightBeAPlugin)
{ {
loadHintsInt.storeRelaxed(loadHints); loadHintsInt.storeRelaxed(loadHints);
if (canonicalFileName.isEmpty()) if (canonicalFileName.isEmpty())
@ -519,7 +518,7 @@ QLibraryPrivate::~QLibraryPrivate()
void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh) void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
{ {
// if the library is already loaded, we can't change the load hints // if the library is already loaded, we can't change the load hints
if (pHnd) if (pHnd.loadRelaxed())
return; return;
loadHintsInt.storeRelaxed(lh); loadHintsInt.storeRelaxed(lh);
@ -527,7 +526,7 @@ void QLibraryPrivate::mergeLoadHints(QLibrary::LoadHints lh)
QFunctionPointer QLibraryPrivate::resolve(const char *symbol) QFunctionPointer QLibraryPrivate::resolve(const char *symbol)
{ {
if (!pHnd) if (!pHnd.loadRelaxed())
return nullptr; return nullptr;
return resolve_sys(symbol); return resolve_sys(symbol);
} }
@ -539,9 +538,36 @@ void QLibraryPrivate::setLoadHints(QLibrary::LoadHints lh)
mergeLoadHints(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() bool QLibraryPrivate::load()
{ {
if (pHnd) { if (pHnd.loadRelaxed()) {
libraryUnloadCount.ref(); libraryUnloadCount.ref();
return true; return true;
} }
@ -550,7 +576,9 @@ bool QLibraryPrivate::load()
Q_TRACE(QLibraryPrivate_load_entry, fileName); Q_TRACE(QLibraryPrivate_load_entry, fileName);
mutex.lock();
bool ret = load_sys(); bool ret = load_sys();
mutex.unlock();
if (qt_debug_component()) { if (qt_debug_component()) {
if (ret) { if (ret) {
qDebug() << "loaded library" << fileName; qDebug() << "loaded library" << fileName;
@ -573,9 +601,10 @@ bool QLibraryPrivate::load()
bool QLibraryPrivate::unload(UnloadFlag flag) bool QLibraryPrivate::unload(UnloadFlag flag)
{ {
if (!pHnd) if (!pHnd.loadRelaxed())
return false; return false;
if (libraryUnloadCount.loadRelaxed() > 0 && !libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to if (libraryUnloadCount.loadRelaxed() > 0 && !libraryUnloadCount.deref()) { // only unload if ALL QLibrary instance wanted to
QMutexLocker locker(&mutex);
delete inst.data(); delete inst.data();
if (flag == NoUnloadSys || unload_sys()) { if (flag == NoUnloadSys || unload_sys()) {
if (qt_debug_component()) 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' //when the library is unloaded, we release the reference on it so that 'this'
//can get deleted //can get deleted
libraryRefCount.deref(); libraryRefCount.deref();
pHnd = nullptr; pHnd.storeRelaxed(nullptr);
instance = nullptr; instanceFactory.storeRelaxed(nullptr);
return true;
} }
} }
return (pHnd == nullptr); return false;
} }
void QLibraryPrivate::release() void QLibraryPrivate::release()
@ -597,22 +627,23 @@ void QLibraryPrivate::release()
QLibraryStore::releaseLibrary(this); QLibraryStore::releaseLibrary(this);
} }
bool QLibraryPrivate::loadPlugin() QtPluginInstanceFunction QLibraryPrivate::loadPlugin()
{ {
if (instance) { if (auto ptr = instanceFactory.loadAcquire()) {
libraryUnloadCount.ref(); libraryUnloadCount.ref();
return true; return ptr;
} }
if (pluginState == IsNotAPlugin) if (pluginState == IsNotAPlugin)
return false; return nullptr;
if (load()) { if (load()) {
instance = (QtPluginInstanceFunction)resolve("qt_plugin_instance"); auto ptr = reinterpret_cast<QtPluginInstanceFunction>(resolve("qt_plugin_instance"));
return instance; instanceFactory.storeRelease(ptr); // two threads may store the same value
return ptr;
} }
if (qt_debug_component()) if (qt_debug_component())
qWarning() << "QLibraryPrivate::loadPlugin failed on" << fileName << ":" << errorString; qWarning() << "QLibraryPrivate::loadPlugin failed on" << fileName << ":" << errorString;
pluginState = IsNotAPlugin; pluginState = IsNotAPlugin;
return false; return nullptr;
} }
/*! /*!
@ -719,6 +750,7 @@ bool QLibraryPrivate::isPlugin()
void QLibraryPrivate::updatePluginState() void QLibraryPrivate::updatePluginState()
{ {
QMutexLocker locker(&mutex);
errorString.clear(); errorString.clear();
if (pluginState != MightBeAPlugin) if (pluginState != MightBeAPlugin)
return; return;
@ -739,7 +771,7 @@ void QLibraryPrivate::updatePluginState()
} }
#endif #endif
if (!pHnd) { if (!pHnd.loadRelaxed()) {
// scan for the plugin metadata without loading // scan for the plugin metadata without loading
success = findPatternUnloaded(fileName, this); success = findPatternUnloaded(fileName, this);
} else { } else {
@ -803,7 +835,7 @@ bool QLibrary::load()
if (!d) if (!d)
return false; return false;
if (did_load) if (did_load)
return d->pHnd; return d->pHnd.loadRelaxed();
did_load = true; did_load = true;
return d->load(); return d->load();
} }
@ -839,7 +871,7 @@ bool QLibrary::unload()
*/ */
bool QLibrary::isLoaded() const 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 QString QLibrary::fileName() const
{ {
if (d) if (d) {
QMutexLocker locker(&d->mutex);
return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName; return d->qualifiedFileName.isEmpty() ? d->fileName : d->qualifiedFileName;
}
return QString(); return QString();
} }
@ -1092,7 +1126,12 @@ QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &versi
*/ */
QString QLibrary::errorString() const 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;
} }
/*! /*!

View File

@ -54,10 +54,10 @@
#include <QtCore/private/qglobal_p.h> #include <QtCore/private/qglobal_p.h>
#include "QtCore/qlibrary.h" #include "QtCore/qlibrary.h"
#include "QtCore/qmutex.h"
#include "QtCore/qpointer.h" #include "QtCore/qpointer.h"
#include "QtCore/qstringlist.h" #include "QtCore/qstringlist.h"
#include "QtCore/qplugin.h" #include "QtCore/qplugin.h"
#include "QtCore/qsharedpointer.h"
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
# include "QtCore/qt_windows.h" # include "QtCore/qt_windows.h"
#endif #endif
@ -72,21 +72,18 @@ class QLibraryStore;
class QLibraryPrivate class QLibraryPrivate
{ {
public: public:
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
HINSTANCE using Handle = HINSTANCE;
#else #else
void * using Handle = void *;
#endif #endif
pHnd;
enum UnloadFlag { UnloadSys, NoUnloadSys }; enum UnloadFlag { UnloadSys, NoUnloadSys };
QString fileName, qualifiedFileName; const QString fileName;
QString fullVersion; const QString fullVersion;
bool load(); bool load();
bool loadPlugin(); // loads and resolves instance QtPluginInstanceFunction loadPlugin(); // loads and resolves instance
bool unload(UnloadFlag flag = UnloadSys); bool unload(UnloadFlag flag = UnloadSys);
void release(); void release();
QFunctionPointer resolve(const char *); QFunctionPointer resolve(const char *);
@ -94,17 +91,22 @@ public:
QLibrary::LoadHints loadHints() const QLibrary::LoadHints loadHints() const
{ return QLibrary::LoadHints(loadHintsInt.loadRelaxed()); } { return QLibrary::LoadHints(loadHintsInt.loadRelaxed()); }
void setLoadHints(QLibrary::LoadHints lh); void setLoadHints(QLibrary::LoadHints lh);
QObject *pluginInstance();
static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(), static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString(),
QLibrary::LoadHints loadHints = { }); QLibrary::LoadHints loadHints = { });
static QStringList suffixes_sys(const QString &fullVersion); static QStringList suffixes_sys(const QString &fullVersion);
static QStringList prefixes_sys(); static QStringList prefixes_sys();
QPointer<QObject> inst; QAtomicPointer<std::remove_pointer<QtPluginInstanceFunction>::type> instanceFactory;
QtPluginInstanceFunction instance; QAtomicPointer<std::remove_pointer<Handle>::type> pHnd;
QJsonObject metaData;
// the mutex protects the fields below
QMutex mutex;
QPointer<QObject> inst; // used by QFactoryLoader
QJsonObject metaData;
QString errorString; QString errorString;
QString qualifiedFileName;
void updatePluginState(); void updatePluginState();
bool isPlugin(); bool isPlugin();

View File

@ -214,8 +214,9 @@ bool QLibraryPrivate::load_sys()
#endif #endif
bool retry = true; bool retry = true;
for(int prefix = 0; retry && !pHnd && prefix < prefixes.size(); prefix++) { Handle hnd = nullptr;
for(int suffix = 0; retry && !pHnd && suffix < suffixes.size(); suffix++) { 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))) if (!prefixes.at(prefix).isEmpty() && name.startsWith(prefixes.at(prefix)))
continue; continue;
if (path.isEmpty() && prefixes.at(prefix).contains(QLatin1Char('/'))) 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); 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 #ifdef Q_OS_ANDROID
if (!pHnd) { if (!pHnd) {
auto attemptFromBundle = attempt; auto attemptFromBundle = attempt;
@ -248,7 +249,7 @@ bool QLibraryPrivate::load_sys()
} }
#endif #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. // 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 // 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...) // 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 #ifdef Q_OS_MAC
if (!pHnd) { if (!hnd) {
QByteArray utf8Bundle = fileName.toUtf8(); QByteArray utf8Bundle = fileName.toUtf8();
QCFType<CFURLRef> bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast<const UInt8*>(utf8Bundle.data()), utf8Bundle.length(), true); QCFType<CFURLRef> bundleUrl = CFURLCreateFromFileSystemRepresentation(NULL, reinterpret_cast<const UInt8*>(utf8Bundle.data()), utf8Bundle.length(), true);
QCFType<CFBundleRef> bundle = CFBundleCreate(NULL, bundleUrl); QCFType<CFBundleRef> bundle = CFBundleCreate(NULL, bundleUrl);
@ -268,23 +269,24 @@ bool QLibraryPrivate::load_sys()
char executableFile[FILENAME_MAX]; char executableFile[FILENAME_MAX];
CFURLGetFileSystemRepresentation(url, true, reinterpret_cast<UInt8*>(executableFile), FILENAME_MAX); CFURLGetFileSystemRepresentation(url, true, reinterpret_cast<UInt8*>(executableFile), FILENAME_MAX);
attempt = QString::fromUtf8(executableFile); attempt = QString::fromUtf8(executableFile);
pHnd = dlopen(QFile::encodeName(attempt), dlFlags); hnd = dlopen(QFile::encodeName(attempt), dlFlags);
} }
} }
#endif #endif
if (!pHnd) { if (!hnd) {
errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror()); errorString = QLibrary::tr("Cannot load library %1: %2").arg(fileName, qdlerror());
} }
if (pHnd) { if (hnd) {
qualifiedFileName = attempt; qualifiedFileName = attempt;
errorString.clear(); errorString.clear();
} }
return (pHnd != nullptr); pHnd.storeRelaxed(hnd);
return (hnd != nullptr);
} }
bool QLibraryPrivate::unload_sys() bool QLibraryPrivate::unload_sys()
{ {
if (dlclose(pHnd)) { if (dlclose(pHnd.loadAcquire())) {
#if defined (Q_OS_QNX) // Workaround until fixed in QNX; fixes crash in #if defined (Q_OS_QNX) // Workaround until fixed in QNX; fixes crash in
char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance char *error = dlerror(); // QtDeclarative auto test "qqmlenginecleanup" for instance
if (!qstrcmp(error, "Shared objects still referenced")) // On QNX that's only "informative" 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 QLibraryPrivate::resolve_sys(const char* symbol)
{ {
QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol)); QFunctionPointer address = QFunctionPointer(dlsym(pHnd.loadAcquire(), symbol));
if (!address) {
errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg(
QString::fromLatin1(symbol), fileName, qdlerror());
} else {
errorString.clear();
}
return address; return address;
} }

View File

@ -95,26 +95,27 @@ bool QLibraryPrivate::load_sys()
attempts.prepend(QDir::rootPath() + fileName); attempts.prepend(QDir::rootPath() + fileName);
#endif #endif
Handle hnd = nullptr;
for (const QString &attempt : qAsConst(attempts)) { for (const QString &attempt : qAsConst(attempts)) {
#ifndef Q_OS_WINRT #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 #else // Q_OS_WINRT
QString path = QDir::toNativeSeparators(QDir::current().relativeFilePath(attempt)); QString path = QDir::toNativeSeparators(QDir::current().relativeFilePath(attempt));
pHnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0); hnd = LoadPackagedLibrary(reinterpret_cast<LPCWSTR>(path.utf16()), 0);
if (pHnd) if (hnd)
qualifiedFileName = attempt; qualifiedFileName = attempt;
#endif // !Q_OS_WINRT #endif // !Q_OS_WINRT
// If we have a handle or the last error is something other than "unable // If we have a handle or the last error is something other than "unable
// to find the module", then bail out // to find the module", then bail out
if (pHnd || ::GetLastError() != ERROR_MOD_NOT_FOUND) if (hnd || ::GetLastError() != ERROR_MOD_NOT_FOUND)
break; break;
} }
#ifndef Q_OS_WINRT #ifndef Q_OS_WINRT
SetErrorMode(oldmode); SetErrorMode(oldmode);
#endif #endif
if (!pHnd) { if (!hnd) {
errorString = QLibrary::tr("Cannot load library %1: %2").arg( errorString = QLibrary::tr("Cannot load library %1: %2").arg(
QDir::toNativeSeparators(fileName), qt_error_string()); QDir::toNativeSeparators(fileName), qt_error_string());
} else { } else {
@ -123,7 +124,7 @@ bool QLibraryPrivate::load_sys()
#ifndef Q_OS_WINRT #ifndef Q_OS_WINRT
wchar_t buffer[MAX_PATH]; wchar_t buffer[MAX_PATH];
::GetModuleFileName(pHnd, buffer, MAX_PATH); ::GetModuleFileName(hnd, buffer, MAX_PATH);
QString moduleFileName = QString::fromWCharArray(buffer); QString moduleFileName = QString::fromWCharArray(buffer);
moduleFileName.remove(0, 1 + moduleFileName.lastIndexOf(QLatin1Char('\\'))); moduleFileName.remove(0, 1 + moduleFileName.lastIndexOf(QLatin1Char('\\')));
@ -138,19 +139,20 @@ bool QLibraryPrivate::load_sys()
HMODULE hmod; HMODULE hmod;
bool ok = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN | bool ok = GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN |
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
reinterpret_cast<const wchar_t *>(pHnd), reinterpret_cast<const wchar_t *>(hnd),
&hmod); &hmod);
Q_ASSERT(!ok || hmod == pHnd); Q_ASSERT(!ok || hmod == hnd);
Q_UNUSED(ok); Q_UNUSED(ok);
} }
#endif // !Q_OS_WINRT #endif // !Q_OS_WINRT
} }
return (pHnd != 0); pHnd.storeRelaxed(hnd);
return (pHnd != nullptr);
} }
bool QLibraryPrivate::unload_sys() bool QLibraryPrivate::unload_sys()
{ {
if (!FreeLibrary(pHnd)) { if (!FreeLibrary(pHnd.loadAcquire())) {
errorString = QLibrary::tr("Cannot unload library %1: %2").arg( errorString = QLibrary::tr("Cannot unload library %1: %2").arg(
QDir::toNativeSeparators(fileName), qt_error_string()); QDir::toNativeSeparators(fileName), qt_error_string());
return false; return false;
@ -161,13 +163,7 @@ bool QLibraryPrivate::unload_sys()
QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol)
{ {
FARPROC address = GetProcAddress(pHnd, symbol); FARPROC address = GetProcAddress(pHnd.loadAcquire(), 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();
}
return QFunctionPointer(address); return QFunctionPointer(address);
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -196,9 +196,7 @@ QObject *QPluginLoader::instance()
{ {
if (!isLoaded() && !load()) if (!isLoaded() && !load())
return nullptr; return nullptr;
if (!d->inst && d->instance) return d->pluginInstance();
d->inst = d->instance();
return d->inst.data();
} }
/*! /*!
@ -233,7 +231,7 @@ bool QPluginLoader::load()
if (!d || d->fileName.isEmpty()) if (!d || d->fileName.isEmpty())
return false; return false;
if (did_load) if (did_load)
return d->pHnd && d->instance; return d->pHnd && d->instanceFactory.loadAcquire();
if (!d->isPlugin()) if (!d->isPlugin())
return false; return false;
did_load = true; did_load = true;
@ -275,7 +273,7 @@ bool QPluginLoader::unload()
*/ */
bool QPluginLoader::isLoaded() const bool QPluginLoader::isLoaded() const
{ {
return d && d->pHnd && d->instance; return d && d->pHnd && d->instanceFactory.loadRelaxed();
} }
#if defined(QT_SHARED) #if defined(QT_SHARED)

View File

@ -115,7 +115,8 @@ struct ByteData
QStringView asStringView() const{ return QStringView(utf16(), len / 2); } QStringView asStringView() const{ return QStringView(utf16(), len / 2); }
QString asQStringRaw() const { return QString::fromRawData(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 } // namespace QtCbor
Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE); Q_DECLARE_TYPEINFO(QtCbor::Element, Q_PRIMITIVE_TYPE);

View File

@ -1667,7 +1667,8 @@ namespace {
QFontEngine *previousGlyphFontEngine; QFontEngine *previousGlyphFontEngine;
QFixed minw; QFixed minw;
QFixed softHyphenWidth; QFixed currentSoftHyphenWidth;
QFixed commitedSoftHyphenWidth;
QFixed rightBearing; QFixed rightBearing;
QFixed minimumRightBearing; QFixed minimumRightBearing;
@ -1681,7 +1682,7 @@ namespace {
QFixed calculateNewWidth(const QScriptLine &line) const { QFixed calculateNewWidth(const QScriptLine &line) const {
return line.textWidth + tmpData.textWidth + spaceData.textWidth return line.textWidth + tmpData.textWidth + spaceData.textWidth
+ softHyphenWidth + negativeRightBearing(); + (line.textWidth > 0 ? currentSoftHyphenWidth : QFixed()) + negativeRightBearing();
} }
inline glyph_t currentGlyph() const inline glyph_t currentGlyph() const
@ -1755,6 +1756,7 @@ inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs)) if (line.length && !manualWrap && (newWidth > line.width || glyphCount > maxGlyphs))
return true; return true;
const QFixed oldTextWidth = line.textWidth;
minw = qMax(minw, tmpData.textWidth); minw = qMax(minw, tmpData.textWidth);
line += tmpData; line += tmpData;
line.textWidth += spaceData.textWidth; line.textWidth += spaceData.textWidth;
@ -1765,6 +1767,11 @@ inline bool LineBreakHelper::checkFullOtherwiseExtend(QScriptLine &line)
spaceData.textWidth = 0; spaceData.textWidth = 0;
spaceData.length = 0; spaceData.length = 0;
if (oldTextWidth != line.textWidth || currentSoftHyphenWidth > 0) {
commitedSoftHyphenWidth = currentSoftHyphenWidth;
currentSoftHyphenWidth = 0;
}
return false; return false;
} }
@ -1837,7 +1844,6 @@ void QTextLine::layout_helper(int maxGlyphs)
while (newItem < eng->layoutData->items.size()) { while (newItem < eng->layoutData->items.size()) {
lbh.resetRightBearing(); lbh.resetRightBearing();
lbh.softHyphenWidth = 0;
if (newItem != item) { if (newItem != item) {
item = newItem; item = newItem;
const QScriptItem &current = eng->layoutData->items.at(item); const QScriptItem &current = eng->layoutData->items.at(item);
@ -1975,9 +1981,9 @@ void QTextLine::layout_helper(int maxGlyphs)
} while (lbh.currentPosition < end); } while (lbh.currentPosition < end);
lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw); lbh.minw = qMax(lbh.tmpData.textWidth, lbh.minw);
if (lbh.currentPosition > 0 && lbh.currentPosition < end if (lbh.currentPosition > 0 && lbh.currentPosition <= end
&& attributes[lbh.currentPosition].lineBreak && (lbh.currentPosition == end || attributes[lbh.currentPosition].lineBreak)
&& eng->layoutData->string.at(lbh.currentPosition - 1).unicode() == QChar::SoftHyphen) { && eng->layoutData->string.at(lbh.currentPosition - 1) == QChar::SoftHyphen) {
// if we are splitting up a word because of // if we are splitting up a word because of
// a soft hyphen then we ... // 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 // want the soft-hyphen to slip into the next line
// and thus become invisible again. // and thus become invisible again.
// //
if (line.length) lbh.currentSoftHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]];
lbh.softHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]];
else if (breakany)
lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]];
} }
if (sb_or_ws|breakany) { if (sb_or_ws|breakany) {
@ -2023,6 +2026,7 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.calculateRightBearing(); lbh.calculateRightBearing();
if (lbh.checkFullOtherwiseExtend(line)) { if (lbh.checkFullOtherwiseExtend(line)) {
// We are too wide to accept the next glyph with its bearing, so we restore the // 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), // 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. // 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 else
lbh.calculateRightBearingForPreviousGlyph(); lbh.calculateRightBearingForPreviousGlyph();
if (!breakany) { line.textWidth += lbh.commitedSoftHyphenWidth;
line.textWidth += lbh.softHyphenWidth;
}
goto found; goto found;
} }
@ -2045,6 +2047,7 @@ void QTextLine::layout_helper(int maxGlyphs)
} }
LB_DEBUG("reached end of line"); LB_DEBUG("reached end of line");
lbh.checkFullOtherwiseExtend(line); lbh.checkFullOtherwiseExtend(line);
line.textWidth += lbh.commitedSoftHyphenWidth;
found: found:
line.textAdvance = line.textWidth; line.textAdvance = line.textWidth;

View File

@ -56,6 +56,7 @@
#include <QtGui/qpalette.h> #include <QtGui/qpalette.h>
#include <QtGui/qtextdocument.h> #include <QtGui/qtextdocument.h>
#include <QtGui/qtextlist.h> #include <QtGui/qtextlist.h>
#include <QtCore/qpointer.h>
#include <QtCore/qstack.h> #include <QtCore/qstack.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE

View File

@ -46,7 +46,11 @@
#include <QSocketNotifier> #include <QSocketNotifier>
#include <QLoggingCategory> #include <QLoggingCategory>
#ifdef Q_OS_FREEBSD
#include <dev/evdev/input.h>
#else
#include <linux/input.h> #include <linux/input.h>
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE

View File

@ -122,6 +122,7 @@ static const char *xcb_atomnames = {
"_NET_WM_STATE_MODAL\0" "_NET_WM_STATE_MODAL\0"
"_NET_WM_STATE_STAYS_ON_TOP\0" "_NET_WM_STATE_STAYS_ON_TOP\0"
"_NET_WM_STATE_DEMANDS_ATTENTION\0" "_NET_WM_STATE_DEMANDS_ATTENTION\0"
"_NET_WM_STATE_HIDDEN\0"
"_NET_WM_USER_TIME\0" "_NET_WM_USER_TIME\0"
"_NET_WM_USER_TIME_WINDOW\0" "_NET_WM_USER_TIME_WINDOW\0"

View File

@ -123,6 +123,7 @@ public:
_NET_WM_STATE_MODAL, _NET_WM_STATE_MODAL,
_NET_WM_STATE_STAYS_ON_TOP, _NET_WM_STATE_STAYS_ON_TOP,
_NET_WM_STATE_DEMANDS_ATTENTION, _NET_WM_STATE_DEMANDS_ATTENTION,
_NET_WM_STATE_HIDDEN,
_NET_WM_USER_TIME, _NET_WM_USER_TIME,
_NET_WM_USER_TIME_WINDOW, _NET_WM_USER_TIME_WINDOW,

View File

@ -903,6 +903,8 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates()
result |= NetWmStateStaysOnTop; result |= NetWmStateStaysOnTop;
if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION))) if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)))
result |= NetWmStateDemandsAttention; result |= NetWmStateDemandsAttention;
if (statesEnd != std::find(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_HIDDEN)))
result |= NetWmStateHidden;
} else { } else {
qCDebug(lcQpaXcb, "getting net wm state (%x), empty\n", m_window); qCDebug(lcQpaXcb, "getting net wm state (%x), empty\n", m_window);
} }
@ -1074,6 +1076,9 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow()
states |= NetWmStateBelow; states |= NetWmStateBelow;
} }
if (window()->windowStates() & Qt::WindowMinimized)
states |= NetWmStateHidden;
if (window()->windowStates() & Qt::WindowFullScreen) if (window()->windowStates() & Qt::WindowFullScreen)
states |= NetWmStateFullScreen; states |= NetWmStateFullScreen;
@ -1107,6 +1112,8 @@ void QXcbWindow::setNetWmStateOnUnmappedWindow()
atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE)); atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW))) if (states & NetWmStateBelow && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_BELOW)))
atoms.push_back(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))) if (states & NetWmStateFullScreen && !atoms.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)))
atoms.push_back(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))) 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)); || (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
} }
} }
if (m_minimized)
newState = Qt::WindowMinimized;
const NetWmStates states = netWmStates(); 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) if (states & NetWmStateFullScreen)
newState |= Qt::WindowFullScreen; newState |= Qt::WindowFullScreen;
if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert)) if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))

View File

@ -68,7 +68,8 @@ public:
NetWmStateMaximizedVert = 0x10, NetWmStateMaximizedVert = 0x10,
NetWmStateModal = 0x20, NetWmStateModal = 0x20,
NetWmStateStaysOnTop = 0x40, NetWmStateStaysOnTop = 0x40,
NetWmStateDemandsAttention = 0x80 NetWmStateDemandsAttention = 0x80,
NetWmStateHidden = 0x100
}; };
Q_DECLARE_FLAGS(NetWmStates, NetWmState) Q_DECLARE_FLAGS(NetWmStates, NetWmState)

View File

@ -546,12 +546,19 @@ void WriteInitialization::acceptUI(DomUI *node)
m_output << m_option.indent << language::endFunctionDefinition("setupUi"); m_output << m_option.indent << language::endFunctionDefinition("setupUi");
if (!m_mainFormUsedInRetranslateUi && language::language() == Language::Cpp) { if (!m_mainFormUsedInRetranslateUi) {
if (language::language() == Language::Cpp) {
// Mark varName as unused to avoid compiler warnings. // Mark varName as unused to avoid compiler warnings.
m_refreshInitialization += m_indent; m_refreshInitialization += m_indent;
m_refreshInitialization += QLatin1String("(void)"); m_refreshInitialization += QLatin1String("(void)");
m_refreshInitialization += varName ; m_refreshInitialization += varName ;
m_refreshInitialization += language::eol; 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 m_output << m_option.indent

View File

@ -65,6 +65,7 @@
#include <stdio.h> #include <stdio.h>
#include <limits>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -4364,7 +4365,7 @@ void QDomElement::setAttribute(const QString& name, float value)
if (!impl) if (!impl)
return; return;
QString x; QString x;
x.setNum(value); x.setNum(value, 'g', 8);
IMPL->setAttribute(name, x); IMPL->setAttribute(name, x);
} }
@ -4378,7 +4379,7 @@ void QDomElement::setAttribute(const QString& name, double value)
if (!impl) if (!impl)
return; return;
QString x; QString x;
x.setNum(value); x.setNum(value, 'g', 17);
IMPL->setAttribute(name, x); IMPL->setAttribute(name, x);
} }
@ -4547,7 +4548,7 @@ void QDomElement::setAttributeNS(const QString nsURI, const QString& qName, doub
if (!impl) if (!impl)
return; return;
QString x; QString x;
x.setNum(value); x.setNum(value, 'g', 17);
IMPL->setAttributeNS(nsURI, qName, x); IMPL->setAttributeNS(nsURI, qName, x);
} }

View File

@ -1,3 +0,0 @@
[elapsed]
macos
windows-10

View File

@ -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("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("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"); QTest::newRow("good resolve") << (int)Resolve << appDir + "/mylib" << true << QString("Unknown error");
#ifdef Q_OS_WIN #ifdef Q_OS_WIN

View File

@ -62,6 +62,7 @@ private slots:
void lineBreaking(); void lineBreaking();
#ifdef QT_BUILD_INTERNAL #ifdef QT_BUILD_INTERNAL
void simpleBoundingRect(); void simpleBoundingRect();
void threeLineBoundingRect_data();
void threeLineBoundingRect(); void threeLineBoundingRect();
void boundingRectWithLongLineAndNoWrap(); void boundingRectWithLongLineAndNoWrap();
void forcedBreaks(); void forcedBreaks();
@ -140,6 +141,7 @@ private slots:
void showLineAndParagraphSeparatorsCrash(); void showLineAndParagraphSeparatorsCrash();
void koreanWordWrap(); void koreanWordWrap();
void tooManyDirectionalCharctersCrash_qtbug77819(); void tooManyDirectionalCharctersCrash_qtbug77819();
void softHyphens();
private: private:
QFont testFont; QFont testFont;
@ -315,18 +317,49 @@ void tst_QTextLayout::simpleBoundingRect()
QCOMPARE(layout.boundingRect(), QRectF(0, 0, width, QFontMetrics(testFont).height())); 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() void tst_QTextLayout::threeLineBoundingRect()
{ {
/* stricter check. break text into three lines */ /* stricter check. break text into three lines */
QFETCH(QChar, wordBoundary1);
QFETCH(QChar, wordBoundary2);
QString firstWord("hello"); QString firstWord("hello");
QString secondWord("world"); QString secondWord("test");
QString thirdWord("test"); QString thirdWord("world");
QString text(firstWord + ' ' + secondWord + ' ' + thirdWord); QString text(firstWord + wordBoundary1 + secondWord + wordBoundary2 + thirdWord);
const int firstLineWidth = firstWord.length() * testFont.pixelSize(); int firstLineWidth = firstWord.length() * testFont.pixelSize();
const int secondLineWidth = secondWord.length() * testFont.pixelSize(); int secondLineWidth = secondWord.length() * testFont.pixelSize();
const int thirdLineWidth = thirdWord.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)); const int longestLine = qMax(firstLineWidth, qMax(secondLineWidth, thirdLineWidth));
@ -339,8 +372,7 @@ void tst_QTextLayout::threeLineBoundingRect()
line.setLineWidth(firstLineWidth); line.setLineWidth(firstLineWidth);
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
// + 1 for trailing space QCOMPARE(line.textLength(), firstLineLength);
QCOMPARE(line.textLength(), firstWord.length() + 1);
QCOMPARE(qRound(line.naturalTextWidth()), firstLineWidth); QCOMPARE(qRound(line.naturalTextWidth()), firstLineWidth);
pos += line.textLength(); pos += line.textLength();
@ -349,9 +381,8 @@ void tst_QTextLayout::threeLineBoundingRect()
line = layout.createLine(); line = layout.createLine();
line.setLineWidth(secondLineWidth); line.setLineWidth(secondLineWidth);
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
// + 1 for trailing space
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), secondWord.length() + 1); QCOMPARE(line.textLength(), secondLineLength);
QCOMPARE(qRound(line.naturalTextWidth()), secondLineWidth); QCOMPARE(qRound(line.naturalTextWidth()), secondLineWidth);
pos += line.textLength(); pos += line.textLength();
@ -360,9 +391,8 @@ void tst_QTextLayout::threeLineBoundingRect()
line = layout.createLine(); line = layout.createLine();
line.setLineWidth(secondLineWidth); line.setLineWidth(secondLineWidth);
line.setPosition(QPoint(0, y)); line.setPosition(QPoint(0, y));
// no trailing space here!
QCOMPARE(line.textStart(), pos); QCOMPARE(line.textStart(), pos);
QCOMPARE(line.textLength(), thirdWord.length()); QCOMPARE(line.textLength(), thirdLineLength);
QCOMPARE(qRound(line.naturalTextWidth()), thirdLineWidth); QCOMPARE(qRound(line.naturalTextWidth()), thirdLineWidth);
y += qRound(line.ascent() + line.descent()); y += qRound(line.ascent() + line.descent());
@ -2352,5 +2382,111 @@ void tst_QTextLayout::tooManyDirectionalCharctersCrash_qtbug77819()
tl.endLayout(); 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) QTEST_MAIN(tst_QTextLayout)
#include "tst_qtextlayout.moc" #include "tst_qtextlayout.moc"

View File

@ -2,7 +2,3 @@
# QTBUG-66345 # QTBUG-66345
opensuse-42.3 opensuse-42.3
ubuntu-16.04 ubuntu-16.04
[setWindowState]
ubuntu-18.04
rhel-7.6

View File

@ -38,6 +38,7 @@
#include <QtTest/QtTest> #include <QtTest/QtTest>
#include <QtXml> #include <QtXml>
#include <QVariant> #include <QVariant>
#include <cmath>
QT_FORWARD_DECLARE_CLASS(QDomDocument) QT_FORWARD_DECLARE_CLASS(QDomDocument)
QT_FORWARD_DECLARE_CLASS(QDomNode) QT_FORWARD_DECLARE_CLASS(QDomNode)
@ -419,7 +420,9 @@ void tst_QDom::setGetAttributes()
const int intVal = std::numeric_limits<int>::min(); const int intVal = std::numeric_limits<int>::min();
const uint uintVal = std::numeric_limits<uint>::max(); const uint uintVal = std::numeric_limits<uint>::max();
const float floatVal = 0.1234f; 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("qstringVal", qstringVal);
rootNode.setAttribute("qlonglongVal", qlonglongVal); rootNode.setAttribute("qlonglongVal", qlonglongVal);
@ -427,7 +430,9 @@ void tst_QDom::setGetAttributes()
rootNode.setAttribute("intVal", intVal); rootNode.setAttribute("intVal", intVal);
rootNode.setAttribute("uintVal", uintVal); rootNode.setAttribute("uintVal", uintVal);
rootNode.setAttribute("floatVal", floatVal); 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"); QDomElement nsNode = doc.createElement("NS");
rootNode.appendChild(nsNode); rootNode.appendChild(nsNode);
@ -437,7 +442,9 @@ void tst_QDom::setGetAttributes()
nsNode.setAttributeNS("namespace", "intVal", intVal); nsNode.setAttributeNS("namespace", "intVal", intVal);
nsNode.setAttributeNS("namespace", "uintVal", uintVal); nsNode.setAttributeNS("namespace", "uintVal", uintVal);
nsNode.setAttributeNS("namespace", "floatVal", floatVal); // not available atm 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; bool bOk;
QCOMPARE(rootNode.attribute("qstringVal"), qstringVal); QCOMPARE(rootNode.attribute("qstringVal"), qstringVal);
@ -451,8 +458,10 @@ void tst_QDom::setGetAttributes()
QVERIFY(bOk); QVERIFY(bOk);
QCOMPARE(rootNode.attribute("floatVal").toFloat(&bOk), floatVal); QCOMPARE(rootNode.attribute("floatVal").toFloat(&bOk), floatVal);
QVERIFY(bOk); 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", "qstringVal"), qstringVal);
QCOMPARE(nsNode.attributeNS("namespace", "qlonglongVal").toLongLong(&bOk), qlonglongVal); QCOMPARE(nsNode.attributeNS("namespace", "qlonglongVal").toLongLong(&bOk), qlonglongVal);
@ -465,8 +474,9 @@ void tst_QDom::setGetAttributes()
QVERIFY(bOk); QVERIFY(bOk);
QCOMPARE(nsNode.attributeNS("namespace", "floatVal").toFloat(&bOk), floatVal); QCOMPARE(nsNode.attributeNS("namespace", "floatVal").toFloat(&bOk), floatVal);
QVERIFY(bOk); QVERIFY(bOk);
QCOMPARE(nsNode.attributeNS("namespace", "doubleVal").toDouble(&bOk), doubleVal); QVERIFY(nsNode.attributeNS("namespace", "doubleVal1").toDouble(&bOk) == doubleVal1 && bOk);
QVERIFY(bOk); QVERIFY(nsNode.attributeNS("namespace", "doubleVal2").toDouble(&bOk) == doubleVal2 && bOk);
QVERIFY(nsNode.attributeNS("namespace", "doubleVal3").toDouble(&bOk) == doubleVal3 && bOk);
QLocale::setDefault(oldLocale); QLocale::setDefault(oldLocale);
} }