diff options
author | Liang Qi <liang.qi@qt.io> | 2018-02-07 11:03:01 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-02-07 11:03:01 +0100 |
commit | 3e3c6717ba634825a65069541500c40645a808ee (patch) | |
tree | ed47bf1c276e81f5585b4ac139f6bf2a09c1a437 | |
parent | 6fe4c1f2803abac74da152b9a5656eff2d71dceb (diff) | |
parent | c6b3c69e014f846a142c2429cd2d675c75b74245 (diff) |
Merge remote-tracking branch 'origin/5.9' into 5.105.10
Change-Id: I3b250545e334f50dcef1a75acdef51820d34079a
-rw-r--r-- | src/qml/doc/snippets/code/src_script_qjsengine.cpp | 20 | ||||
-rw-r--r-- | src/qml/jsapi/qjsengine.cpp | 24 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4value_p.h | 4 | ||||
-rw-r--r-- | src/qml/memory/qv4mm.cpp | 15 | ||||
-rw-r--r-- | src/qml/qml/qqmldata_p.h | 10 | ||||
-rw-r--r-- | src/qml/qml/qqmlengine.cpp | 24 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator.cpp | 3 | ||||
-rw-r--r-- | src/qml/qml/qqmlobjectcreator_p.h | 2 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 35 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/data/nans.qml | 5 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 15 | ||||
-rw-r--r-- | tests/auto/quick/qquickwindow/tst_qquickwindow.cpp | 9 |
12 files changed, 126 insertions, 40 deletions
diff --git a/src/qml/doc/snippets/code/src_script_qjsengine.cpp b/src/qml/doc/snippets/code/src_script_qjsengine.cpp index 3799189f83..6c58fd8a18 100644 --- a/src/qml/doc/snippets/code/src_script_qjsengine.cpp +++ b/src/qml/doc/snippets/code/src_script_qjsengine.cpp @@ -114,3 +114,23 @@ engine.globalObject().setProperty("myObject", myScriptQObject); qDebug() << engine.evaluate("myObject.dynamicProperty").toInt(); //! [6] + + +//! [7] +class MyObject : public QObject +{ + Q_OBJECT + +public: + Q_INVOKABLE MyObject() {} +}; +//! [7] + +//! [8] +QJSValue jsMetaObject = engine.newQMetaObject(&MyObject::staticMetaObject); +engine.globalObject().setProperty("MyObject", jsMetaObject); +//! [8] + +//! [9] +engine.evaluate("var myObject = new MyObject()"); +//! [9] diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index d5b8b295a7..6cab8def4f 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -166,16 +166,30 @@ Q_DECLARE_METATYPE(QList<int>) properties of the proxy object. No binding code is needed because it is done dynamically using the Qt meta object system. + \snippet code/src_script_qjsengine.cpp 5 + Use newQMetaObject() to wrap a QMetaObject; this gives you a "script representation" of a QObject-based class. newQMetaObject() returns a proxy script object; enum values of the class are available as properties of the proxy object. - Constructors exposed to the meta-object system ( using Q_INVOKABLE ) can be + Constructors exposed to the meta-object system (using Q_INVOKABLE) can be called from the script to create a new QObject instance with - JavaScriptOwnership. + JavaScriptOwnership. For example, given the following class definition: - \snippet code/src_script_qjsengine.cpp 5 + \snippet code/src_script_qjsengine.cpp 7 + + The \c staticMetaObject for the class can be exposed to JavaScript like so: + + \snippet code/src_script_qjsengine.cpp 8 + + Instances of the class can then be created in JavaScript: + + \snippet code/src_script_qjsengine.cpp 9 + + \note Currently only classes using the Q_OBJECT macro are supported; it is + not possible to expose the \c staticMetaObject of a Q_GADGET class to + JavaScript. \section2 Dynamic QObject Properties @@ -537,7 +551,7 @@ QJSValue QJSEngine::newQObject(QObject *object) When called as a constructor, a new instance of the class will be created. Only constructors exposed by Q_INVOKABLE will be visible from the script engine. - \sa newQObject() + \sa newQObject(), {QObject Integration} */ QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) { @@ -554,7 +568,7 @@ QJSValue QJSEngine::newQMetaObject(const QMetaObject* metaObject) { Creates a JavaScript object that wraps the static QMetaObject associated with class \c{T}. - \sa newQObject() + \sa newQObject(), {QObject Integration} */ diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 50cecb6598..1158b82318 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -56,6 +56,8 @@ #include "qv4global_p.h" #include <private/qv4heap_p.h> +#include <private/qnumeric_p.h> + #if QT_POINTER_SIZE == 8 #define QV4_USE_64_BIT_VALUE_ENCODING #endif @@ -362,6 +364,8 @@ public: return d; } QML_NEARLY_ALWAYS_INLINE void setDouble(double d) { + if (qt_is_nan(d)) + d = qt_qnan(); memcpy(&_val, &d, 8); #ifdef QV4_USE_64_BIT_VALUE_ENCODING _val ^= NaNEncodeMask; diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 27b3c756c5..d420572606 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -400,6 +400,9 @@ bool Chunk::sweep(ExecutionEngine *engine) v->destroy(b); b->_checkIsDestroyed(); } +#ifdef V4_USE_HEAPTRACK + heaptrack_report_free(itemToFree); +#endif } Q_V4_PROFILE_DEALLOC(engine, qPopulationCount((objectBitmap[i] | extendsBitmap[i]) - (blackBitmap[i] | e)) * Chunk::SlotSize, @@ -448,6 +451,9 @@ void Chunk::freeAll(ExecutionEngine *engine) b->vtable()->destroy(b); b->_checkIsDestroyed(); } +#ifdef V4_USE_HEAPTRACK + heaptrack_report_free(itemToFree); +#endif } Q_V4_PROFILE_DEALLOC(engine, (qPopulationCount(objectBitmap[i]|extendsBitmap[i]) - qPopulationCount(e)) * Chunk::SlotSize, Profiling::SmallItem); @@ -705,6 +711,9 @@ HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) { done: m->setAllocatedSlots(slotsRequired); Q_V4_PROFILE_ALLOC(engine, slotsRequired * Chunk::SlotSize, Profiling::SmallItem); +#ifdef V4_USE_HEAPTRACK + heaptrack_report_alloc(m, slotsRequired * Chunk::SlotSize); +#endif // DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase()); return m; } @@ -762,6 +771,9 @@ HeapItem *HugeItemAllocator::allocate(size_t size) { chunks.push_back(HugeChunk{c, size}); Chunk::setBit(c->objectBitmap, c->first() - c->realBase()); Q_V4_PROFILE_ALLOC(engine, size, Profiling::LargeItem); +#ifdef V4_USE_HEAPTRACK + heaptrack_report_alloc(c, size); +#endif return c->first(); } @@ -778,6 +790,9 @@ static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocato b->_checkIsDestroyed(); } chunkAllocator->free(c.chunk, c.size); +#ifdef V4_USE_HEAPTRACK + heaptrack_report_free(c.chunk); +#endif } void HugeItemAllocator::sweep(ClassDestroyStatsCallback classCountPtr) diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index 5794e6f0c5..17d145f939 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -56,6 +56,7 @@ #include <private/qqmlpropertyindex_p.h> #include <private/qv4value_p.h> #include <private/qv4persistent_p.h> +#include <private/qqmlrefcount_p.h> #include <qjsengine.h> #include <qvector.h> @@ -116,6 +117,7 @@ class Q_QML_PRIVATE_EXPORT QQmlData : public QAbstractDeclarativeData { public: QQmlData(); + ~QQmlData(); static inline void init() { static bool initialized = false; @@ -219,12 +221,15 @@ public: quint32 jsEngineId; // id of the engine that created the jsWrapper struct DeferredData { + DeferredData(); + ~DeferredData(); unsigned int deferredIdx; QMultiHash<int, const QV4::CompiledData::Binding *> bindings; - QV4::CompiledData::CompilationUnit *compilationUnit;//Not always the same as the other compilation unit + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;//Not always the same as the other compilation unit QQmlContextData *context;//Could be either context or outerContext + Q_DISABLE_COPY(DeferredData); }; - QV4::CompiledData::CompilationUnit *compilationUnit; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; QVector<DeferredData *> deferredData; void deferData(int objectIndex, QV4::CompiledData::CompilationUnit *, QQmlContextData *); @@ -299,6 +304,7 @@ private: const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits; return bits[offset] & bitFlagForBit(bit); } + Q_DISABLE_COPY(QQmlData); }; bool QQmlData::wasDeleted(const QObject *object) diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index d53c94e901..8e3b0a790f 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -752,13 +752,17 @@ QQmlData::QQmlData() hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false), bindingBitsArraySize(InlineBindingArraySize), notifyList(0), bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), - lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), + lineNumber(0), columnNumber(0), jsEngineId(0), propertyCache(0), guards(0), extendedData(0) { memset(bindingBitsValue, 0, sizeof(bindingBitsValue)); init(); } +QQmlData::~QQmlData() +{ +} + void QQmlData::destroyed(QAbstractDeclarativeData *d, QObject *o) { QQmlData *ddata = static_cast<QQmlData *>(d); @@ -930,6 +934,14 @@ void QQmlData::flushPendingBindingImpl(QQmlPropertyIndex index) QQmlPropertyData::DontRemoveBinding); } +QQmlData::DeferredData::DeferredData() +{ +} + +QQmlData::DeferredData::~DeferredData() +{ +} + bool QQmlEnginePrivate::baseModulesUninitialized = true; void QQmlEnginePrivate::init() { @@ -1684,7 +1696,6 @@ void QQmlData::deferData(int objectIndex, QV4::CompiledData::CompilationUnit *co QQmlData::DeferredData *deferData = new QQmlData::DeferredData; deferData->deferredIdx = objectIndex; deferData->compilationUnit = compilationUnit; - deferData->compilationUnit->addref(); deferData->context = context; const QV4::CompiledData::Object *compiledObject = compilationUnit->objectAt(objectIndex); @@ -1706,7 +1717,6 @@ void QQmlData::releaseDeferredData() while (it != deferredData.end()) { DeferredData *deferData = *it; if (deferData->bindings.isEmpty()) { - deferData->compilationUnit->release(); delete deferData; it = deferredData.erase(it); } else { @@ -1784,12 +1794,10 @@ void QQmlData::destroyed(QObject *object) if (bindings && !bindings->ref.deref()) delete bindings; - if (compilationUnit) { - compilationUnit->release(); - compilationUnit = 0; - } + compilationUnit = nullptr; - releaseDeferredData(); + qDeleteAll(deferredData); + deferredData.clear(); QQmlBoundSignal *signalHandler = signalHandlers; while (signalHandler) { diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 7caab2a5d3..9114fbb83a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -203,10 +203,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI if (instance) { QQmlData *ddata = QQmlData::get(instance); Q_ASSERT(ddata); - if (ddata->compilationUnit) - ddata->compilationUnit->release(); ddata->compilationUnit = compilationUnit; - ddata->compilationUnit->addref(); } if (topLevelCreator) diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index f4c03af5b7..bef58b8c9a 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -137,7 +137,7 @@ private: QQmlEngine *engine; QV4::ExecutionEngine *v4; - QV4::CompiledData::CompilationUnit *compilationUnit; + QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; const QV4::CompiledData::Unit *qmlUnit; QQmlGuardedContextData parentContext; QQmlContextData *context; diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 067e9fc762..78c4a179ce 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -143,7 +143,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame); QSGMaterialShader *s = material->createShader(); - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); QOpenGLShaderProgram *p = s->program(); @@ -2031,7 +2031,7 @@ Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip) int vboSize = 0; bool useVBO = false; - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = m_context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); if (!ctx->isOpenGLES() && profile == QSurfaceFormat::CoreProfile) { @@ -2493,18 +2493,21 @@ void Renderer::updateLineWidth(QSGGeometry *g) if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES) glLineWidth(g->lineWidth()); #if !defined(QT_OPENGL_ES_2) - else if (!QOpenGLContext::currentContext()->isOpenGLES() && g->drawingMode() == GL_POINTS) { - QOpenGLFunctions_1_0 *gl1funcs = 0; - QOpenGLFunctions_3_2_Core *gl3funcs = 0; - if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) - gl3funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); - else - gl1funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_1_0>(); - Q_ASSERT(gl1funcs || gl3funcs); - if (gl1funcs) - gl1funcs->glPointSize(g->lineWidth()); - else - gl3funcs->glPointSize(g->lineWidth()); + else { + QOpenGLContext *ctx = m_context->openglContext(); + if (!ctx->isOpenGLES() && g->drawingMode() == GL_POINTS) { + QOpenGLFunctions_1_0 *gl1funcs = 0; + QOpenGLFunctions_3_2_Core *gl3funcs = 0; + if (ctx->format().profile() == QSurfaceFormat::CoreProfile) + gl3funcs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>(); + else + gl1funcs = ctx->versionFunctions<QOpenGLFunctions_1_0>(); + Q_ASSERT(gl1funcs || gl3funcs); + if (gl1funcs) + gl1funcs->glPointSize(g->lineWidth()); + else + gl3funcs->glPointSize(g->lineWidth()); + } } #endif } @@ -2610,6 +2613,8 @@ void Renderer::deleteRemovedElements() void Renderer::render() { + Q_ASSERT(m_context->openglContext() == QOpenGLContext::currentContext()); + if (Q_UNLIKELY(debug_dump())) { qDebug("\n"); QSGNodeDumper::dump(rootNode()); @@ -3152,7 +3157,7 @@ void Renderer::visualizeOverdraw() visualizeOverdraw_helper(m_nodes.value(rootNode())); // Animate the view... - QSurface *surface = QOpenGLContext::currentContext()->surface(); + QSurface *surface = m_context->openglContext()->surface(); if (surface->surfaceClass() == QSurface::Window) if (QQuickWindow *window = qobject_cast<QQuickWindow *>(static_cast<QWindow *>(surface))) window->update(); diff --git a/tests/auto/qml/qqmlecmascript/data/nans.qml b/tests/auto/qml/qqmlecmascript/data/nans.qml new file mode 100644 index 0000000000..ece69f2d79 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/nans.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property var prop: undefined +} diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index c662fdfb8b..2cb5db2cef 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -342,6 +342,7 @@ private slots: void freeze_empty_object(); void singleBlockLoops(); void qtbug_60547(); + void anotherNaN(); private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); @@ -8374,6 +8375,20 @@ void tst_qqmlecmascript::qtbug_60547() QCOMPARE(object->property("counter"), QVariant(int(1))); } +void tst_qqmlecmascript::anotherNaN() +{ + QQmlComponent component(&engine, testFileUrl("nans.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY2(!object.isNull(), qPrintable(component.errorString())); + object->setProperty("prop", std::numeric_limits<double>::quiet_NaN()); // don't crash + + std::uint64_t anotherNaN = 0xFFFFFF01000000F7ul; + double d; + std::memcpy(&d, &anotherNaN, sizeof(d)); + QVERIFY(std::isnan(d)); + object->setProperty("prop", d); // don't crash +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index 5c87daaed6..a968d4179b 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -771,9 +771,8 @@ void tst_qquickwindow::touchEvent_propagation() // single touch to top item, should be received by middle item QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window); - QTest::qWait(50); + QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 1); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(middleItem->lastEvent.touchPoints.count(), 1); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos)))); @@ -782,9 +781,8 @@ void tst_qquickwindow::touchEvent_propagation() // touch top and middle items, middle item should get both events QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) .press(1, pointInMiddleItem, window); - QTest::qWait(50); + QTRY_COMPARE(middleItem->lastEvent.touchPoints.count(), 2); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(middleItem->lastEvent.touchPoints.count(), 2); QVERIFY(bottomItem->lastEvent.touchPoints.isEmpty()); COMPARE_TOUCH_DATA(middleItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(middleItem, middleItem->mapFromItem(topItem, pos)) @@ -802,10 +800,9 @@ void tst_qquickwindow::touchEvent_propagation() // touch top and middle items, bottom item should get all events QTest::touchEvent(window, touchDevice).press(0, pointInTopItem, window) .press(1, pointInMiddleItem, window); - QTest::qWait(50); + QTRY_COMPARE(bottomItem->lastEvent.touchPoints.count(), 2); QVERIFY(topItem->lastEvent.touchPoints.isEmpty()); QVERIFY(middleItem->lastEvent.touchPoints.isEmpty()); - QCOMPARE(bottomItem->lastEvent.touchPoints.count(), 2); COMPARE_TOUCH_DATA(bottomItem->lastEvent, makeTouchData(QEvent::TouchBegin, window, Qt::TouchPointPressed, (QList<QTouchEvent::TouchPoint>() << makeTouchPoint(bottomItem, bottomItem->mapFromItem(topItem, pos)) << makeTouchPoint(bottomItem, bottomItem->mapFromItem(middleItem, pos)) ))); |