Merge remote-tracking branch 'origin/5.9' into 5.10

Change-Id: I3b250545e334f50dcef1a75acdef51820d34079a
This commit is contained in:
Liang Qi 2018-02-07 11:03:01 +01:00
commit 3e3c6717ba
12 changed files with 126 additions and 40 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,5 @@
import QtQuick 2.0
QtObject {
property var prop: undefined
}

View File

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

View File

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