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"
#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
}

View File

@ -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;

View File

@ -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);

View File

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

View File

@ -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]

View File

@ -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

View File

@ -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.

View File

@ -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)

View File

@ -389,16 +389,11 @@ 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 (QObject *obj = library->pluginInstance()) {
if (!obj->parent())
obj->moveToThread(QCoreApplicationPrivate::mainThread());
return obj;
}
}
return nullptr;
}
index -= d->libraryList.size();

View File

@ -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;
}
/*!

View File

@ -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();

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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 &current = 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;

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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,

View File

@ -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))

View File

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

View File

@ -546,12 +546,19 @@ void WriteInitialization::acceptUI(DomUI *node)
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.
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

View File

@ -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);
}

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("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

View File

@ -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);
QString secondWord("test");
QString thirdWord("world");
QString text(firstWord + wordBoundary1 + secondWord + wordBoundary2 + thirdWord);
const int firstLineWidth = firstWord.length() * testFont.pixelSize();
const int secondLineWidth = secondWord.length() * testFont.pixelSize();
const int thirdLineWidth = thirdWord.length() * testFont.pixelSize();
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"

View File

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

View File

@ -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);
}