Merge remote-tracking branch 'origin/5.9' into 5.10
Change-Id: I3b250545e334f50dcef1a75acdef51820d34079a
This commit is contained in:
		
						commit
						3e3c6717ba
					
				|  | @ -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]
 | ||||
|  |  | |||
|  | @ -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} | ||||
| */ | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
|  | @ -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) | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -0,0 +1,5 @@ | |||
| import QtQuick 2.0 | ||||
| 
 | ||||
| QtObject { | ||||
|     property var prop: undefined | ||||
| } | ||||
|  | @ -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" | ||||
|  |  | |||
|  | @ -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)) ))); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue