diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-03-23 01:00:08 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-03-25 10:13:23 +0100 |
commit | a1e38651ce245edcd8628bc8e2aad7e83184066e (patch) | |
tree | 27d3a68ac4204975faa6d0d427970fb1013e0ed4 | |
parent | 3980ccf785462dc7b2cb53f72790638eb9e7b8c0 (diff) | |
parent | 42ed40cf0abd0155d6e6d1ef01faf9bded065588 (diff) |
Merge remote-tracking branch 'origin/5.12' into 5.13
Conflicts:
.qmake.conf
src/qmltest/quicktest.cpp
tests/auto/qml/qmlcachegen/qmlcachegen.pro
Change-Id: I70e96e8817d59647f876b8b77b30cdeede8f0662
42 files changed, 523 insertions, 243 deletions
diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp index 5bd96af582..5d2684b510 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.cpp @@ -106,16 +106,9 @@ static void closeAllWindows() bool QQmlPreviewHandler::eventFilter(QObject *obj, QEvent *event) { - if (event->type() == QEvent::Show) { - if (QWindow *window = qobject_cast<QQuickWindow*>(obj)) { - m_lastPosition.initLastSavedWindowPosition(window); - } - } - if (m_currentWindow && (event->type() == QEvent::Move || event->type() == QEvent::Resize) && + if (m_currentWindow && (event->type() == QEvent::Move) && qobject_cast<QQuickWindow*>(obj) == m_currentWindow) { - // we always start with factor 1 so calculate and save the origin as it would be not scaled - m_lastPosition.setPosition(m_currentWindow->framePosition() * - QHighDpiScaling::factor(m_currentWindow)); + m_lastPosition.takePosition(m_currentWindow); } return QObject::eventFilter(obj, event); @@ -196,49 +189,38 @@ void QQmlPreviewHandler::rerun() void QQmlPreviewHandler::zoom(qreal newFactor) { + m_zoomFactor = newFactor; + QTimer::singleShot(0, this, &QQmlPreviewHandler::doZoom); +} + +void QQmlPreviewHandler::doZoom() +{ if (!m_currentWindow) return; - if (qFuzzyIsNull(newFactor)) { + if (qFuzzyIsNull(m_zoomFactor)) { emit error(QString::fromLatin1("Zooming with factor: %1 will result in nothing " \ - "so it will be ignored.").arg(newFactor)); + "so it will be ignored.").arg(m_zoomFactor)); return; } - QString errorMessage; - bool resetZoom = false; - if (newFactor < 0) { + bool resetZoom = false; + if (m_zoomFactor < 0) { resetZoom = true; - newFactor = 1.0; + m_zoomFactor = 1.0; } - // On single-window devices we allow any scale factor as the window will adapt to the screen. - if (m_supportsMultipleWindows) { - const QSize newAvailableScreenSize = QQmlPreviewPosition::currentScreenSize(m_currentWindow) - * QHighDpiScaling::factor(m_currentWindow) / newFactor; - if (m_currentWindow->size().width() > newAvailableScreenSize.width()) { - errorMessage = QString::fromLatin1( - "Zooming with factor: " - "%1 will result in a too wide preview.").arg(newFactor); - } - if (m_currentWindow->size().height() > newAvailableScreenSize.height()) { - errorMessage = QString::fromLatin1( - "Zooming with factor: " - "%1 will result in a too heigh preview.").arg(newFactor); - } - } + m_currentWindow->setGeometry(m_currentWindow->geometry()); - if (errorMessage.isEmpty()) { - const QPoint newToOriginMappedPosition = m_currentWindow->position() * - QHighDpiScaling::factor(m_currentWindow) / newFactor; - m_currentWindow->destroy(); - QHighDpiScaling::setScreenFactor(m_currentWindow->screen(), newFactor); - if (resetZoom) - QHighDpiScaling::updateHighDpiScaling(); - m_currentWindow->setPosition(newToOriginMappedPosition); - m_currentWindow->show(); - } else { - emit error(errorMessage); - } + m_lastPosition.takePosition(m_currentWindow, QQmlPreviewPosition::InitializePosition); + m_currentWindow->destroy(); + + for (QScreen *screen : QGuiApplication::screens()) + QHighDpiScaling::setScreenFactor(screen, m_zoomFactor); + if (resetZoom) + QHighDpiScaling::updateHighDpiScaling(); + + m_currentWindow->show(); + m_lastPosition.initLastSavedWindowPosition(m_currentWindow); } void QQmlPreviewHandler::removeTranslators() diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h index 21ea672580..47491b9d8f 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewhandler.h @@ -104,6 +104,7 @@ signals: protected: bool eventFilter(QObject *obj, QEvent *event); private: + void doZoom(); void tryCreateObject(); void showObject(QObject *object); void setCurrentWindow(QQuickWindow *window); @@ -121,6 +122,7 @@ private: QVector<QPointer<QObject>> m_createdObjects; QScopedPointer<QQmlComponent> m_component; QPointer<QQuickWindow> m_currentWindow; + qreal m_zoomFactor = 1.0; bool m_supportsMultipleWindows; QQmlPreviewPosition m_lastPosition; diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp index 3edcbac0a9..d4acd24da5 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.cpp @@ -42,14 +42,47 @@ #include <QtGui/qwindow.h> #include <QtGui/qscreen.h> #include <QtGui/qguiapplication.h> +#include <private/qhighdpiscaling_p.h> QT_BEGIN_NAMESPACE -static const QSize availableScreenSize(const QPoint &point) +static QVector<QQmlPreviewPosition::ScreenData> initScreensData() { - if (const QScreen *screen = QGuiApplication::screenAt(point)) - return screen->availableGeometry().size(); - return QSize(); + QVector<QQmlPreviewPosition::ScreenData> screensData; + + for (QScreen *screen : QGuiApplication::screens()) { + QQmlPreviewPosition::ScreenData sd{screen->name(), screen->size()}; + screensData.append(sd); + } + return screensData; +} + +static QScreen *findScreen(const QString &nameOfScreen) +{ + for (QScreen *screen : QGuiApplication::screens()) { + if (screen->name() == nameOfScreen) + return screen; + } + return nullptr; +} + +static QDataStream &operator<<(QDataStream &out, const QQmlPreviewPosition::ScreenData &screenData) +{ + out << screenData.name; + out << screenData.size; + return out; +} + +static QDataStream &operator>>(QDataStream &in, QQmlPreviewPosition::ScreenData &screenData) +{ + in >> screenData.name; + in >> screenData.size; + return in; +} + +bool QQmlPreviewPosition::ScreenData::operator==(const QQmlPreviewPosition::ScreenData &other) const +{ + return other.size == size && other.name == name; } QQmlPreviewPosition::QQmlPreviewPosition() @@ -62,20 +95,36 @@ QQmlPreviewPosition::QQmlPreviewPosition() }); } -void QQmlPreviewPosition::setPosition(const QPoint &point) +QQmlPreviewPosition::~QQmlPreviewPosition() +{ + saveWindowPosition(); +} + +void QQmlPreviewPosition::takePosition(QWindow *window, InitializeState state) { - m_hasPosition = true; - m_lastWindowPosition = point; - m_savePositionTimer.start(); + Q_ASSERT(window); + // only save the position if we already tried to get the last saved position + if (m_initializeState == PositionInitialized) { + m_hasPosition = true; + auto screen = window->screen(); + auto nativePosition = QHighDpiScaling::mapPositionToNative(window->framePosition(), + screen->handle()); + m_lastWindowPosition = {screen->name(), nativePosition}; + + m_savePositionTimer.start(); + } + if (state == InitializePosition) + m_initializeState = InitializePosition; } void QQmlPreviewPosition::saveWindowPosition() { if (m_hasPosition) { + const QByteArray positionAsByteArray = fromPositionToByteArray(m_lastWindowPosition); if (!m_settingsKey.isNull()) - m_settings.setValue(m_settingsKey, m_lastWindowPosition); + m_settings.setValue(m_settingsKey, positionAsByteArray); - m_settings.setValue(QLatin1String("global_lastpostion"), m_lastWindowPosition); + m_settings.setValue(QLatin1String("global_lastpostion"), positionAsByteArray); } } @@ -85,29 +134,86 @@ void QQmlPreviewPosition::loadWindowPositionSettings(const QUrl &url) if (m_settings.contains(m_settingsKey)) { m_hasPosition = true; - m_lastWindowPosition = m_settings.value(m_settingsKey).toPoint(); + readLastPositionFromByteArray(m_settings.value(m_settingsKey).toByteArray()); } } void QQmlPreviewPosition::initLastSavedWindowPosition(QWindow *window) { - if (m_positionedWindows.contains(window)) - return; + Q_ASSERT(window); + m_initializeState = PositionInitialized; + if (m_currentInitScreensData.isEmpty()) + m_currentInitScreensData = initScreensData(); + // if it is the first time we just use the fall back from a last shown qml file if (!m_hasPosition) { - // in case there was nothing saved, we do not want to set anything if (!m_settings.contains(QLatin1String("global_lastpostion"))) return; - m_lastWindowPosition = m_settings.value(QLatin1String("global_lastpostion")).toPoint(); + readLastPositionFromByteArray(m_settings.value(QLatin1String("global_lastpostion")) + .toByteArray()); } - if (QGuiApplication::screenAt(m_lastWindowPosition)) - window->setFramePosition(m_lastWindowPosition); + setPosition(m_lastWindowPosition, window); +} + +QByteArray QQmlPreviewPosition::fromPositionToByteArray( + const QQmlPreviewPosition::Position &position) +{ + QByteArray array; + QDataStream stream(&array, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_5_12); + + const quint16 majorVersion = 1; + const quint16 minorVersion = 0; + + stream << majorVersion + << minorVersion + << m_currentInitScreensData + << position.screenName + << position.nativePosition; + return array; +} + +void QQmlPreviewPosition::readLastPositionFromByteArray(const QByteArray &array) +{ + QDataStream stream(array); + stream.setVersion(QDataStream::Qt_5_12); + + // no version check for 1.0 + //const quint16 currentMajorVersion = 1; + quint16 majorVersion = 0; + quint16 minorVersion = 0; - m_positionedWindows.append(window); + stream >> majorVersion >> minorVersion; + + QVector<ScreenData> initScreensData; + stream >> initScreensData; + + if (m_currentInitScreensData != initScreensData) + return; + + QString nameOfScreen; + stream >> nameOfScreen; + + QScreen *screen = findScreen(nameOfScreen); + if (!screen) + return; + + QPoint nativePosition; + stream >> nativePosition; + if (nativePosition.isNull()) + return; + m_lastWindowPosition = {nameOfScreen, nativePosition}; } -const QSize QQmlPreviewPosition::currentScreenSize(QWindow *window) +void QQmlPreviewPosition::setPosition(const QQmlPreviewPosition::Position &position, + QWindow *window) { - return availableScreenSize(window->position()); + if (position.nativePosition.isNull()) + return; + if (QScreen *screen = findScreen(position.screenName)) { + window->setScreen(screen); + window->setFramePosition(QHighDpiScaling::mapPositionFromNative(position.nativePosition, + screen->handle())); + } } QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h index 3d4ca9dc67..f403917f8c 100644 --- a/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h +++ b/src/plugins/qmltooling/qmldbg_preview/qqmlpreviewposition.h @@ -56,6 +56,8 @@ #include <QtCore/qurl.h> #include <QtCore/qtimer.h> #include <QtCore/qsettings.h> +#include <QtCore/qsize.h> +#include <QtCore/qdatastream.h> QT_BEGIN_NAMESPACE @@ -64,23 +66,46 @@ class QWindow; class QQmlPreviewPosition { public: + class ScreenData { + public: + bool operator==(const QQmlPreviewPosition::ScreenData &other) const; + QString name; + QSize size; + }; + class Position { + public: + QString screenName; + QPoint nativePosition; + }; + enum InitializeState { + InitializePosition, + PositionInitialized + }; + QQmlPreviewPosition(); + ~QQmlPreviewPosition(); - void setPosition(const QPoint &point); - void saveWindowPosition(); - void loadWindowPositionSettings(const QUrl &url); + + void takePosition(QWindow *window, InitializeState state = PositionInitialized); void initLastSavedWindowPosition(QWindow *window); - static const QSize currentScreenSize(QWindow *window); + void loadWindowPositionSettings(const QUrl &url); private: + void setPosition(const QQmlPreviewPosition::Position &position, QWindow *window); + QByteArray fromPositionToByteArray(const Position &position); + void readLastPositionFromByteArray(const QByteArray &array); + void saveWindowPosition(); + bool m_hasPosition = false; - QPoint m_lastWindowPosition; + InitializeState m_initializeState = InitializePosition; QSettings m_settings; QString m_settingsKey; QTimer m_savePositionTimer; + Position m_lastWindowPosition; QVector<QWindow *> m_positionedWindows; -}; + QVector<ScreenData> m_currentInitScreensData; +}; QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index a22dd7aa32..6e077ec44c 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1111,6 +1111,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg QV4::CompiledData::TranslationData translationData; translationData.number = -1; translationData.commentIndex = 0; // empty string + translationData.padding = 0; if (!args || !args->expression) return; // no arguments, stop @@ -1151,6 +1152,7 @@ void IRBuilder::tryGeneratingTranslationBinding(const QStringRef &base, AST::Arg QV4::CompiledData::TranslationData translationData; translationData.number = -1; translationData.commentIndex = 0; // empty string, but unused + translationData.padding = 0; if (!args || !args->expression) return; // no arguments, stop diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index f497184ab5..e0d259bd0c 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1738,59 +1738,46 @@ Codegen::Reference Codegen::binopHelper(QSOperator::Op oper, Reference &left, Re return Reference::fromAccumulator(this); } -static QSOperator::Op operatorForSwappedOperands(QSOperator::Op oper) -{ - switch (oper) { - case QSOperator::StrictEqual: return QSOperator::StrictEqual; - case QSOperator::StrictNotEqual: return QSOperator::StrictNotEqual; - case QSOperator::Equal: return QSOperator::Equal; - case QSOperator::NotEqual: return QSOperator::NotEqual; - case QSOperator::Gt: return QSOperator::Le; - case QSOperator::Ge: return QSOperator::Lt; - case QSOperator::Lt: return QSOperator::Ge; - case QSOperator::Le: return QSOperator::Gt; - default: Q_UNIMPLEMENTED(); return QSOperator::Invalid; - } -} - Codegen::Reference Codegen::jumpBinop(QSOperator::Op oper, Reference &left, Reference &right) { - if (left.isConstant()) { - oper = operatorForSwappedOperands(oper); - qSwap(left, right); - } + // See if we can generate specialized comparison instructions: + if (oper == QSOperator::Equal || oper == QSOperator::NotEqual) { + // Because == and != are reflexive, we can do the following: + if (left.isConstant() && !right.isConstant()) + qSwap(left, right); // null==a -> a==null - if (right.isConstant() && (oper == QSOperator::Equal || oper == QSOperator::NotEqual)) { - Value c = Value::fromReturnedValue(right.constant); - if (c.isNull() || c.isUndefined()) { - left.loadInAccumulator(); - if (oper == QSOperator::Equal) { - Instruction::CmpEqNull cmp; - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } else if (oper == QSOperator::NotEqual) { - Instruction::CmpNeNull cmp; - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } - } else if (c.isInt32()) { - left.loadInAccumulator(); - if (oper == QSOperator::Equal) { - Instruction::CmpEqInt cmp; - cmp.lhs = c.int_32(); - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } else if (oper == QSOperator::NotEqual) { - Instruction::CmpNeInt cmp; - cmp.lhs = c.int_32(); - bytecodeGenerator->addInstruction(cmp); - addCJump(); - return Reference(); - } + if (right.isConstant()) { + Value c = Value::fromReturnedValue(right.constant); + if (c.isNull() || c.isUndefined()) { + left.loadInAccumulator(); + if (oper == QSOperator::Equal) { + Instruction::CmpEqNull cmp; + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } else if (oper == QSOperator::NotEqual) { + Instruction::CmpNeNull cmp; + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } + } else if (c.isInt32()) { + left.loadInAccumulator(); + if (oper == QSOperator::Equal) { + Instruction::CmpEqInt cmp; + cmp.lhs = c.int_32(); + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } else if (oper == QSOperator::NotEqual) { + Instruction::CmpNeInt cmp; + cmp.lhs = c.int_32(); + bytecodeGenerator->addInstruction(cmp); + addCJump(); + return Reference(); + } + } } } diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index b110fafaac..dc5466371d 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -98,18 +98,25 @@ CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, setUnitData(unitData, nullptr, fileName, finalUrlString); } -#ifndef V4_BOOTSTRAP CompilationUnit::~CompilationUnit() { +#ifndef V4_BOOTSTRAP unlink(); +#endif if (data) { if (data->qmlUnit() != qmlData) free(const_cast<QmlUnit *>(qmlData)); qmlData = nullptr; +#ifndef V4_BOOTSTRAP if (!(data->flags & QV4::CompiledData::Unit::StaticData)) free(const_cast<Unit *>(data)); +#else + // Unconditionally free the memory. In the dev tools we create units that have + // the flag set and will be saved to disk, so intended to persist later. + free(const_cast<Unit *>(data)); +#endif } data = nullptr; #if Q_BYTE_ORDER == Q_BIG_ENDIAN @@ -120,6 +127,7 @@ CompilationUnit::~CompilationUnit() delete [] imports; imports = nullptr; } +#ifndef V4_BOOTSTRAP QString CompilationUnit::localCacheFilePath(const QUrl &url) { diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 2d7a027b37..23e33247a8 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -1090,11 +1090,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit final : public CompilationUnitBase const QmlUnit *qmlData = nullptr; public: CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString()); -#ifdef V4_BOOTSTRAP - ~CompilationUnit() {} -#else ~CompilationUnit(); -#endif void addref() { diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp index 97b955632d..a2c8e3916f 100644 --- a/src/qml/jsruntime/qv4qmlcontext.cpp +++ b/src/qml/jsruntime/qv4qmlcontext.cpp @@ -79,6 +79,53 @@ void Heap::QQmlContextWrapper::destroy() Object::destroy(); } +static OptionalReturnedValue searchContextProperties(QV4::ExecutionEngine *v4, QQmlContextData *context, String *name, + bool *hasProperty, Value *base, QV4::Lookup *lookup, + QV4::Lookup *originalLookup, QQmlEnginePrivate *ep) +{ + const QV4::IdentifierHash &properties = context->propertyNames(); + if (properties.count() == 0) + return OptionalReturnedValue(); + + const int propertyIdx = properties.value(name); + + if (propertyIdx == -1) + return OptionalReturnedValue(); + + if (propertyIdx < context->idValueCount) { + if (hasProperty) + *hasProperty = true; + + if (lookup) { + lookup->qmlContextIdObjectLookup.objectId = propertyIdx; + lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupIdObject; + return OptionalReturnedValue(lookup->qmlContextPropertyGetter(lookup, v4, base)); + } else if (originalLookup) { + originalLookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupInParentContextHierarchy; + } + + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); + return OptionalReturnedValue(QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx])); + } + + QQmlContextPrivate *cp = context->asQQmlContextPrivate(); + + if (ep->propertyCapture) + ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); + + const QVariant &value = cp->propertyValues.at(propertyIdx); + if (hasProperty) + *hasProperty = true; + if (value.userType() == qMetaTypeId<QList<QObject*> >()) { + QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), + QQmlContextPrivate::context_count, + QQmlContextPrivate::context_at); + return OptionalReturnedValue(QmlListWrapper::create(v4, prop, qMetaTypeId<QQmlListProperty<QObject> >())); + } + return OptionalReturnedValue(v4->fromVariant(cp->propertyValues.at(propertyIdx))); +} + ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *resource, PropertyKey id, const Value *receiver, bool *hasProperty, Value *base, Lookup *lookup) { if (!id.isString()) @@ -224,47 +271,8 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r } while (context) { - // Search context properties - const QV4::IdentifierHash &properties = context->propertyNames(); - if (properties.count()) { - int propertyIdx = properties.value(name); - - if (propertyIdx != -1) { - - if (propertyIdx < context->idValueCount) { - if (hasProperty) - *hasProperty = true; - - if (lookup) { - lookup->qmlContextIdObjectLookup.objectId = propertyIdx; - lookup->qmlContextPropertyGetter = QQmlContextWrapper::lookupIdObject; - return lookup->qmlContextPropertyGetter(lookup, v4, base); - } - - if (ep->propertyCapture) - ep->propertyCapture->captureProperty(&context->idValues[propertyIdx].bindings); - return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]); - } else { - - QQmlContextPrivate *cp = context->asQQmlContextPrivate(); - - if (ep->propertyCapture) - ep->propertyCapture->captureProperty(context->asQQmlContext(), -1, propertyIdx + cp->notifyIndex); - - const QVariant &value = cp->propertyValues.at(propertyIdx); - if (hasProperty) - *hasProperty = true; - if (value.userType() == qMetaTypeId<QList<QObject*> >()) { - QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx), - QQmlContextPrivate::context_count, - QQmlContextPrivate::context_at); - return QmlListWrapper::create(v4, prop, qMetaTypeId<QQmlListProperty<QObject> >()); - } else { - return scope.engine->fromVariant(cp->propertyValues.at(propertyIdx)); - } - } - } - } + if (auto property = searchContextProperties(v4, context, name, hasProperty, base, lookup, originalLookup, ep)) + return *property; // Search scope object if (scopeObject) { @@ -311,17 +319,21 @@ ReturnedValue QQmlContextWrapper::getPropertyAndBase(const QQmlContextWrapper *r if (base) *base = QV4::QObjectWrapper::wrap(v4, context->contextObject); - if (lookup && propertyData) { - QQmlData *ddata = QQmlData::get(context->contextObject, false); - if (ddata && ddata->propertyCache) { - ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); - const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); - lookup->qobjectLookup.ic = That->internalClass(); - lookup->qobjectLookup.staticQObject = nullptr; - lookup->qobjectLookup.propertyCache = ddata->propertyCache; - lookup->qobjectLookup.propertyCache->addref(); - lookup->qobjectLookup.propertyData = propertyData; - lookup->qmlContextPropertyGetter = contextGetterFunction; + if (propertyData) { + if (lookup) { + QQmlData *ddata = QQmlData::get(context->contextObject, false); + if (ddata && ddata->propertyCache) { + ScopedValue val(scope, base ? *base : Value::fromReturnedValue(QV4::QObjectWrapper::wrap(v4, context->contextObject))); + const QObjectWrapper *That = static_cast<const QObjectWrapper *>(val->objectValue()); + lookup->qobjectLookup.ic = That->internalClass(); + lookup->qobjectLookup.staticQObject = nullptr; + lookup->qobjectLookup.propertyCache = ddata->propertyCache; + lookup->qobjectLookup.propertyCache->addref(); + lookup->qobjectLookup.propertyData = propertyData; + lookup->qmlContextPropertyGetter = contextGetterFunction; + } + } else if (originalLookup) { + originalLookup->qmlContextPropertyGetter = lookupInParentContextHierarchy; } } @@ -576,6 +588,55 @@ ReturnedValue QQmlContextWrapper::lookupInGlobalObject(Lookup *l, ExecutionEngin return result; } +ReturnedValue QQmlContextWrapper::lookupInParentContextHierarchy(Lookup *l, ExecutionEngine *engine, Value *base) +{ + Scope scope(engine); + Scoped<QmlContext> qmlContext(scope, engine->qmlContext()); + if (!qmlContext) + return QV4::Encode::undefined(); + + QQmlContextData *context = qmlContext->qmlContext(); + if (!context) + return QV4::Encode::undefined(); + + QQmlContextData *expressionContext = context; + + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine()); + + PropertyKey id =engine->identifierTable->asPropertyKey(engine->currentStackFrame->v4Function->compilationUnit-> + runtimeStrings[l->nameIndex]); + ScopedString name(scope, id.asStringOrSymbol()); + + ScopedValue result(scope); + + for (context = context->parent; context; context = context->parent) { + if (auto property = searchContextProperties(engine, context, name, nullptr, base, nullptr, nullptr, ep)) + return *property; + + // Search context object + if (context->contextObject) { + bool hasProp = false; + result = QV4::QObjectWrapper::getQmlProperty(engine, context, context->contextObject, + name, QV4::QObjectWrapper::CheckRevision, &hasProp); + if (hasProp) { + if (base) + *base = QV4::QObjectWrapper::wrap(engine, context->contextObject); + + return result->asReturnedValue(); + } + } + } + + bool hasProp = false; + result = engine->globalObject->get(name, &hasProp); + if (hasProp) + return result->asReturnedValue(); + + expressionContext->unresolvedNames = true; + + return Encode::undefined(); +} + void Heap::QmlContext::init(QV4::ExecutionContext *outerContext, QV4::QQmlContextWrapper *qml) { Heap::ExecutionContext::init(Heap::ExecutionContext::Type_QmlContext); diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h index 6375294375..4c8287ef2f 100644 --- a/src/qml/jsruntime/qv4qmlcontext_p.h +++ b/src/qml/jsruntime/qv4qmlcontext_p.h @@ -111,6 +111,7 @@ struct Q_QML_EXPORT QQmlContextWrapper : Object static ReturnedValue lookupScopeObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupContextObjectProperty(Lookup *l, ExecutionEngine *engine, Value *base); static ReturnedValue lookupInGlobalObject(Lookup *l, ExecutionEngine *engine, Value *base); + static ReturnedValue lookupInParentContextHierarchy(Lookup *l, ExecutionEngine *engine, Value *base); }; struct Q_QML_EXPORT QmlContext : public ExecutionContext diff --git a/src/qmltest/doc/src/qtquicktest-index.qdoc b/src/qmltest/doc/src/qtquicktest-index.qdoc index 4c0124689b..668d6c1417 100644 --- a/src/qmltest/doc/src/qtquicktest-index.qdoc +++ b/src/qmltest/doc/src/qtquicktest-index.qdoc @@ -149,11 +149,13 @@ \header \li Name \li Purpose + \li Since \row \li \c {void applicationAvailable()} \li Called right after the QApplication object was instantiated. - Use this function to setup everything that is not related - to QML directly. + Use this function to perform setup that does not require a + \l QQmlEngine instance. + \li Qt 5.12 \row \li \c {void qmlEngineAvailable(QQmlEngine *)} \li Called when the QML engine is available. @@ -161,10 +163,17 @@ \l {QQmlEngine::addPluginPath}{plugin paths}, and \l {QQmlFileSelector::setExtraSelectors}{extra file selectors} will have been set on the engine by this point. + + This function can be used to \l {Choosing the Correct Integration + Method Between C++ and QML}{register QML types} and + \l {QQmlEngine::addImportPath()}{add import paths}, + amongst other things. + \li Qt 5.11 \row \li \c {void cleanupTestCase()} \li Called right after the test execution has finished. Use this function to clean up before everything will start to be destructed. + \li Qt 5.12 \endtable Each function will be called once for each \c {tst_*.qml} file, so any diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index 9a73726797..9cddf61543 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -575,6 +575,13 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch qmlFileSelector->setExtraSelectors(fileSelectors); } + // Do this down here so that import paths, plugin paths, file selectors, etc. are available + // in case the user needs access to them. Do it _before_ the TestCaseCollector parses the + // QML files though, because it attempts to import modules, which might not be available + // if qmlRegisterType()/QQmlEngine::addImportPath() are called in qmlEngineAvailable(). + if (setup) + maybeInvokeSetupMethod(setup, "qmlEngineAvailable(QQmlEngine*)", Q_ARG(QQmlEngine*, &engine)); + TestCaseCollector testCaseCollector(fi, &engine); if (!testCaseCollector.errors().isEmpty()) { for (const QQmlError &error : testCaseCollector.errors()) @@ -606,11 +613,6 @@ int quick_test_main_with_setup(int argc, char **argv, const char *name, const ch view.rootContext()->setContextProperty (QLatin1String("qtest"), QTestRootObject::instance()); // Deprecated. Use QTestRootObject from Qt.test.qtestroot instead - // Do this down here so that import paths, plugin paths, - // file selectors, etc. are available in case the user needs access to them. - if (setup) - maybeInvokeSetupMethod(setup, "qmlEngineAvailable(QQmlEngine*)", Q_ARG(QQmlEngine*, view.engine())); - view.setObjectName(fi.baseName()); view.setTitle(view.objectName()); QTestRootObject::instance()->init(); diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp index f713aa76c3..c7f8ec1118 100644 --- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp +++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp @@ -319,12 +319,12 @@ void tst_QQmlPreview::zoom() QTRY_VERIFY(m_files.contains(testFile(file))); float baseZoomFactor = -1; QTRY_VERIFY_WITH_TIMEOUT((baseZoomFactor = parseZoomFactor(m_process->output())) > 0, 30000); - m_client->triggerZoom(2.0f); - verifyZoomFactor(m_process, baseZoomFactor * 2.0f); - m_client->triggerZoom(1.5f); - verifyZoomFactor(m_process, baseZoomFactor * 1.5f); - m_client->triggerZoom(0.5f); - verifyZoomFactor(m_process, baseZoomFactor * 0.5f); + + for (auto testZoomFactor : {2.0f, 1.5f, 0.5f}) { + m_client->triggerZoom(testZoomFactor); + verifyZoomFactor(m_process, baseZoomFactor * testZoomFactor); + } + m_client->triggerZoom(-1.0f); verifyZoomFactor(m_process, baseZoomFactor); m_process->stop(); diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index fb9c7b0152..3e871108bc 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -235,6 +235,8 @@ private slots: void importModuleWithLexicallyScopedVars(); void importExportErrors(); + void equality(); + public: Q_INVOKABLE QJSValue throwingCppMethod1(); Q_INVOKABLE void throwingCppMethod2(); @@ -4622,6 +4624,14 @@ void tst_QJSEngine::importExportErrors() } } +void tst_QJSEngine::equality() +{ + QJSEngine engine; + QJSValue ok = engine.evaluate("(0 < 0) ? 'ko' : 'ok'"); + QVERIFY(ok.isString()); + QCOMPARE(ok.toString(), QString("ok")); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qmlcachegen/Enums.qml b/tests/auto/qml/qmlcachegen/data/Enums.qml index 830babb73e..830babb73e 100644 --- a/tests/auto/qml/qmlcachegen/Enums.qml +++ b/tests/auto/qml/qmlcachegen/data/Enums.qml diff --git a/tests/auto/qml/qmlcachegen/Retain.qml b/tests/auto/qml/qmlcachegen/data/Retain.qml index 0e69012662..0e69012662 100644 --- a/tests/auto/qml/qmlcachegen/Retain.qml +++ b/tests/auto/qml/qmlcachegen/data/Retain.qml diff --git a/tests/auto/qml/qmlcachegen/data/componentInItem.qml b/tests/auto/qml/qmlcachegen/data/componentInItem.qml new file mode 100644 index 0000000000..820b9fddcd --- /dev/null +++ b/tests/auto/qml/qmlcachegen/data/componentInItem.qml @@ -0,0 +1,15 @@ +import QtQuick 2.12 + +Item { + Component { + Rectangle { + id: xxx + Text { + text: qsTr("&Undo") + } + Text { + text: qsTr("&Redo") + } + } + } +} diff --git a/tests/auto/qml/qmlcachegen/jsimport.qml b/tests/auto/qml/qmlcachegen/data/jsimport.qml index 9c40878e60..9c40878e60 100644 --- a/tests/auto/qml/qmlcachegen/jsimport.qml +++ b/tests/auto/qml/qmlcachegen/data/jsimport.qml diff --git a/tests/auto/qml/qmlcachegen/jsmoduleimport.qml b/tests/auto/qml/qmlcachegen/data/jsmoduleimport.qml index c1fad7fee2..c1fad7fee2 100644 --- a/tests/auto/qml/qmlcachegen/jsmoduleimport.qml +++ b/tests/auto/qml/qmlcachegen/data/jsmoduleimport.qml diff --git a/tests/auto/qml/qmlcachegen/library.js b/tests/auto/qml/qmlcachegen/data/library.js index 51fb41dc23..51fb41dc23 100644 --- a/tests/auto/qml/qmlcachegen/library.js +++ b/tests/auto/qml/qmlcachegen/data/library.js diff --git a/tests/auto/qml/qmlcachegen/script.js b/tests/auto/qml/qmlcachegen/data/script.js index fa55f9069e..fa55f9069e 100644 --- a/tests/auto/qml/qmlcachegen/script.js +++ b/tests/auto/qml/qmlcachegen/data/script.js diff --git a/tests/auto/qml/qmlcachegen/script.mjs b/tests/auto/qml/qmlcachegen/data/script.mjs index 459c336125..459c336125 100644 --- a/tests/auto/qml/qmlcachegen/script.mjs +++ b/tests/auto/qml/qmlcachegen/data/script.mjs diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qml b/tests/auto/qml/qmlcachegen/data/trickypaths.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/trickypaths.qml +++ b/tests/auto/qml/qmlcachegen/data/trickypaths.qml diff --git a/tests/auto/qml/qmlcachegen/umlaut.qml b/tests/auto/qml/qmlcachegen/data/umlaut.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/umlaut.qml +++ b/tests/auto/qml/qmlcachegen/data/umlaut.qml diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-core-yc.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-core-yc.qml +++ b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-core-yc.qml diff --git a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-more.qml index 0836808dc2..0836808dc2 100644 --- a/tests/auto/qml/qmlcachegen/versionStyleSuffix-1.2-more.qml +++ b/tests/auto/qml/qmlcachegen/data/versionStyleSuffix-1.2-more.qml diff --git a/tests/auto/qml/qmlcachegen/versionchecks.qml b/tests/auto/qml/qmlcachegen/data/versionchecks.qml index 77d67e7da4..77d67e7da4 100644 --- a/tests/auto/qml/qmlcachegen/versionchecks.qml +++ b/tests/auto/qml/qmlcachegen/data/versionchecks.qml diff --git a/tests/auto/qml/qmlcachegen/worker.js b/tests/auto/qml/qmlcachegen/data/worker.js index dd2d0b843d..dd2d0b843d 100644 --- a/tests/auto/qml/qmlcachegen/worker.js +++ b/tests/auto/qml/qmlcachegen/data/worker.js diff --git a/tests/auto/qml/qmlcachegen/worker.qml b/tests/auto/qml/qmlcachegen/data/worker.qml index 1f1c9d1ac7..1f1c9d1ac7 100644 --- a/tests/auto/qml/qmlcachegen/worker.qml +++ b/tests/auto/qml/qmlcachegen/data/worker.qml diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index c7820ac1cd..7bd4414302 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -2,26 +2,34 @@ CONFIG += testcase qtquickcompiler TARGET = tst_qmlcachegen macos:CONFIG -= app_bundle +include (../../shared/util.pri) +TESTDATA = data/* + SOURCES += tst_qmlcachegen.cpp -workerscripts_test.files = worker.js worker.qml +RESOURCES += \ + data/versionchecks.qml \ + data/jsimport.qml \ + data/script.js \ + data/library.js \ + data/Enums.qml \ + data/componentInItem.qml \ + data/jsmoduleimport.qml \ + data/script.mjs + +workerscripts_test.files = \ + data/worker.js \ + data/worker.qml workerscripts_test.prefix = /workerscripts -RESOURCES += workerscripts_test - -RESOURCES += versionchecks.qml - -RESOURCES += trickypaths.qrc -RESOURCES += jsimport.qml script.js library.js - -RESOURCES += Enums.qml +RESOURCES += \ + workerscripts_test \ + trickypaths.qrc \ + retain.qrc # QTBUG-46375 !win32: RESOURCES += trickypaths_umlaut.qrc -RESOURCES += jsmoduleimport.qml script.mjs - -RESOURCES += retain.qrc QTQUICK_COMPILER_RETAINED_RESOURCES += retain.qrc QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmlcachegen/retain.qrc b/tests/auto/qml/qmlcachegen/retain.qrc index af042b25d8..e5eed9b12f 100644 --- a/tests/auto/qml/qmlcachegen/retain.qrc +++ b/tests/auto/qml/qmlcachegen/retain.qrc @@ -1,5 +1,5 @@ <RCC> <qresource prefix="/"> - <file>Retain.qml</file> + <file alias="Retain.qml">data/Retain.qml</file> </qresource> </RCC> diff --git a/tests/auto/qml/qmlcachegen/trickypaths.qrc b/tests/auto/qml/qmlcachegen/trickypaths.qrc index 57977ccf6d..b0c3bcf209 100644 --- a/tests/auto/qml/qmlcachegen/trickypaths.qrc +++ b/tests/auto/qml/qmlcachegen/trickypaths.qrc @@ -1,7 +1,7 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/directory with spaces"> -<file alias="file name with spaces.qml">trickypaths.qml</file> -<file>versionStyleSuffix-1.2-core-yc.qml</file> -<file>versionStyleSuffix-1.2-more.qml</file> +<file alias="file name with spaces.qml">data/trickypaths.qml</file> +<file alias="versionStyleSuffix-1.2-core-yc.qml">data/versionStyleSuffix-1.2-core-yc.qml</file> +<file alias="versionStyleSuffix-1.2-more.qml">data/versionStyleSuffix-1.2-more.qml</file> </qresource> </RCC> diff --git a/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc index 9ca889d692..17aa30473f 100644 --- a/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc +++ b/tests/auto/qml/qmlcachegen/trickypaths_umlaut.qrc @@ -1,5 +1,5 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource prefix="/"> -<file alias="Bäh.qml">umlaut.qml</file> +<file alias="Bäh.qml">data/umlaut.qml</file> </qresource> </RCC> diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 8cfa4cb6af..5462e6c8ae 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -38,7 +38,9 @@ #include <private/qqmlcomponent_p.h> #include <qtranslator.h> -class tst_qmlcachegen: public QObject +#include "../../shared/util.h" + +class tst_qmlcachegen: public QQmlDataTest { Q_OBJECT @@ -66,6 +68,9 @@ private slots: void enums(); void sourceFileIndices(); + + void reproducibleCache_data(); + void reproducibleCache(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -353,12 +358,13 @@ static QQmlPrivate::CachedQmlUnit *temporaryModifiedCachedUnit = nullptr; void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() { - QVERIFY(QFile::exists(":/versionchecks.qml")); - QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0); + QVERIFY(QFile::exists(":/data/versionchecks.qml")); + QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0); Q_ASSERT(!temporaryModifiedCachedUnit); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - const QV4::CompiledData::Unit *originalUnit = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error); + const QV4::CompiledData::Unit *originalUnit = QQmlMetaType::findCachedCompilationUnit( + QUrl("qrc:/data/versionchecks.qml"), &error); QVERIFY(originalUnit); QV4::CompiledData::Unit *tweakedUnit = (QV4::CompiledData::Unit *)malloc(originalUnit->unitSize); memcpy(reinterpret_cast<void *>(tweakedUnit), reinterpret_cast<const void *>(originalUnit), originalUnit->unitSize); @@ -366,7 +372,7 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() temporaryModifiedCachedUnit = new QQmlPrivate::CachedQmlUnit{tweakedUnit, nullptr, nullptr}; auto testHandler = [](const QUrl &url) -> const QQmlPrivate::CachedQmlUnit * { - if (url == QUrl("qrc:/versionchecks.qml")) + if (url == QUrl("qrc:/data/versionchecks.qml")) return temporaryModifiedCachedUnit; return nullptr; }; @@ -374,15 +380,18 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() { QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - QVERIFY(!QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error)); + QVERIFY(!QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/data/versionchecks.qml"), &error)); QCOMPARE(error, QQmlMetaType::CachedUnitLookupError::VersionMismatch); } { QQmlEngine engine; - QQmlComponent component(&engine, QUrl("qrc:/versionchecks.qml")); + QQmlComponent component(&engine, QUrl("qrc:/data/versionchecks.qml")); QCOMPARE(component.status(), QQmlComponent::Error); - QCOMPARE(component.errorString(), QString("qrc:/versionchecks.qml:-1 File was compiled ahead of time with an incompatible version of Qt and the original file cannot be found. Please recompile\n")); + QCOMPARE(component.errorString(), + QString("qrc:/data/versionchecks.qml:-1 File was compiled ahead of time with an " + "incompatible version of Qt and the original file cannot be found. Please " + "recompile\n")); } Q_ASSERT(temporaryModifiedCachedUnit); @@ -402,12 +411,12 @@ void tst_qmlcachegen::retainedResources() void tst_qmlcachegen::workerScripts() { - QVERIFY(QFile::exists(":/workerscripts/worker.js")); - QVERIFY(QFile::exists(":/workerscripts/worker.qml")); - QCOMPARE(QFileInfo(":/workerscripts/worker.js").size(), 0); + QVERIFY(QFile::exists(":/workerscripts/data/worker.js")); + QVERIFY(QFile::exists(":/workerscripts/data/worker.qml")); + QCOMPARE(QFileInfo(":/workerscripts/data/worker.js").size(), 0); QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/worker.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/data/worker.qml")); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_VERIFY(obj->property("success").toBool()); @@ -504,7 +513,7 @@ void tst_qmlcachegen::trickyPaths() void tst_qmlcachegen::qrcScriptImport() { QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///jsimport.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/jsimport.qml")); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_COMPARE(obj->property("value").toInt(), 42); @@ -567,14 +576,14 @@ void tst_qmlcachegen::fsScriptImport() void tst_qmlcachegen::moduleScriptImport() { QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///jsmoduleimport.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/jsmoduleimport.qml")); QVERIFY2(!component.isError(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_VERIFY(obj->property("ok").toBool()); - QVERIFY(QFile::exists(":/script.mjs")); - QCOMPARE(QFileInfo(":/script.mjs").size(), 0); + QVERIFY(QFile::exists(":/data/script.mjs")); + QCOMPARE(QFileInfo(":/data/script.mjs").size(), 0); { auto componentPrivate = QQmlComponentPrivate::get(&component); @@ -587,7 +596,8 @@ void tst_qmlcachegen::moduleScriptImport() QVERIFY(unitData->flags & QV4::CompiledData::Unit::IsESModule); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/script.mjs"), &error); + const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit( + QUrl("qrc:/data/script.mjs"), &error); QVERIFY(unitFromResources); QCOMPARE(unitFromResources, compilationUnit->unitData()); @@ -597,7 +607,7 @@ void tst_qmlcachegen::moduleScriptImport() void tst_qmlcachegen::enums() { QQmlEngine engine; - CleanlyLoadingComponent component(&engine, QUrl("qrc:///Enums.qml")); + CleanlyLoadingComponent component(&engine, QUrl("qrc:///data/Enums.qml")); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); QTRY_COMPARE(obj->property("value").toInt(), 200); @@ -605,16 +615,50 @@ void tst_qmlcachegen::enums() void tst_qmlcachegen::sourceFileIndices() { - QVERIFY(QFile::exists(":/versionchecks.qml")); - QCOMPARE(QFileInfo(":/versionchecks.qml").size(), 0); + QVERIFY(QFile::exists(":/data/versionchecks.qml")); + QCOMPARE(QFileInfo(":/data/versionchecks.qml").size(), 0); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; - const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit(QUrl("qrc:/versionchecks.qml"), &error); + const QV4::CompiledData::Unit *unitFromResources = QQmlMetaType::findCachedCompilationUnit( + QUrl("qrc:/data/versionchecks.qml"), &error); QVERIFY(unitFromResources); QVERIFY(unitFromResources->flags & QV4::CompiledData::Unit::PendingTypeCompilation); QCOMPARE(uint(unitFromResources->sourceFileIndex), uint(0)); } +void tst_qmlcachegen::reproducibleCache_data() +{ + QTest::addColumn<QString>("filePath"); + + QDir dir(dataDirectory()); + for (const QString &entry : dir.entryList(QDir::Files)) { + QVERIFY(entry.endsWith(".qml") || entry.endsWith(".js") || entry.endsWith(".mjs")); + QTest::newRow(entry.toUtf8().constData()) << dir.filePath(entry); + } +} + +void tst_qmlcachegen::reproducibleCache() +{ + QFETCH(QString, filePath); + + QFile file(filePath); + QVERIFY(file.exists()); + + auto generate = [](const QString &path) { + if (!generateCache(path)) + return QByteArray(); + QFile generated(path + 'c'); + [&](){ QVERIFY(generated.open(QIODevice::ReadOnly)); }(); + const QByteArray result = generated.readAll(); + generated.remove(); + return result; + }; + + const QByteArray contents1 = generate(file.fileName()); + const QByteArray contents2 = generate(file.fileName()); + QCOMPARE(contents1, contents2); +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" diff --git a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST index cdb3e7733b..de939b5273 100644 --- a/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST +++ b/tests/auto/quick/qquickmultipointtoucharea/BLACKLIST @@ -1,6 +1,10 @@ [nonOverlapping] ubuntu-16.04 ubuntu-18.04 +opensuse-42.3 +opensuse-leap [nested] ubuntu-16.04 ubuntu-18.04 +opensuse-42.3 +opensuse-leap diff --git a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp index b34612ee88..832b973d96 100644 --- a/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp +++ b/tests/auto/quick/qquickrectangle/tst_qquickrectangle.cpp @@ -159,17 +159,15 @@ void tst_qquickrectangle::gradient_multiple() // Start off clean QQuickItemPrivate *firstRectPriv = QQuickItemPrivate::get(firstRect); QQuickItemPrivate *secondRectPriv = QQuickItemPrivate::get(secondRect); - bool firstIsDirty = firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content; + QTRY_VERIFY(!(firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content)); bool secondIsDirty = secondRectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(!firstIsDirty); QVERIFY(!secondIsDirty); QMetaObject::invokeMethod(view.rootObject(), "changeGradient"); // Changing the gradient should have scheduled an update of both items - firstIsDirty = firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content; + QTRY_VERIFY(firstRectPriv->dirtyAttributes & QQuickItemPrivate::Content); secondIsDirty = secondRectPriv->dirtyAttributes & QQuickItemPrivate::Content; - QVERIFY(firstIsDirty); QVERIFY(secondIsDirty); } diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index a862604fc1..4cf7fa7119 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -1645,11 +1645,11 @@ void tst_qquickwindow::focusReason() window->setTitle(QTest::currentTestFunction()); QVERIFY(QTest::qWaitForWindowExposed(window)); - QQuickItem *firstItem = new QQuickItem; + QScopedPointer<QQuickItem> firstItem(new QQuickItem); firstItem->setSize(QSizeF(100, 100)); firstItem->setParentItem(window->contentItem()); - QQuickItem *secondItem = new QQuickItem; + QScopedPointer<QQuickItem> secondItem(new QQuickItem); secondItem->setSize(QSizeF(100, 100)); secondItem->setParentItem(window->contentItem()); @@ -1673,7 +1673,7 @@ void tst_qquickwindow::ignoreUnhandledMouseEvents() window->show(); QVERIFY(QTest::qWaitForWindowExposed(window)); - QQuickItem *item = new QQuickItem; + QScopedPointer<QQuickItem> item(new QQuickItem); item->setSize(QSizeF(100, 100)); item->setParentItem(window->contentItem()); @@ -1883,8 +1883,8 @@ void tst_qquickwindow::hideThenDelete() QFETCH(bool, persistentSG); QFETCH(bool, persistentGL); - QSignalSpy *openglDestroyed = nullptr; - QSignalSpy *sgInvalidated = nullptr; + QScopedPointer<QSignalSpy> openglDestroyed; + QScopedPointer<QSignalSpy> sgInvalidated; { QQuickWindow window; @@ -1903,10 +1903,10 @@ void tst_qquickwindow::hideThenDelete() const bool isGL = window.rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL; #if QT_CONFIG(opengl) if (isGL) - openglDestroyed = new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed())); + openglDestroyed.reset(new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed()))); #endif - sgInvalidated = new QSignalSpy(&window, SIGNAL(sceneGraphInvalidated())); + sgInvalidated.reset(new QSignalSpy(&window, SIGNAL(sceneGraphInvalidated()))); window.hide(); @@ -1951,7 +1951,7 @@ void tst_qquickwindow::showHideAnimate() QQmlEngine engine; QQmlComponent component(&engine); component.loadUrl(testFileUrl("showHideAnimate.qml")); - QQuickItem* created = qobject_cast<QQuickItem *>(component.create()); + QScopedPointer<QQuickItem> created(qobject_cast<QQuickItem *>(component.create())); QVERIFY(created); @@ -2293,7 +2293,7 @@ void tst_qquickwindow::contentItemSize() QQmlEngine engine; QQmlComponent component(&engine); component.setData(QByteArray("import QtQuick 2.1\n Rectangle { anchors.fill: parent }"), QUrl()); - QQuickItem *rect = qobject_cast<QQuickItem *>(component.create()); + QScopedPointer<QQuickItem> rect(qobject_cast<QQuickItem *>(component.create())); QVERIFY(rect); rect->setParentItem(window.contentItem()); QCOMPARE(QSizeF(rect->width(), rect->height()), size); diff --git a/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml b/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml index 0f5466998a..ea6b3e014b 100644 --- a/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml +++ b/tests/auto/quicktest/quicktestmainwithsetup/data/tst_setup.qml @@ -29,9 +29,15 @@ import QtQuick 2.0 import QtTest 1.2 +import QmlRegisterTypeCppModule 1.0 +import ImportPathQmlModule 1.0 + TestCase { name: "setup" + QmlRegisterTypeCppType {} + ImportPathQmlType {} + function initTestCase() { verify(qmlEngineAvailableCalled) diff --git a/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml new file mode 100644 index 0000000000..617bdaaf67 --- /dev/null +++ b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/ImportPathQmlType.qml @@ -0,0 +1,3 @@ +import QtQuick 2.0 + +Item {} diff --git a/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir new file mode 100644 index 0000000000..dea7c9a8a4 --- /dev/null +++ b/tests/auto/quicktest/quicktestmainwithsetup/imports/ImportPathQmlModule/qmldir @@ -0,0 +1,2 @@ +module ImportPathQmlModule +ImportPathQmlType 1.0 ImportPathQmlType.qml diff --git a/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp b/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp index b0545d1a95..b5deeceac4 100644 --- a/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp +++ b/tests/auto/quicktest/quicktestmainwithsetup/tst_quicktestmainwithsetup.cpp @@ -35,6 +35,14 @@ #include "../../shared/util.h" +class QmlRegisterTypeCppType : public QObject +{ + Q_OBJECT + +public: + QmlRegisterTypeCppType() {} +}; + class CustomTestSetup : public QObject { Q_OBJECT @@ -45,6 +53,12 @@ public: public slots: void qmlEngineAvailable(QQmlEngine *qmlEngine) { + // Test that modules are successfully imported by the TestCaseCollector that + // parses the QML files (but doesn't run them). For that to happen, qmlEngineAvailable() + // must be called before TestCaseCollector does its thing. + qmlRegisterType<QmlRegisterTypeCppType>("QmlRegisterTypeCppModule", 1, 0, "QmlRegisterTypeCppType"); + qmlEngine->addImportPath(QString::fromUtf8(QT_QMLTEST_DATADIR) + "/../imports"); + qmlEngine->rootContext()->setContextProperty("qmlEngineAvailableCalled", true); } }; diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp index f6f1d99526..1c9a004cb3 100644 --- a/tools/qmlcachegen/qmlcachegen.cpp +++ b/tools/qmlcachegen/qmlcachegen.cpp @@ -204,7 +204,6 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti &irDocument.jsGenerator, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, &irDocument.jsGenerator.stringTable, illegalNames); - v4CodeGen.setUseFastLookups(false); // Disable lookups in non-standalone (aka QML) mode for (QmlIR::Object *object: qAsConst(irDocument.objects)) { if (object->functionsAndExpressions->count == 0) continue; @@ -236,8 +235,6 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti if (!saveFunction(irDocument.javaScriptCompilationUnit, &error->message)) return false; - - free(unit); } return true; } @@ -245,7 +242,6 @@ static bool compileQmlFile(const QString &inputFileName, SaveFunction saveFuncti static bool compileJSFile(const QString &inputFileName, const QString &inputFileUrl, SaveFunction saveFunction, Error *error) { QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit; - QScopedPointer<QV4::CompiledData::Unit, QScopedPointerPodDeleter> unitDataToFree; QString sourceCode; { @@ -327,7 +323,6 @@ static bool compileJSFile(const QString &inputFileName, const QString &inputFile generator.generate(irDocument); QV4::CompiledData::Unit *unitData = const_cast<QV4::CompiledData::Unit*>(irDocument.javaScriptCompilationUnit->data); unitData->flags |= QV4::CompiledData::Unit::StaticData; - unitDataToFree.reset(unitData); unit = irDocument.javaScriptCompilationUnit; } } |