diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-04-06 09:12:42 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-04-06 09:13:13 +0200 |
commit | 0e90e0d2c385d8928d188314ed16d70050b362eb (patch) | |
tree | 26a55cc9382b9dd0c047aedd529cac248088d492 /src | |
parent | 68af8842f5f580dab140f397cfd5683ebdc368cf (diff) | |
parent | 60da655dff4ffcc94d32a05bb5fa32240b0eaa0b (diff) |
Merge remote-tracking branch 'origin/dev' into wip/scenegraphng
Change-Id: Id98d3514e602a3c8c159a27be7b2fd24d7d290ae
Diffstat (limited to 'src')
115 files changed, 1855 insertions, 1433 deletions
diff --git a/src/3rdparty/masm/stubs/ExecutableAllocator.h b/src/3rdparty/masm/stubs/ExecutableAllocator.h index fe8fc66b03..5a3939b7b2 100644 --- a/src/3rdparty/masm/stubs/ExecutableAllocator.h +++ b/src/3rdparty/masm/stubs/ExecutableAllocator.h @@ -57,6 +57,10 @@ #include <unistd.h> #endif +#ifdef __QNXNTO__ +using std::perror; +#endif + namespace JSC { class JSGlobalData; diff --git a/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h b/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h index 21436b0bec..0e18132f77 100644 --- a/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h +++ b/src/3rdparty/masm/stubs/wtf/PassOwnPtr.h @@ -101,8 +101,8 @@ public: private: template <typename PtrType> friend PassOwnPtr<PtrType> adoptPtr(PtrType*); - PassOwnPtr<T>& operator=(const PassOwnPtr<T>&) - {} + PassOwnPtr<T>& operator=(const PassOwnPtr<T>& t); + mutable QScopedPointer<T> m_ptr; }; diff --git a/src/3rdparty/masm/stubs/wtf/PassRefPtr.h b/src/3rdparty/masm/stubs/wtf/PassRefPtr.h index 1a837464fa..f072e70dd7 100644 --- a/src/3rdparty/masm/stubs/wtf/PassRefPtr.h +++ b/src/3rdparty/masm/stubs/wtf/PassRefPtr.h @@ -81,8 +81,7 @@ public: } private: - PassRefPtr<T>& operator=(const PassRefPtr<T>&) - {} + PassRefPtr<T>& operator=(const PassRefPtr<T>& t); template <typename PtrType> friend PassRefPtr<PtrType> adoptRef(PtrType*); mutable T* m_ptr; diff --git a/src/imports/testlib/SignalSpy.qml b/src/imports/testlib/SignalSpy.qml index 7288c57ea0..200fc725f7 100644 --- a/src/imports/testlib/SignalSpy.qml +++ b/src/imports/testlib/SignalSpy.qml @@ -222,14 +222,16 @@ Item { /*! \internal */ function qtest_update() { if (qtest_prevTarget != null) { - var prevFunc = qtest_prevTarget[qtest_prevSignalName] + var prevHandlerName = qtest_signalHandlerName(qtest_prevSignalName) + var prevFunc = qtest_prevTarget[prevHandlerName] if (prevFunc) prevFunc.disconnect(spy.qtest_activated) qtest_prevTarget = null qtest_prevSignalName = "" } if (target != null && signalName != "") { - var func = target[signalName] + var handlerName = qtest_signalHandlerName(signalName) + var func = target[handlerName] if (func === undefined) { spy.qtest_valid = false console.log("Signal '" + signalName + "' not found") @@ -250,4 +252,11 @@ Item { ++qtest_count spy.qtest_signalArguments[spy.qtest_signalArguments.length] = arguments } + + /*! \internal */ + function qtest_signalHandlerName(sn) { + if (sn.substr(0, 2) === "on" && sn[2] === sn[2].toUpperCase()) + return sn + return "on" + sn.substr(0, 1).toUpperCase() + sn.substr(1) + } } diff --git a/src/particles/qquickage.cpp b/src/particles/qquickage.cpp index 9867e7e0ed..578207531d 100644 --- a/src/particles/qquickage.cpp +++ b/src/particles/qquickage.cpp @@ -88,23 +88,23 @@ QQuickAgeAffector::QQuickAgeAffector(QQuickItem *parent) : bool QQuickAgeAffector::affectParticle(QQuickParticleData *d, qreal dt) { Q_UNUSED(dt); - if (d->stillAlive()){ - qreal curT = (qreal)m_system->timeInt/1000.0; - qreal ttl = (qreal)m_lifeLeft/1000.0; + if (d->stillAlive(m_system)){ + float curT = m_system->timeInt / 1000.0f; + float ttl = m_lifeLeft / 1000.0f; if (!m_advancePosition && ttl > 0){ - qreal x = d->curX(); - qreal vx = d->curVX(); - qreal ax = d->curAX(); - qreal y = d->curY(); - qreal vy = d->curVY(); - qreal ay = d->curAY(); + float x = d->curX(m_system); + float vx = d->curVX(m_system); + float ax = d->curAX(); + float y = d->curY(m_system); + float vy = d->curVY(m_system); + float ay = d->curAY(); d->t = curT - (d->lifeSpan - ttl); - d->setInstantaneousX(x); - d->setInstantaneousVX(vx); - d->setInstantaneousAX(ax); - d->setInstantaneousY(y); - d->setInstantaneousVY(vy); - d->setInstantaneousAY(ay); + d->setInstantaneousX(x, m_system); + d->setInstantaneousVX(vx, m_system); + d->setInstantaneousAX(ax, m_system); + d->setInstantaneousY(y, m_system); + d->setInstantaneousVY(vy, m_system); + d->setInstantaneousAY(ay, m_system); } else { d->t = curT - (d->lifeSpan - ttl); } diff --git a/src/particles/qquickcustomaffector.cpp b/src/particles/qquickcustomaffector.cpp index 55310f92d5..b95810bb62 100644 --- a/src/particles/qquickcustomaffector.cpp +++ b/src/particles/qquickcustomaffector.cpp @@ -122,11 +122,15 @@ void QQuickCustomAffector::affectSystem(qreal dt) updateOffsets(); QList<QQuickParticleData*> toAffect; - foreach (QQuickParticleGroupData* gd, m_system->groupData) - if (activeGroup(m_system->groupData.key(gd))) - foreach (QQuickParticleData* d, gd->data) - if (shouldAffect(d)) + foreach (QQuickParticleGroupData* gd, m_system->groupData) { + if (activeGroup(gd->index)) { + foreach (QQuickParticleData* d, gd->data) { + if (shouldAffect(d)) { toAffect << d; + } + } + } + } if (toAffect.isEmpty()) return; @@ -134,8 +138,8 @@ void QQuickCustomAffector::affectSystem(qreal dt) if (justAffected) { foreach (QQuickParticleData* d, toAffect) {//Not postAffect to avoid saying the particle changed if (m_onceOff) - m_onceOffed << qMakePair(d->group, d->index); - emit affected(d->curX(), d->curY()); + m_onceOffed << qMakePair(d->groupId, d->index); + emit affected(d->curX(m_system), d->curY(m_system)); } return; } @@ -150,7 +154,7 @@ void QQuickCustomAffector::affectSystem(qreal dt) QV4::ScopedArrayObject array(scope, v4->newArrayObject(toAffect.size())); QV4::ScopedValue v(scope); for (int i=0; i<toAffect.size(); i++) - array->putIndexed(i, (v = toAffect[i]->v4Value())); + array->putIndexed(i, (v = toAffect[i]->v4Value(m_system))); if (dt >= simulationCutoff || dt <= simulationDelta) { affectProperties(toAffect, dt); @@ -180,7 +184,7 @@ bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt) { //This does the property based affecting, called by superclass if signal isn't hooked up. bool changed = false; - QPointF curPos(d->curX(), d->curY()); + QPointF curPos(d->curX(m_system), d->curY(m_system)); if (m_acceleration != &m_nullVector){ QPointF pos = m_acceleration->sample(curPos); @@ -190,22 +194,22 @@ bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt) pos += curAcc; } if (pos != curAcc) { - d->setInstantaneousAX(pos.x()); - d->setInstantaneousAY(pos.y()); + d->setInstantaneousAX(pos.x(), m_system); + d->setInstantaneousAY(pos.y(), m_system); changed = true; } } if (m_velocity != &m_nullVector){ QPointF pos = m_velocity->sample(curPos); - QPointF curVel = QPointF(d->curVX(), d->curVY()); + QPointF curVel = QPointF(d->curVX(m_system), d->curVY(m_system)); if (m_relative) { pos *= dt; pos += curVel; } if (pos != curVel) { - d->setInstantaneousVX(pos.x()); - d->setInstantaneousVY(pos.y()); + d->setInstantaneousVX(pos.x(), m_system); + d->setInstantaneousVY(pos.y(), m_system); changed = true; } } @@ -217,8 +221,8 @@ bool QQuickCustomAffector::affectParticle(QQuickParticleData *d, qreal dt) pos += curPos; } if (pos != curPos) { - d->setInstantaneousX(pos.x()); - d->setInstantaneousY(pos.y()); + d->setInstantaneousX(pos.x(), m_system); + d->setInstantaneousY(pos.y(), m_system); changed = true; } } diff --git a/src/particles/qquickcustomparticle.cpp b/src/particles/qquickcustomparticle.cpp index 97cfdc7bf9..32b2fd847e 100644 --- a/src/particles/qquickcustomparticle.cpp +++ b/src/particles/qquickcustomparticle.cpp @@ -324,19 +324,18 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes() return 0; } - if (m_groups.isEmpty()) + if (groups().isEmpty()) return 0; QQuickShaderEffectNode *rootNode = 0; QQuickShaderEffectMaterial *material = new QQuickShaderEffectMaterial; m_dirtyProgram = true; - foreach (const QString &str, m_groups){ - int gIdx = m_system->groupIds[str]; - int count = m_system->groupData[gIdx]->size(); + for (auto groupId : groupIds()) { + int count = m_system->groupData[groupId]->size(); QQuickShaderEffectNode* node = new QQuickShaderEffectNode(); - m_nodes.insert(gIdx, node); + m_nodes.insert(groupId, node); node->setMaterial(material); @@ -349,7 +348,7 @@ QQuickShaderEffectNode* QQuickCustomParticle::buildCustomNodes() node->setFlag(QSGNode::OwnsGeometry, true); PlainVertex *vertices = (PlainVertex *) g->vertexData(); for (int p=0; p < count; ++p) { - commit(gIdx, p); + commit(groupId, p); vertices[0].tx = 0; vertices[0].ty = 0; diff --git a/src/particles/qquickfriction.cpp b/src/particles/qquickfriction.cpp index f234bc27ad..401f4cd8c9 100644 --- a/src/particles/qquickfriction.cpp +++ b/src/particles/qquickfriction.cpp @@ -80,8 +80,8 @@ bool QQuickFrictionAffector::affectParticle(QQuickParticleData *d, qreal dt) { if (!m_factor) return false; - qreal curVX = d->curVX(); - qreal curVY = d->curVY(); + qreal curVX = d->curVX(m_system); + qreal curVY = d->curVY(m_system); if (!curVX && !curVY) return false; qreal newVX = curVX + (curVX * m_factor * -1 * dt); @@ -106,8 +106,8 @@ bool QQuickFrictionAffector::affectParticle(QQuickParticleData *d, qreal dt) } } - d->setInstantaneousVX(newVX); - d->setInstantaneousVY(newVY); + d->setInstantaneousVX(newVX, m_system); + d->setInstantaneousVY(newVY, m_system); return true; } QT_END_NAMESPACE diff --git a/src/particles/qquickgravity.cpp b/src/particles/qquickgravity.cpp index 54a03ac4bd..90f305f336 100644 --- a/src/particles/qquickgravity.cpp +++ b/src/particles/qquickgravity.cpp @@ -90,8 +90,8 @@ bool QQuickGravityAffector::affectParticle(QQuickParticleData *d, qreal dt) m_dy = m_magnitude * std::sin(m_angle * CONV); } - d->setInstantaneousVX(d->curVX() + m_dx*dt); - d->setInstantaneousVY(d->curVY() + m_dy*dt); + d->setInstantaneousVX(d->curVX(m_system) + m_dx*dt, m_system); + d->setInstantaneousVY(d->curVY(m_system) + m_dy*dt, m_system); return true; } QT_END_NAMESPACE diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index c88a0b002b..07cbee1383 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1020,10 +1020,13 @@ void QQuickImageParticle::setEntryEffect(EntryEffect arg) void QQuickImageParticle::resetColor() { m_explicitColor = false; - foreach (const QString &str, m_groups) - foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data) - if (d->colorOwner == this) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (d->colorOwner == this) { d->colorOwner = 0; + } + } + } m_color = QColor(); m_color_variation = 0.0f; m_redVariation = 0.0f; @@ -1036,10 +1039,13 @@ void QQuickImageParticle::resetColor() void QQuickImageParticle::resetRotation() { m_explicitRotation = false; - foreach (const QString &str, m_groups) - foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data) - if (d->rotationOwner == this) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (d->rotationOwner == this) { d->rotationOwner = 0; + } + } + } m_rotation = 0; m_rotationVariation = 0; m_rotationVelocity = 0; @@ -1050,10 +1056,13 @@ void QQuickImageParticle::resetRotation() void QQuickImageParticle::resetDeformation() { m_explicitDeformation = false; - foreach (const QString &str, m_groups) - foreach (QQuickParticleData* d, m_system->groupData[m_system->groupIds[str]]->data) - if (d->deformationOwner == this) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (d->deformationOwner == this) { d->deformationOwner = 0; + } + } + } if (m_xVector) delete m_xVector; if (m_yVector) @@ -1159,21 +1168,21 @@ QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datu //Will return datum if the datum is a sentinel or uninitialized, to centralize that one check if (datum->systemIndex == -1) return datum; - QQuickParticleGroupData* gd = m_system->groupData[datum->group]; - if (!m_shadowData.contains(datum->group)) { + QQuickParticleGroupData* gd = m_system->groupData[datum->groupId]; + if (!m_shadowData.contains(datum->groupId)) { QVector<QQuickParticleData*> data; const int gdSize = gd->size(); data.reserve(gdSize); for (int i = 0; i < gdSize; i++) { - QQuickParticleData* datum = new QQuickParticleData(m_system); + QQuickParticleData* datum = new QQuickParticleData; *datum = *(gd->data[i]); data << datum; } - m_shadowData.insert(datum->group, data); + m_shadowData.insert(datum->groupId, data); } //### If dynamic resize is added, remember to potentially resize the shadow data on out-of-bounds access request - return m_shadowData[datum->group][datum->index]; + return m_shadowData[datum->groupId][datum->index]; } bool QQuickImageParticle::loadingSomething() @@ -1255,9 +1264,9 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) perfLevel = Simple; } - foreach (const QString &str, m_groups){//For sharing higher levels, need to have highest used so it renders - int gIdx = m_system->groupIds[str]; - foreach (QQuickParticlePainter* p, m_system->groupData[gIdx]->painters){ + for (auto groupId : groupIds()) { + //For sharing higher levels, need to have highest used so it renders + for (QQuickParticlePainter* p : qAsConst(m_system->groupData[groupId]->painters)) { QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p); if (other){ if (other->perfLevel > perfLevel) { @@ -1382,16 +1391,15 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) } m_nodes.clear(); - foreach (const QString &str, m_groups){ - int gIdx = m_system->groupIds[str]; - int count = m_system->groupData[gIdx]->size(); + for (auto groupId : groupIds()) { + int count = m_system->groupData[groupId]->size(); QSGGeometryNode* node = new QSGGeometryNode(); node->setMaterial(m_material); node->markDirty(QSGNode::DirtyMaterial); - m_nodes.insert(gIdx, node); - m_idxStarts.insert(gIdx, m_lastIdxStart); - m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, gIdx)); + m_nodes.insert(groupId, node); + m_idxStarts.insert(groupId, m_lastIdxStart); + m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, groupId)); m_lastIdxStart += count; //Create Particle Geometry @@ -1423,7 +1431,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) g->setDrawingMode(GL_TRIANGLES); for (int p=0; p < count; ++p) - commit(gIdx, p);//commit sets geometry for the node, has its own perfLevel switch + commit(groupId, p);//commit sets geometry for the node, has its own perfLevel switch if (perfLevel == Sprites) initTexCoords<SpriteVertex>((SpriteVertex*)g->vertexData(), vCount); @@ -1538,10 +1546,9 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) void QQuickImageParticle::spritesUpdate(qreal time) { // Sprite progression handled CPU side, so as to have per-frame control. - foreach (const QString &str, m_groups) { - int gIdx = m_system->groupIds[str]; - foreach (QQuickParticleData* mainDatum, m_system->groupData[gIdx]->data) { - QSGGeometryNode *node = m_nodes[gIdx]; + for (auto groupId : groupIds()) { + for (QQuickParticleData* mainDatum : qAsConst(m_system->groupData[groupId]->data)) { + QSGGeometryNode *node = m_nodes[groupId]; if (!node) continue; //TODO: Interpolate between two different animations if it's going to transition next frame @@ -1549,7 +1556,7 @@ void QQuickImageParticle::spritesUpdate(qreal time) QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum)); int spriteIdx = 0; for (int i = 0; i<m_startsIdx.count(); i++) { - if (m_startsIdx[i].second == gIdx){ + if (m_startsIdx[i].second == groupId){ spriteIdx = m_startsIdx[i].first + datum->index; break; } diff --git a/src/particles/qquickitemparticle.cpp b/src/particles/qquickitemparticle.cpp index 86dc04ea5a..15cf19181e 100644 --- a/src/particles/qquickitemparticle.cpp +++ b/src/particles/qquickitemparticle.cpp @@ -206,8 +206,8 @@ void QQuickItemParticle::tick(int time) m_managed << d->delegate; } if (d && d->delegate){//###Data can be zero if creating an item leads to a reset - this screws things up. - d->delegate->setX(d->curX() - d->delegate->width()/2);//TODO: adjust for system? - d->delegate->setY(d->curY() - d->delegate->height()/2); + d->delegate->setX(d->curX(m_system) - d->delegate->width() / 2); //TODO: adjust for system? + d->delegate->setY(d->curY(m_system) - d->delegate->height() / 2); QQuickItemParticleAttached* mpa = qobject_cast<QQuickItemParticleAttached*>(qmlAttachedPropertiesObject<QQuickItemParticle>(d->delegate)); if (mpa){ mpa->m_mp = this; @@ -231,10 +231,10 @@ void QQuickItemParticle::reset() // delete all managed items which had their logical particles cleared // but leave it alone if the logical particle is maintained QSet<QQuickItem*> lost = QSet<QQuickItem*>::fromList(m_managed); - foreach (const QString group, m_groups){ - int gIdx = m_system->groupIds[group]; - foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data) - lost.remove(d->delegate); + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + lost.remove(d->delegate); + } } m_deletables.append(lost.toList()); //TODO: This doesn't yet handle calling detach on taken particles in the system reset case @@ -249,11 +249,12 @@ QSGNode* QQuickItemParticle::updatePaintNode(QSGNode* n, UpdatePaintNodeData* d) m_pleaseReset = false; //Refill loadables, delayed here so as to only happen once per frame max //### Constant resetting might lead to m_loadables never being populated when tick() occurs - foreach (const QString group, m_groups){ - int gIdx = m_system->groupIds[group]; - foreach (QQuickParticleData* d, m_system->groupData[gIdx]->data) - if (!d->delegate && d->t != -1 && d->stillAlive()) + for (auto groupId : groupIds()) { + for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + if (!d->delegate && d->t != -1 && d->stillAlive(m_system)) { m_loadables << d; + } + } } } prepareNextFrame(); @@ -276,37 +277,32 @@ void QQuickItemParticle::prepareNextFrame() return; //TODO: Size, better fade? - foreach (const QString &str, m_groups){ - const int gIdx = m_system->groupIds[str]; - const QVector<QQuickParticleData*> dataVector = m_system->groupData.value(gIdx)->data; - const int count = dataVector.size(); - - for (int i=0; i<count; i++){ - QQuickParticleData* data = dataVector.at(i); + for (auto groupId : groupIds()) { + for (QQuickParticleData* data : qAsConst(m_system->groupData[groupId]->data)) { QQuickItem* item = data->delegate; if (!item) continue; - qreal t = ((timeStamp/1000.0) - data->t) / data->lifeSpan; + float t = ((timeStamp / 1000.0f) - data->t) / data->lifeSpan; if (m_stasis.contains(item)) { data->t += dt;//Stasis effect continue; } - if (t >= 1.0){//Usually happens from load + if (t >= 1.0f){//Usually happens from load m_deletables << item; data->delegate = 0; }else{//Fade data->delegate->setVisible(true); if (m_fade){ - qreal o = 1.; - if (t<0.2) - o = t*5; - if (t>0.8) + float o = 1.f; + if (t <0.2f) + o = t * 5; + if (t > 0.8f) o = (1-t)*5; item->setOpacity(o); } } - item->setX(data->curX() - item->width()/2 - m_systemOffset.x()); - item->setY(data->curY() - item->height()/2 - m_systemOffset.y()); + item->setX(data->curX(m_system) - item->width() / 2 - m_systemOffset.x()); + item->setY(data->curY(m_system) - item->height() / 2 - m_systemOffset.y()); } } } diff --git a/src/particles/qquickparticleaffector.cpp b/src/particles/qquickparticleaffector.cpp index 139b0d9bbe..6ed0d9e14a 100644 --- a/src/particles/qquickparticleaffector.cpp +++ b/src/particles/qquickparticleaffector.cpp @@ -162,13 +162,13 @@ bool QQuickParticleAffector::shouldAffect(QQuickParticleData* d) { if (!d) return false; - if (activeGroup(d->group)){ - if ((m_onceOff && m_onceOffed.contains(qMakePair(d->group, d->index))) - || !d->stillAlive()) + if (activeGroup(d->groupId)){ + if ((m_onceOff && m_onceOffed.contains(qMakePair(d->groupId, d->index))) + || !d->stillAlive(m_system)) return false; //Need to have previous location for affected anyways if (width() == 0 || height() == 0 - || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()), QPointF(d->curX(), d->curY()))){ + || m_shape->contains(QRectF(m_offset.x(), m_offset.y(), width(), height()), QPointF(d->curX(m_system), d->curY(m_system)))){ if (m_whenCollidingWith.isEmpty() || isColliding(d)){ return true; } @@ -182,9 +182,9 @@ void QQuickParticleAffector::postAffect(QQuickParticleData* d) { m_system->needsReset << d; if (m_onceOff) - m_onceOffed << qMakePair(d->group, d->index); + m_onceOffed << qMakePair(d->groupId, d->index); if (isAffectedConnected()) - emit affected(d->curX(), d->curY()); + emit affected(d->curX(m_system), d->curY(m_system)); } const qreal QQuickParticleAffector::simulationDelta = 0.020; @@ -200,7 +200,7 @@ void QQuickParticleAffector::affectSystem(qreal dt) if (m_onceOff) dt = 1.0; foreach (QQuickParticleGroupData* gd, m_system->groupData) { - if (activeGroup(m_system->groupData.key(gd))) { + if (activeGroup(gd->index)) { foreach (QQuickParticleData* d, gd->data) { if (shouldAffect(d)) { bool affected = false; @@ -210,7 +210,7 @@ void QQuickParticleAffector::affectSystem(qreal dt) m_system->timeInt -= myDt * 1000.0; while (myDt > simulationDelta) { m_system->timeInt += simulationDelta * 1000.0; - if (d->alive())//Only affect during the parts it was alive for + if (d->alive(m_system))//Only affect during the parts it was alive for affected = affectParticle(d, simulationDelta) || affected; myDt -= simulationDelta; } @@ -234,8 +234,8 @@ bool QQuickParticleAffector::affectParticle(QQuickParticleData *, qreal ) void QQuickParticleAffector::reset(QQuickParticleData* pd) {//TODO: This, among other ones, should be restructured so they don't all need to remember to call the superclass if (m_onceOff) - if (activeGroup(pd->group)) - m_onceOffed.remove(qMakePair(pd->group, pd->index)); + if (activeGroup(pd->groupId)) + m_onceOffed.remove(qMakePair(pd->groupId, pd->index)); } void QQuickParticleAffector::updateOffsets() @@ -246,16 +246,16 @@ void QQuickParticleAffector::updateOffsets() bool QQuickParticleAffector::isColliding(QQuickParticleData *d) { - qreal myCurX = d->curX(); - qreal myCurY = d->curY(); - qreal myCurSize = d->curSize()/2; + qreal myCurX = d->curX(m_system); + qreal myCurY = d->curY(m_system); + qreal myCurSize = d->curSize(m_system) / 2; foreach (const QString &group, m_whenCollidingWith){ foreach (QQuickParticleData* other, m_system->groupData[m_system->groupIds[group]]->data){ - if (!other->stillAlive()) + if (!other->stillAlive(m_system)) continue; - qreal otherCurX = other->curX(); - qreal otherCurY = other->curY(); - qreal otherCurSize = other->curSize()/2; + qreal otherCurX = other->curX(m_system); + qreal otherCurY = other->curY(m_system); + qreal otherCurSize = other->curSize(m_system) / 2; if ((myCurX + myCurSize > otherCurX - otherCurSize && myCurX - myCurSize < otherCurX + otherCurSize) && (myCurY + myCurSize > otherCurY - otherCurSize diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp index 4d9f834492..6e116d450c 100644 --- a/src/particles/qquickparticleemitter.cpp +++ b/src/particles/qquickparticleemitter.cpp @@ -237,6 +237,8 @@ QQuickParticleEmitter::QQuickParticleEmitter(QQuickItem *parent) : , m_reset_last(true) , m_last_timestamp(-1) , m_last_emission(0) + , m_groupIdNeedRecalculation(false) + , m_groupId(QQuickParticleGroupData::DefaultGroupID) { //TODO: Reset velocity/acc back to null vector? Or allow null pointer? @@ -257,10 +259,22 @@ bool QQuickParticleEmitter::isEmitConnected() IS_SIGNAL_CONNECTED(this, QQuickParticleEmitter, emitParticles, (QQmlV4Handle)); } +void QQuickParticleEmitter::reclaculateGroupId() const +{ + if (!m_system) { + m_groupId = QQuickParticleGroupData::InvalidID; + return; + } + m_groupId = m_system->groupIds.value(group(), QQuickParticleGroupData::InvalidID); + m_groupIdNeedRecalculation = m_groupId == QQuickParticleGroupData::InvalidID; +} + void QQuickParticleEmitter::componentComplete() { if (!m_system && qobject_cast<QQuickParticleSystem*>(parentItem())) setSystem(qobject_cast<QQuickParticleSystem*>(parentItem())); + if (m_system) + m_system->finishRegisteringParticleEmitter(this); QQuickItem::componentComplete(); } @@ -319,13 +333,6 @@ void QQuickParticleEmitter::setMaxParticleCount(int arg) } } -int QQuickParticleEmitter::particleCount() const -{ - if (m_maxParticleCount >= 0) - return m_maxParticleCount; - return m_particlesPerSecond*((m_particleDuration+m_particleDurationVariation)/1000.0); -} - void QQuickParticleEmitter::setVelocityFromMovement(qreal t) { if (t == m_velocity_from_movement) @@ -402,7 +409,6 @@ void QQuickParticleEmitter::emitWindow(int timeStamp) //int pos = m_last_particle % m_particle_count; QQuickParticleData* datum = m_system->newDatum(m_system->groupIds[m_group], !m_overwrite); if (datum){//actually emit(otherwise we've been asked to skip this one) - datum->e = this;//###useful? qreal t = 1 - (pt - opt) / dt; qreal vx = - 2 * ax * (1 - t) @@ -475,7 +481,7 @@ void QQuickParticleEmitter::emitWindow(int timeStamp) } foreach (QQuickParticleData* d, toEmit) - m_system->emitParticle(d); + m_system->emitParticle(d, this); if (isEmitConnected()) { QQmlEngine *qmlEngine = ::qmlEngine(this); @@ -487,7 +493,7 @@ void QQuickParticleEmitter::emitWindow(int timeStamp) QV4::ScopedArrayObject array(scope, v4->newArrayObject(toEmit.size())); QV4::ScopedValue v(scope); for (int i=0; i<toEmit.size(); i++) - array->putIndexed(i, (v = toEmit[i]->v4Value())); + array->putIndexed(i, (v = toEmit[i]->v4Value(m_system))); emitParticles(QQmlV4Handle(array));//A chance for arbitrary JS changes } diff --git a/src/particles/qquickparticleemitter_p.h b/src/particles/qquickparticleemitter_p.h index e0036c4007..9b114ad46b 100644 --- a/src/particles/qquickparticleemitter_p.h +++ b/src/particles/qquickparticleemitter_p.h @@ -119,6 +119,13 @@ public: return m_group; } + QQuickParticleGroupData::ID groupId() const + { + if (m_groupIdNeedRecalculation) + reclaculateGroupId(); + return m_groupId; + } + int particleDurationVariation() const { return m_particleDurationVariation; @@ -185,6 +192,7 @@ public Q_SLOTS: { if (m_system != arg) { m_system = arg; + m_groupIdNeedRecalculation = true; if (m_system) m_system->registerParticleEmitter(this); Q_EMIT systemChanged(arg); @@ -195,6 +203,7 @@ public Q_SLOTS: { if (m_group != arg) { m_group = arg; + m_groupIdNeedRecalculation = true; Q_EMIT groupChanged(arg); } } @@ -266,7 +275,12 @@ public Q_SLOTS: virtual void reset(); public: - int particleCount() const; + int particleCount() const + { + if (m_maxParticleCount >= 0) + return m_maxParticleCount; + return m_particlesPerSecond*((m_particleDuration+m_particleDurationVariation)/1000.0); + } QQuickParticleExtruder* extruder() const { @@ -314,7 +328,6 @@ protected: int m_particleDurationVariation; bool m_enabled; QQuickParticleSystem* m_system; - QString m_group; QQuickParticleExtruder* m_extruder; QQuickParticleExtruder* m_defaultExtruder; QQuickParticleExtruder* effectiveExtruder(); @@ -345,7 +358,14 @@ protected: QPointF m_last_last_last_emitter; bool isEmitConnected(); -private: + +private: // methods + void reclaculateGroupId() const; + +private: // data + QString m_group; + mutable bool m_groupIdNeedRecalculation; + mutable QQuickParticleGroupData::ID m_groupId; QQuickDirection m_nullVector; }; diff --git a/src/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp index 134689713d..d6303eb219 100644 --- a/src/particles/qquickparticlepainter.cpp +++ b/src/particles/qquickparticlepainter.cpp @@ -64,9 +64,13 @@ QT_BEGIN_NAMESPACE If empty, it will paint the default particle group (""). */ -QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent) : - QQuickItem(parent), - m_system(0), m_count(0), m_pleaseReset(true), m_window(0) +QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent) + : QQuickItem(parent) + , m_system(0) + , m_count(0) + , m_pleaseReset(true) + , m_window(0) + , m_groupIdsNeedRecalculation(false) { } @@ -89,11 +93,32 @@ void QQuickParticlePainter::componentComplete() QQuickItem::componentComplete(); } +void QQuickParticlePainter::recalculateGroupIds() const +{ + if (!m_system) { + m_groupIds.clear(); + return; + } + + m_groupIdsNeedRecalculation = false; + m_groupIds.clear(); + + for (const QString &str : groups()) { + QQuickParticleGroupData::ID groupId = m_system->groupIds.value(str, QQuickParticleGroupData::InvalidID); + if (groupId == QQuickParticleGroupData::InvalidID) { + // invalid data, not finished setting up, or whatever. Fallback: do not cache. + m_groupIdsNeedRecalculation = true; + } else { + m_groupIds.append(groupId); + } + } +} void QQuickParticlePainter::setSystem(QQuickParticleSystem *arg) { if (m_system != arg) { m_system = arg; + m_groupIdsNeedRecalculation = true; if (m_system){ m_system->registerParticlePainter(this); reset(); @@ -102,19 +127,29 @@ void QQuickParticlePainter::setSystem(QQuickParticleSystem *arg) } } +void QQuickParticlePainter::setGroups(const QStringList &arg) +{ + if (m_groups != arg) { + m_groups = arg; + m_groupIdsNeedRecalculation = true; + //Note: The system watches this as it has to recalc things when groups change. It will request a reset if necessary + Q_EMIT groupsChanged(arg); + } +} + void QQuickParticlePainter::load(QQuickParticleData* d) { - initialize(d->group, d->index); + initialize(d->groupId, d->index); if (m_pleaseReset) return; - m_pendingCommits << qMakePair<int, int>(d->group, d->index); + m_pendingCommits << qMakePair<int, int>(d->groupId, d->index); } void QQuickParticlePainter::reload(QQuickParticleData* d) { if (m_pleaseReset) return; - m_pendingCommits << qMakePair<int, int>(d->group, d->index); + m_pendingCommits << qMakePair<int, int>(d->groupId, d->index); } void QQuickParticlePainter::reset() @@ -133,11 +168,6 @@ void QQuickParticlePainter::setCount(int c)//### TODO: some resizeing so that pa reset(); } -int QQuickParticlePainter::count() -{ - return m_count; -} - void QQuickParticlePainter::calcSystemOffset(bool resetPending) { if (!m_system || !parentItem()) diff --git a/src/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h index 719dfdb3d8..064ce27fe8 100644 --- a/src/particles/qquickparticlepainter_p.h +++ b/src/particles/qquickparticlepainter_p.h @@ -64,25 +64,40 @@ class QQuickParticlePainter : public QQuickItem Q_PROPERTY(QQuickParticleSystem* system READ system WRITE setSystem NOTIFY systemChanged) Q_PROPERTY(QStringList groups READ groups WRITE setGroups NOTIFY groupsChanged) +public: // data + typedef QQuickParticleVarLengthArray<QQuickParticleGroupData::ID, 4> GroupIDs; + public: explicit QQuickParticlePainter(QQuickItem *parent = 0); //Data Interface to system void load(QQuickParticleData*); void reload(QQuickParticleData*); void setCount(int c); - int count(); + + int count() const + { + return m_count; + } + void performPendingCommits();//Called from updatePaintNode QQuickParticleSystem* system() const { return m_system; } - QStringList groups() const { return m_groups; } + const GroupIDs &groupIds() const + { + if (m_groupIdsNeedRecalculation) { + recalculateGroupIds(); + } + return m_groupIds; + } + void itemChange(ItemChange, const ItemChangeData &); Q_SIGNALS: @@ -94,14 +109,7 @@ Q_SIGNALS: public Q_SLOTS: void setSystem(QQuickParticleSystem* arg); - void setGroups(const QStringList &arg) - { - if (m_groups != arg) { - m_groups = arg; - //Note: The system watches this as it has to recalc things when groups change. It will request a reset if necessary - Q_EMIT groupsChanged(arg); - } - } + void setGroups(const QStringList &arg); void calcSystemOffset(bool resetPending = false); @@ -130,13 +138,18 @@ protected: friend class QQuickParticleSystem; int m_count; bool m_pleaseReset;//Used by subclasses, but it's a nice optimization to know when stuff isn't going to matter. - QStringList m_groups; QPointF m_systemOffset; QQuickWindow *m_window; -private: +private: // methods + void recalculateGroupIds() const; + +private: // data + QStringList m_groups; QSet<QPair<int,int> > m_pendingCommits; + mutable GroupIDs m_groupIds; + mutable bool m_groupIdsNeedRecalculation; }; QT_END_NAMESPACE diff --git a/src/particles/qquickparticlesystem.cpp b/src/particles/qquickparticlesystem.cpp index 603515dc66..17d9e49d63 100644 --- a/src/particles/qquickparticlesystem.cpp +++ b/src/particles/qquickparticlesystem.cpp @@ -199,24 +199,8 @@ DEFINE_BOOL_CONFIG_OPTION(qmlParticlesDebug, QML_PARTICLES_DEBUG) Discards all currently existing particles. */ -const qreal EPSILON = 0.001; -//Utility functions for when within 1ms is close enough -bool timeEqualOrGreater(qreal a, qreal b) -{ - return (a+EPSILON >= b); -} - -bool timeLess(qreal a, qreal b) -{ - return (a-EPSILON < b); -} -bool timeEqual(qreal a, qreal b) -{ - return (a+EPSILON > b) && (a-EPSILON < b); -} - -int roundedTime(qreal a) +static inline int roundedTime(qreal a) {// in ms return (int)qRound(a*1000.0); } @@ -330,7 +314,10 @@ void QQuickParticleDataHeap::bubbleDown(int idx)//tends to be called log n times } } -QQuickParticleGroupData::QQuickParticleGroupData(int id, QQuickParticleSystem* sys):index(id),m_size(0),m_system(sys) +QQuickParticleGroupData::QQuickParticleGroupData(const QString &name, QQuickParticleSystem* sys) + : index(sys->registerParticleGroupData(name, this)) + , m_size(0) + , m_system(sys) { initList(); } @@ -341,11 +328,6 @@ QQuickParticleGroupData::~QQuickParticleGroupData() delete d; } -int QQuickParticleGroupData::size() -{ - return m_size; -} - QString QQuickParticleGroupData::name()//### Worth caching as well? { return m_system->groupIds.key(index); @@ -357,11 +339,11 @@ void QQuickParticleGroupData::setSize(int newSize) return; Q_ASSERT(newSize > m_size);//XXX allow shrinking data.resize(newSize); + freeList.resize(newSize); for (int i=m_size; i<newSize; i++) { - data[i] = new QQuickParticleData(m_system); - data[i]->group = index; + data[i] = new QQuickParticleData; + data[i]->groupId = index; data[i]->index = i; - reusableIndexes << i; } int delta = newSize - m_size; m_size = newSize; @@ -376,21 +358,20 @@ void QQuickParticleGroupData::initList() void QQuickParticleGroupData::kill(QQuickParticleData* d) { - Q_ASSERT(d->group == index); + Q_ASSERT(d->groupId == index); d->lifeSpan = 0;//Kill off foreach (QQuickParticlePainter* p, painters) p->reload(d); - reusableIndexes << d->index; + freeList.free(d->index); } QQuickParticleData* QQuickParticleGroupData::newDatum(bool respectsLimits) { //recycle();//Extra recycler round to be sure? - while (!reusableIndexes.empty()) { - int idx = *(reusableIndexes.begin()); - reusableIndexes.remove(idx); - if (data[idx]->stillAlive()) {// ### This means resurrection of 'dead' particles. Is that allowed? + while (freeList.hasUnusedEntries()) { + int idx = freeList.alloc(); + if (data[idx]->stillAlive(m_system)) {// ### This means resurrection of 'dead' particles. Is that allowed? prepareRecycler(data[idx]); continue; } @@ -401,16 +382,17 @@ QQuickParticleData* QQuickParticleGroupData::newDatum(bool respectsLimits) int oldSize = m_size; setSize(oldSize + 10);//###+1,10%,+10? Choose something non-arbitrarily - reusableIndexes.remove(oldSize); - return data[oldSize]; + int idx = freeList.alloc(); + Q_ASSERT(idx == oldSize); + return data[idx]; } bool QQuickParticleGroupData::recycle() { while (dataHeap.top() <= m_system->timeInt) { foreach (QQuickParticleData* datum, dataHeap.pop()) { - if (!datum->stillAlive()) { - reusableIndexes << datum->index; + if (!datum->stillAlive(m_system)) { + freeList.free(datum->index); } else { prepareRecycler(datum); //ttl has been altered mid-way, put it back } @@ -418,7 +400,7 @@ bool QQuickParticleGroupData::recycle() } //TODO: If the data is clear, gc (consider shrinking stack size)? - return reusableIndexes.count() == m_size; + return freeList.count() == 0; } void QQuickParticleGroupData::prepareRecycler(QQuickParticleData* d) @@ -427,17 +409,15 @@ void QQuickParticleGroupData::prepareRecycler(QQuickParticleData* d) dataHeap.insert(d); } else { while ((roundedTime(d->t) + 2*m_system->maxLife/3) <= m_system->timeInt) - d->extendLife(m_system->maxLife/3000.0); + d->extendLife(m_system->maxLife / 3000.0, m_system); dataHeap.insertTimed(d, roundedTime(d->t) + 2*m_system->maxLife/3); } } -QQuickParticleData::QQuickParticleData(QQuickParticleSystem* sys) - : e(0) - , system(sys) - , index(0) +QQuickParticleData::QQuickParticleData() + : index(0) , systemIndex(-1) - , group(0) + , groupId(0) , colorOwner(0) , rotationOwner(0) , deformationOwner(0) @@ -493,9 +473,7 @@ QQuickParticleData &QQuickParticleData::operator=(const QQuickParticleData &othe { clone(other); - group = other.group; - e = other.e; - system = other.system; + groupId = other.groupId; index = other.index; systemIndex = other.systemIndex; // Lazily initialized @@ -545,150 +523,34 @@ void QQuickParticleData::clone(const QQuickParticleData& other) animationOwner = other.animationOwner; } -QQmlV4Handle QQuickParticleData::v4Value() +QQmlV4Handle QQuickParticleData::v4Value(QQuickParticleSystem* particleSystem) { if (!v8Datum) - v8Datum = new QQuickV4ParticleData(QQmlEnginePrivate::getV8Engine(qmlEngine(system)), this); + v8Datum = new QQuickV4ParticleData(QQmlEnginePrivate::getV8Engine(qmlEngine(particleSystem)), this, particleSystem); return v8Datum->v4Value(); } -//sets the x accleration without affecting the instantaneous x velocity or position -void QQuickParticleData::setInstantaneousAX(qreal ax) -{ - qreal t = (system->timeInt / 1000.0) - this->t; - qreal vx = (this->vx + t*this->ax) - t*ax; - qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; - qreal x = ex - t*vx - 0.5 * t*t*ax; - - this->ax = ax; - this->vx = vx; - this->x = x; -} -//sets the x velocity without affecting the instantaneous x postion -void QQuickParticleData::setInstantaneousVX(qreal vx) +void QQuickParticleData::debugDump(QQuickParticleSystem* particleSystem) const { - qreal t = (system->timeInt / 1000.0) - this->t; - qreal evx = vx - t*this->ax; - qreal ex = this->x + this->vx * t + 0.5 * this->ax * t * t; - qreal x = ex - t*evx - 0.5 * t*t*this->ax; - - this->vx = evx; - this->x = x; -} - -//sets the instantaneous x postion -void QQuickParticleData::setInstantaneousX(qreal x) -{ - qreal t = (system->timeInt / 1000.0) - this->t; - this->x = x - t*this->vx - 0.5 * t*t*this->ax; -} - -//sets the y accleration without affecting the instantaneous y velocity or position -void QQuickParticleData::setInstantaneousAY(qreal ay) -{ - qreal t = (system->timeInt / 1000.0) - this->t; - qreal vy = (this->vy + t*this->ay) - t*ay; - qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; - qreal y = ey - t*vy - 0.5 * t*t*ay; - - this->ay = ay; - this->vy = vy; - this->y = y; -} - -//sets the y velocity without affecting the instantaneous y position -void QQuickParticleData::setInstantaneousVY(qreal vy) -{ - qreal t = (system->timeInt / 1000.0) - this->t; - qreal evy = vy - t*this->ay; - qreal ey = this->y + this->vy * t + 0.5 * this->ay * t * t; - qreal y = ey - t*evy - 0.5 * t*t*this->ay; - - this->vy = evy; - this->y = y; -} - -//sets the instantaneous Y position -void QQuickParticleData::setInstantaneousY(qreal y) -{ - qreal t = (system->timeInt / 1000.0) - this->t; - this->y = y - t*this->vy - 0.5 * t*t*this->ay; -} - -qreal QQuickParticleData::curX() const -{ - qreal t = (system->timeInt / 1000.0) - this->t; - return this->x + this->vx * t + 0.5 * this->ax * t * t; -} - -qreal QQuickParticleData::curVX() const -{ - qreal t = (system->timeInt / 1000.0) - this->t; - return this->vx + t*this->ax; -} - -qreal QQuickParticleData::curY() const -{ - qreal t = (system->timeInt / 1000.0) - this->t; - return y + vy * t + 0.5 * ay * t * t; -} - -qreal QQuickParticleData::curVY() const -{ - qreal t = (system->timeInt / 1000.0) - this->t; - return vy + t*ay; -} - -void QQuickParticleData::debugDump() -{ - qDebug() << "Particle" << systemIndex << group << "/" << index << stillAlive() + qDebug() << "Particle" << systemIndex << groupId << "/" << index << stillAlive(particleSystem) << "Pos: " << x << "," << y << "Vel: " << vx << "," << vy << "Acc: " << ax << "," << ay << "Size: " << size << "," << endSize - << "Time: " << t << "," <<lifeSpan << ";" << (system->timeInt / 1000.0) ; -} - -bool QQuickParticleData::stillAlive() -{ - if (!system) - return false; - return (t + lifeSpan - EPSILON) > ((qreal)system->timeInt/1000.0); -} - -bool QQuickParticleData::alive() -{ - if (!system) - return false; - qreal st = ((qreal)system->timeInt/1000.0); - return (t + EPSILON) < st && (t + lifeSpan - EPSILON) > st; + << "Time: " << t << "," <<lifeSpan << ";" << (particleSystem->timeInt / 1000.0) ; } -float QQuickParticleData::curSize() +void QQuickParticleData::extendLife(float time, QQuickParticleSystem* particleSystem) { - if (!system || !lifeSpan) - return 0.0f; - return size + (endSize - size) * (1 - (lifeLeft() / lifeSpan)); -} - -float QQuickParticleData::lifeLeft() -{ - if (!system) - return 0.0f; - return (t + lifeSpan) - (system->timeInt/1000.0); -} - -void QQuickParticleData::extendLife(float time) -{ - qreal newX = curX(); - qreal newY = curY(); - qreal newVX = curVX(); - qreal newVY = curVY(); + qreal newX = curX(particleSystem); + qreal newY = curY(particleSystem); + qreal newVX = curVX(particleSystem); + qreal newVY = curVY(particleSystem); t += time; animT += time; - qreal elapsed = (system->timeInt / 1000.0) - t; + qreal elapsed = (particleSystem->timeInt / 1000.0) - t; qreal evy = newVY - elapsed*ay; qreal ey = newY - elapsed*evy - 0.5 * elapsed*elapsed*ay; qreal evx = newVX - elapsed*ax; @@ -703,6 +565,7 @@ void QQuickParticleData::extendLife(float time) QQuickParticleSystem::QQuickParticleSystem(QQuickItem *parent) : QQuickItem(parent), stateEngine(0), + nextFreeGroupId(0), m_animation(0), m_running(true), initialized(0), @@ -732,11 +595,11 @@ void QQuickParticleSystem::initGroups() qDeleteAll(groupData); groupData.clear(); groupIds.clear(); + nextFreeGroupId = 0; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(0, this);//Default group - groupData.insert(0,gd); - groupIds.insert(QString(), 0); - m_nextGroupId = 1; + QQuickParticleGroupData *pd = new QQuickParticleGroupData(QString(), this); // Default group + Q_ASSERT(pd->index == 0); + Q_UNUSED(pd); } void QQuickParticleSystem::registerParticlePainter(QQuickParticlePainter* p) @@ -755,11 +618,16 @@ void QQuickParticleSystem::registerParticleEmitter(QQuickParticleEmitter* e) if (m_debugMode) qDebug() << "Registering Emitter" << e << "to" << this; m_emitters << QPointer<QQuickParticleEmitter>(e);//###How to get them out? +} + +void QQuickParticleSystem::finishRegisteringParticleEmitter(QQuickParticleEmitter* e) +{ connect(e, SIGNAL(particleCountChanged()), this, SLOT(emittersChanged())); connect(e, SIGNAL(groupChanged(QString)), this, SLOT(emittersChanged())); - emittersChanged(); + if (m_componentComplete) + emittersChanged(); e->reset();//Start, so that starttime factors appropriately } @@ -848,6 +716,34 @@ void QQuickParticleSystem::stateRedirect(QQuickParticleGroup* group, QQuickParti qWarning() << value << " was placed inside a particle system state but cannot be taken into the particle system. It will be lost."; } + +int QQuickParticleSystem::registerParticleGroupData(const QString &name, QQuickParticleGroupData *pgd) +{ + Q_ASSERT(!groupIds.contains(name)); + int id; + if (nextFreeGroupId >= groupData.size()) { + groupData.push_back(pgd); + nextFreeGroupId = groupData.size(); + id = nextFreeGroupId - 1; + } else { + id = nextFreeGroupId; + groupData[id] = pgd; + searchNextFreeGroupId(); + } + groupIds.insert(name, id); + return id; +} + +void QQuickParticleSystem::searchNextFreeGroupId() +{ + ++nextFreeGroupId; + for (int ei = groupData.size(); nextFreeGroupId != ei; ++nextFreeGroupId) { + if (groupData[nextFreeGroupId] == nullptr) { + return; + } + } +} + void QQuickParticleSystem::componentComplete() { @@ -906,25 +802,21 @@ void QQuickParticleSystem::loadPainter(QObject *p) QQuickParticlePainter* painter = qobject_cast<QQuickParticlePainter*>(p); Q_ASSERT(painter);//XXX - foreach (QQuickParticleGroupData* sg, groupData) - sg->painters.remove(painter); + for (QQuickParticleGroupData* sg : groupData) { + sg->painters.removeOne(painter); + } + int particleCount = 0; if (painter->groups().isEmpty()) {//Uses default particle - QStringList def; - def << QString(); + static QStringList def = QStringList() << QString(); painter->setGroups(def); particleCount += groupData[0]->size(); groupData[0]->painters << painter; } else { - foreach (const QString &group, painter->groups()) { - if (group != QLatin1String("") && !groupIds[group]) {//new group - int id = m_nextGroupId++; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(id, this); - groupIds.insert(group, id); - groupData.insert(id, gd); - } - particleCount += groupData[groupIds[group]]->size(); - groupData[groupIds[group]]->painters << painter; + for (auto groupId : painter->groupIds()) { + QQuickParticleGroupData *gd = groupData[groupId]; + particleCount += gd->size(); + gd->painters << painter; } } painter->setCount(particleCount); @@ -939,44 +831,42 @@ void QQuickParticleSystem::emittersChanged() QVector<int> previousSizes; QVector<int> newSizes; - previousSizes.reserve(m_nextGroupId); - newSizes.reserve(m_nextGroupId); - for (int i=0; i<m_nextGroupId; i++) { + previousSizes.reserve(groupData.size()); + newSizes.reserve(groupData.size()); + for (int i = 0, ei = groupData.size(); i != ei; ++i) { previousSizes << groupData[i]->size(); newSizes << 0; } // Populate groups and set sizes. - for (int i = 0; i < m_emitters.count(); ++i) { + for (int i = 0; i < m_emitters.count(); ) { QQuickParticleEmitter *e = m_emitters.at(i); if (!e) { m_emitters.removeAt(i); - i--; continue; } - if (!e->group().isEmpty() && - !groupIds.contains(e->group())) { - int id = m_nextGroupId++; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(id, this); - groupIds.insert(e->group(), id); - groupData.insert(id, gd); + int groupId = e->groupId(); + if (groupId == QQuickParticleGroupData::InvalidID) { + groupId = (new QQuickParticleGroupData(e->group(), this))->index; previousSizes << 0; newSizes << 0; } - newSizes[groupIds[e->group()]] += e->particleCount(); + newSizes[groupId] += e->particleCount(); //###: Cull emptied groups? + + ++i; } //TODO: Garbage collection? particleCount = 0; - for (int i=0; i<m_nextGroupId; i++) { + for (int i = 0, ei = groupData.size(); i != ei; ++i) { groupData[i]->setSize(qMax(newSizes[i], previousSizes[i])); particleCount += groupData[i]->size(); } if (m_debugMode) - qDebug() << "Particle system emitters changed. New particle count: " << particleCount; + qDebug() << "Particle system emitters changed. New particle count: " << particleCount << "in" << groupData.size() << "groups."; if (particleCount > bySysIdx.size())//New datum requests haven't updated it bySysIdx.resize(particleCount); @@ -1008,17 +898,15 @@ void QQuickParticleSystem::createEngine() } } if (!exists) { - int id = m_nextGroupId++; - QQuickParticleGroupData* gd = new QQuickParticleGroupData(id, this); - groupIds.insert(group->name(), id); - groupData.insert(id, gd); + new QQuickParticleGroupData(group->name(), this); } } if (m_groups.count()) { //Reorder groups List so as to have the same order as groupData + // TODO: can't we just merge the two lists? QList<QQuickParticleGroup*> newList; - for (int i=0; i<m_nextGroupId; i++) { + for (int i = 0, ei = groupData.size(); i != ei; ++i) { bool exists = false; QString name = groupData[i]->name(); foreach (QQuickParticleGroup* existing, m_groups) { @@ -1061,7 +949,7 @@ void QQuickParticleSystem::particleStateChange(int idx) void QQuickParticleSystem::moveGroups(QQuickParticleData *d, int newGIdx) { - if (!d || newGIdx == d->group) + if (!d || newGIdx == d->groupId) return; QQuickParticleData* pd = newDatum(newGIdx, false, d->systemIndex); @@ -1072,7 +960,7 @@ void QQuickParticleSystem::moveGroups(QQuickParticleData *d, int newGIdx) finishNewDatum(pd); d->systemIndex = -1; - groupData[d->group]->kill(d); + groupData[d->groupId]->kill(d); } int QQuickParticleSystem::nextSystemIndex() @@ -1114,17 +1002,17 @@ QQuickParticleData* QQuickParticleSystem::newDatum(int groupId, bool respectLimi bySysIdx[ret->systemIndex] = ret; if (stateEngine) - stateEngine->start(ret->systemIndex, ret->group); + stateEngine->start(ret->systemIndex, ret->groupId); m_empty = false; return ret; } -void QQuickParticleSystem::emitParticle(QQuickParticleData* pd) +void QQuickParticleSystem::emitParticle(QQuickParticleData* pd, QQuickParticleEmitter* particleEmitter) {// called from prepareNextFrame()->emitWindow - enforce? //Account for relative emitter position bool okay = false; - QTransform t = pd->e->itemTransform(this, &okay); + QTransform t = particleEmitter->itemTransform(this, &okay); if (okay) { qreal tx,ty; t.map(pd->x, pd->y, &tx, &ty); @@ -1138,12 +1026,12 @@ void QQuickParticleSystem::emitParticle(QQuickParticleData* pd) void QQuickParticleSystem::finishNewDatum(QQuickParticleData *pd) { Q_ASSERT(pd); - groupData[pd->group]->prepareRecycler(pd); + groupData[pd->groupId]->prepareRecycler(pd); foreach (QQuickParticleAffector *a, m_affectors) if (a && a->m_needsReset) a->reset(pd); - foreach (QQuickParticlePainter* p, groupData[pd->group]->painters) + foreach (QQuickParticlePainter* p, groupData[pd->groupId]->painters) if (p) p->load(pd); } @@ -1177,7 +1065,7 @@ void QQuickParticleSystem::updateCurrentTime( int currentTime ) foreach (QQuickParticleAffector* a, m_affectors) a->affectSystem(dt); foreach (QQuickParticleData* d, needsReset) - foreach (QQuickParticlePainter* p, groupData[d->group]->painters) + foreach (QQuickParticlePainter* p, groupData[d->groupId]->painters) p->reload(d); if (oldClear != m_empty) diff --git a/src/particles/qquickparticlesystem_p.h b/src/particles/qquickparticlesystem_p.h index 5a1ab5022d..b57d55bd98 100644 --- a/src/particles/qquickparticlesystem_p.h +++ b/src/particles/qquickparticlesystem_p.h @@ -61,10 +61,35 @@ #include <QAbstractAnimation> #include <QtQml/qqml.h> #include <private/qv8engine_p.h> //For QQmlV4Handle +#include <private/qv4util_p.h> #include "qtquickparticlesglobal_p.h" QT_BEGIN_NAMESPACE +template<class T, int Prealloc> +class QQuickParticleVarLengthArray: public QVarLengthArray<T, Prealloc> +{ +public: + void insert(const T &element) + { + if (!this->contains(element)) { + this->append(element); + } + } + + bool removeOne(const T &element) + { + for (int i = 0; i < this->size(); ++i) { + if (this->at(i) == element) { + this->remove(i); + return true; + } + } + + return false; + } +}; + class QQuickParticleSystem; class QQuickParticleAffector; class QQuickParticleEmitter; @@ -110,22 +135,87 @@ private: }; class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleGroupData { + class FreeList + { + public: + FreeList() + : firstUnused(UINT_MAX) + , allocated(0) + {} + + void resize(int newSize) + { + Q_ASSERT(newSize >= 0); + int oldSize = isUnused.size(); + isUnused.resize(newSize, true); + if (newSize > oldSize) { + if (firstUnused == UINT_MAX) { + firstUnused = oldSize; + } else { + firstUnused = std::min(firstUnused, unsigned(oldSize)); + } + } else if (firstUnused >= unsigned(newSize)) { + firstUnused = UINT_MAX; + } + } + + void free(int index) + { + isUnused.setBit(index); + firstUnused = std::min(firstUnused, unsigned(index)); + --allocated; + } + + int count() const + { return allocated; } + + bool hasUnusedEntries() const + { return firstUnused != UINT_MAX; } + + int alloc() + { + if (hasUnusedEntries()) { + int nextFree = firstUnused; + isUnused.clearBit(firstUnused); + firstUnused = isUnused.findNext(firstUnused, true, false); + if (firstUnused >= unsigned(isUnused.size())) { + firstUnused = UINT_MAX; + } + ++allocated; + return nextFree; + } else { + return -1; + } + } + + private: + QV4::BitVector isUnused; + unsigned firstUnused; + int allocated; + }; + +public: // types + typedef int ID; + enum { InvalidID = -1, DefaultGroupID = 0 }; + public: - QQuickParticleGroupData(int id, QQuickParticleSystem* sys); + QQuickParticleGroupData(const QString &name, QQuickParticleSystem* sys); ~QQuickParticleGroupData(); - int size(); + int size() + { return m_size; } + QString name(); void setSize(int newSize); - int index; - QSet<QQuickParticlePainter*> painters;//TODO: What if they are dynamically removed? + const ID index; + QQuickParticleVarLengthArray<QQuickParticlePainter*, 4> painters;//TODO: What if they are dynamically removed? //TODO: Refactor particle data list out into a separate class QVector<QQuickParticleData*> data; + FreeList freeList; QQuickParticleDataHeap dataHeap; - QSet<int> reusableIndexes; bool recycle(); //Force recycling round, returns true if all indexes are now reusable void initList(); @@ -152,7 +242,7 @@ struct Color4ub { class Q_QUICKPARTICLES_PRIVATE_EXPORT QQuickParticleData { public: //TODO: QObject like memory management (without the cost, just attached to system) - QQuickParticleData(QQuickParticleSystem* sys); + QQuickParticleData(); ~QQuickParticleData(); QQuickParticleData(const QQuickParticleData &other); @@ -162,28 +252,28 @@ public: //If setting multiple parameters at once, doing the conversion yourself will be faster. //sets the x accleration without affecting the instantaneous x velocity or position - void setInstantaneousAX(qreal ax); + void setInstantaneousAX(float ax, QQuickParticleSystem *particleSystem); //sets the x velocity without affecting the instantaneous x postion - void setInstantaneousVX(qreal vx); + void setInstantaneousVX(float vx, QQuickParticleSystem *particleSystem); //sets the instantaneous x postion - void setInstantaneousX(qreal x); + void setInstantaneousX(float x, QQuickParticleSystem *particleSystem); //sets the y accleration without affecting the instantaneous y velocity or position - void setInstantaneousAY(qreal ay); + void setInstantaneousAY(float ay, QQuickParticleSystem *particleSystem); //sets the y velocity without affecting the instantaneous y postion - void setInstantaneousVY(qreal vy); + void setInstantaneousVY(float vy, QQuickParticleSystem *particleSystem); //sets the instantaneous Y postion - void setInstantaneousY(qreal y); + void setInstantaneousY(float y, QQuickParticleSystem *particleSystem); //TODO: Slight caching? - qreal curX() const; - qreal curVX() const; - qreal curAX() const { return ax; } - qreal curY() const; - qreal curVY() const; - qreal curAY() const { return ay; } - - QQuickParticleEmitter* e;//### Needed? - QQuickParticleSystem* system; + float curX(QQuickParticleSystem *particleSystem) const; + float curVX(QQuickParticleSystem *particleSystem) const; + float curAX() const { return ax; } + float curAX(QQuickParticleSystem *) const { return ax; } // used by the macros in qquickv4particledata.cpp + float curY(QQuickParticleSystem *particleSystem) const; + float curVY(QQuickParticleSystem *particleSystem) const; + float curAY() const { return ay; } + float curAY(QQuickParticleSystem *) const { return ay; } // used by the macros in qquickv4particledata.cpp + int index; int systemIndex; @@ -221,7 +311,7 @@ public: float animWidth; float animHeight; - int group; + QQuickParticleGroupData::ID groupId; //Used by ImageParticle data shadowing QQuickImageParticle* colorOwner; @@ -240,14 +330,18 @@ public: // 4 bytes wasted - void debugDump(); - bool stillAlive();//Only checks end, because usually that's all you need and it's a little faster. - bool alive(); - float lifeLeft(); - float curSize(); + void debugDump(QQuickParticleSystem *particleSystem) const; + bool stillAlive(QQuickParticleSystem *particleSystem) const; //Only checks end, because usually that's all you need and it's a little faster. + bool alive(QQuickParticleSystem *particleSystem) const; + float lifeLeft(QQuickParticleSystem *particleSystem) const; + + float curSize(QQuickParticleSystem *particleSystem) const; void clone(const QQuickParticleData& other);//Not =, leaves meta-data like index - QQmlV4Handle v4Value(); - void extendLife(float time); + QQmlV4Handle v4Value(QQuickParticleSystem *particleSystem); + void extendLife(float time, QQuickParticleSystem *particleSystem); + + static inline Q_DECL_CONSTEXPR float EPSILON() Q_DECL_NOTHROW { return 0.001f; } + private: QQuickV4ParticleData* v8Datum; }; @@ -305,7 +399,7 @@ private Q_SLOTS: public: //These can be called multiple times per frame, performance critical - void emitParticle(QQuickParticleData* p); + void emitParticle(QQuickParticleData* p, QQuickParticleEmitter *particleEmitter); QQuickParticleData* newDatum(int groupId, bool respectLimits = true, int sysIdx = -1); void finishNewDatum(QQuickParticleData*); void moveGroups(QQuickParticleData *d, int newGIdx); @@ -317,10 +411,13 @@ public: //Data members here for ease of related class and auto-test usage. Not "public" API. TODO: d_ptrize QSet<QQuickParticleData*> needsReset; QVector<QQuickParticleData*> bySysIdx; //Another reference to the data (data owned by group), but by sysIdx - QHash<QString, int> groupIds; - QHash<int, QQuickParticleGroupData*> groupData; QQuickStochasticEngine* stateEngine; + QHash<QString, int> groupIds; + QVarLengthArray<QQuickParticleGroupData*, 32> groupData; + int nextFreeGroupId; + int registerParticleGroupData(const QString &name, QQuickParticleGroupData *pgd); + //Also only here for auto-test usage void updateCurrentTime( int currentTime ); QQuickParticleSystemAnimation* m_animation; @@ -333,6 +430,7 @@ public: void registerParticlePainter(QQuickParticlePainter* p); void registerParticleEmitter(QQuickParticleEmitter* e); + void finishRegisteringParticleEmitter(QQuickParticleEmitter *e); void registerParticleAffector(QQuickParticleAffector* a); void registerParticleGroup(QQuickParticleGroup* g); @@ -349,6 +447,9 @@ public: } private: + void searchNextFreeGroupId(); + +private: void initializeSystem(); void initGroups(); QList<QPointer<QQuickParticleEmitter> > m_emitters; @@ -356,7 +457,6 @@ private: QList<QPointer<QQuickParticlePainter> > m_painters; QList<QPointer<QQuickParticlePainter> > m_syncList; QList<QQuickParticleGroup*> m_groups; - int m_nextGroupId; int m_nextIndex; QSet<int> m_reusableIndexes; bool m_componentComplete; @@ -391,6 +491,124 @@ private: QQuickParticleSystem* m_system; }; +inline void QQuickParticleData::setInstantaneousAX(float ax, QQuickParticleSystem* particleSystem) +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + float vx = (this->vx + t * this->ax) - t * ax; + float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq; + float x = ex - t * vx - 0.5f * t_sq * ax; + + this->ax = ax; + this->vx = vx; + this->x = x; +} + +inline void QQuickParticleData::setInstantaneousVX(float vx, QQuickParticleSystem* particleSystem) +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + float evx = vx - t * this->ax; + float ex = this->x + this->vx * t + 0.5f * this->ax * t_sq; + float x = ex - t * evx - 0.5f * t_sq * this->ax; + + this->vx = evx; + this->x = x; +} + +inline void QQuickParticleData::setInstantaneousX(float x, QQuickParticleSystem* particleSystem) +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + this->x = x - t * this->vx - 0.5f * t_sq * this->ax; +} + +inline void QQuickParticleData::setInstantaneousAY(float ay, QQuickParticleSystem* particleSystem) +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + float vy = (this->vy + t * this->ay) - t * ay; + float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq; + float y = ey - t * vy - 0.5f * t_sq * ay; + + this->ay = ay; + this->vy = vy; + this->y = y; +} + +inline void QQuickParticleData::setInstantaneousVY(float vy, QQuickParticleSystem* particleSystem) +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + float evy = vy - t * this->ay; + float ey = this->y + this->vy * t + 0.5f * this->ay * t_sq; + float y = ey - t*evy - 0.5f * t_sq * this->ay; + + this->vy = evy; + this->y = y; +} + +inline void QQuickParticleData::setInstantaneousY(float y, QQuickParticleSystem *particleSystem) +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + this->y = y - t * this->vy - 0.5f * t_sq * this->ay; +} + +inline float QQuickParticleData::curX(QQuickParticleSystem *particleSystem) const +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + return this->x + this->vx * t + 0.5f * this->ax * t_sq; +} + +inline float QQuickParticleData::curVX(QQuickParticleSystem *particleSystem) const +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + return this->vx + t * this->ax; +} + +inline float QQuickParticleData::curY(QQuickParticleSystem *particleSystem) const +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + float t_sq = t * t; + return y + vy * t + 0.5f * ay * t_sq; +} + +inline float QQuickParticleData::curVY(QQuickParticleSystem *particleSystem) const +{ + float t = (particleSystem->timeInt / 1000.0f) - this->t; + return vy + t*ay; +} + +inline bool QQuickParticleData::stillAlive(QQuickParticleSystem* system) const +{ + if (!system) + return false; + return (t + lifeSpan - EPSILON()) > (system->timeInt / 1000.0f); +} + +inline bool QQuickParticleData::alive(QQuickParticleSystem* system) const +{ + if (!system) + return false; + float st = (system->timeInt / 1000.0f); + return (t + EPSILON()) < st && (t + lifeSpan - EPSILON()) > st; +} + +inline float QQuickParticleData::lifeLeft(QQuickParticleSystem *particleSystem) const +{ + if (!particleSystem) + return 0.0f; + return (t + lifeSpan) - (particleSystem->timeInt / 1000.0f); +} + +inline float QQuickParticleData::curSize(QQuickParticleSystem *particleSystem) const +{ + if (!particleSystem || lifeSpan == 0.0f) + return 0.0f; + return size + (endSize - size) * (1 - (lifeLeft(particleSystem) / lifeSpan)); +} QT_END_NAMESPACE diff --git a/src/particles/qquickpointattractor.cpp b/src/particles/qquickpointattractor.cpp index 8b3cfbd1ff..779b2915f0 100644 --- a/src/particles/qquickpointattractor.cpp +++ b/src/particles/qquickpointattractor.cpp @@ -115,8 +115,8 @@ bool QQuickAttractorAffector::affectParticle(QQuickParticleData *d, qreal dt) { if (m_strength == 0.0) return false; - qreal dx = m_x+m_offset.x() - d->curX(); - qreal dy = m_y+m_offset.y() - d->curY(); + qreal dx = m_x+m_offset.x() - d->curX(m_system); + qreal dy = m_y+m_offset.y() - d->curY(m_system); qreal r = std::sqrt((dx*dx) + (dy*dy)); qreal theta = std::atan2(dy,dx); qreal ds = 0; @@ -146,15 +146,15 @@ bool QQuickAttractorAffector::affectParticle(QQuickParticleData *d, qreal dt) d->y = (d->y + dy); break; case Acceleration: - d->setInstantaneousAX(d->ax + dx); - d->setInstantaneousAY(d->ay + dy); + d->setInstantaneousAX(d->ax + dx, m_system); + d->setInstantaneousAY(d->ay + dy, m_system); break; case Velocity: //also default default: - vx = d->curVX(); - vy = d->curVY(); - d->setInstantaneousVX(vx + dx); - d->setInstantaneousVY(vy + dy); + vx = d->curVX(m_system); + vy = d->curVY(m_system); + d->setInstantaneousVX(vx + dx, m_system); + d->setInstantaneousVY(vy + dy, m_system); } return true; diff --git a/src/particles/qquickspritegoal.cpp b/src/particles/qquickspritegoal.cpp index 7afb787530..5784f1402d 100644 --- a/src/particles/qquickspritegoal.cpp +++ b/src/particles/qquickspritegoal.cpp @@ -124,7 +124,7 @@ bool QQuickSpriteGoalAffector::affectParticle(QQuickParticleData *d, qreal dt) QQuickStochasticEngine *engine = 0; if (!m_systemStates){ //TODO: Affect all engines - foreach (QQuickParticlePainter *p, m_system->groupData[d->group]->painters) + foreach (QQuickParticlePainter *p, m_system->groupData[d->groupId]->painters) if (qobject_cast<QQuickImageParticle*>(p)) engine = qobject_cast<QQuickImageParticle*>(p)->spriteEngine(); }else{ diff --git a/src/particles/qquicktrailemitter.cpp b/src/particles/qquicktrailemitter.cpp index 89a68a0356..d4d2adcfb2 100644 --- a/src/particles/qquicktrailemitter.cpp +++ b/src/particles/qquicktrailemitter.cpp @@ -179,10 +179,10 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize; int gId = m_system->groupIds[m_follow]; - int gId2 = m_system->groupIds[m_group]; + int gId2 = groupId(); for (int i=0; i<m_system->groupData[gId]->data.count(); i++) { QQuickParticleData *d = m_system->groupData[gId]->data[i]; - if (!d->stillAlive()){ + if (!d->stillAlive(m_system)){ m_lastEmission[i] = time; //Should only start emitting when it returns to life continue; } @@ -192,7 +192,8 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) if (pt + maxLife < time)//We missed so much, that we should skip emiting particles that are dead by now pt = time - maxLife; - if ((width() || height()) && !effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()),QPointF(d->curX(), d->curY()))){ + if ((width() || height()) && !effectiveExtruder()->contains(QRectF(offset.x(), offset.y(), width(), height()), + QPointF(d->curX(m_system), d->curY(m_system)))) { m_lastEmission[d->index] = time;//jump over this time period without emitting, because it's outside continue; } @@ -202,8 +203,6 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) while (pt < time || !m_burstQueue.isEmpty()){ QQuickParticleData* datum = m_system->newDatum(gId2, !m_overwrite); if (datum){//else, skip this emission - datum->e = this;//###useful? - // Particle timestamp datum->t = pt; datum->lifeSpan = @@ -215,8 +214,8 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) // Note that burst location doesn't get used for follow emitter qreal followT = pt - d->t; qreal followT2 = followT * followT * 0.5; - qreal eW = m_emitterXVariation < 0 ? d->curSize() : m_emitterXVariation; - qreal eH = m_emitterYVariation < 0 ? d->curSize() : m_emitterYVariation; + qreal eW = m_emitterXVariation < 0 ? d->curSize(m_system) : m_emitterXVariation; + qreal eH = m_emitterYVariation < 0 ? d->curSize(m_system) : m_emitterYVariation; //Subtract offset, because PS expects this in emitter coordinates QRectF boundsRect(d->x - offset.x() + d->vx * followT + d->ax * followT2 - eW/2, d->y - offset.y() + d->vy * followT + d->ay * followT2 - eH/2, @@ -251,7 +250,7 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) toEmit << datum; - m_system->emitParticle(datum); + m_system->emitParticle(datum, this); } if (!m_burstQueue.isEmpty()){ m_burstQueue.first().first--; @@ -263,7 +262,7 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) } foreach (QQuickParticleData* d, toEmit) - m_system->emitParticle(d); + m_system->emitParticle(d, this); if (isEmitConnected() || isEmitFollowConnected()) { QQmlEngine *qmlEngine = ::qmlEngine(this); @@ -273,10 +272,10 @@ void QQuickTrailEmitter::emitWindow(int timeStamp) QV4::ScopedArrayObject array(scope, v4->newArrayObject(toEmit.size())); QV4::ScopedValue v(scope); for (int i=0; i<toEmit.size(); i++) - array->putIndexed(i, (v = toEmit[i]->v4Value())); + array->putIndexed(i, (v = toEmit[i]->v4Value(m_system))); if (isEmitFollowConnected()) - emitFollowParticles(QQmlV4Handle(array), d->v4Value());//A chance for many arbitrary JS changes + emitFollowParticles(QQmlV4Handle(array), d->v4Value(m_system));//A chance for many arbitrary JS changes else if (isEmitConnected()) emitParticles(QQmlV4Handle(array));//A chance for arbitrary JS changes } diff --git a/src/particles/qquickturbulence.cpp b/src/particles/qquickturbulence.cpp index 154235441b..74558413a6 100644 --- a/src/particles/qquickturbulence.cpp +++ b/src/particles/qquickturbulence.cpp @@ -181,12 +181,12 @@ void QQuickTurbulenceAffector::affectSystem(qreal dt) QRect boundsRect(0,0,m_gridSize,m_gridSize); foreach (QQuickParticleGroupData *gd, m_system->groupData){ - if (!activeGroup(m_system->groupData.key(gd))) + if (!activeGroup(gd->index)) continue; foreach (QQuickParticleData *d, gd->data){ if (!shouldAffect(d)) continue; - QPoint pos = (QPointF(d->curX(), d->curY()) - m_offset).toPoint(); + QPoint pos = (QPointF(d->curX(m_system), d->curY(m_system)) - m_offset).toPoint(); if (!boundsRect.contains(pos,true))//Need to redo bounds checking due to quantization. continue; qreal fx = 0.0; @@ -194,8 +194,8 @@ void QQuickTurbulenceAffector::affectSystem(qreal dt) fx += m_vectorField[pos.x()][pos.y()].x() * m_strength; fy += m_vectorField[pos.x()][pos.y()].y() * m_strength; if (fx || fy){ - d->setInstantaneousVX(d->curVX()+ fx * dt); - d->setInstantaneousVY(d->curVY()+ fy * dt); + d->setInstantaneousVX(d->curVX(m_system)+ fx * dt, m_system); + d->setInstantaneousVY(d->curVY(m_system)+ fy * dt, m_system); postAffect(d); } } diff --git a/src/particles/qquickv4particledata.cpp b/src/particles/qquickv4particledata.cpp index 86e3c91ba8..3d7f4ce5b8 100644 --- a/src/particles/qquickv4particledata.cpp +++ b/src/particles/qquickv4particledata.cpp @@ -272,11 +272,13 @@ QT_BEGIN_NAMESPACE struct QV4ParticleData : public QV4::Object { struct Data : QV4::Object::Data { - Data(QQuickParticleData *datum) + Data(QQuickParticleData *datum, QQuickParticleSystem* particleSystem) : datum(datum) + , particleSystem(particleSystem) { } QQuickParticleData* datum;//TODO: Guard needed? + QQuickParticleSystem* particleSystem; }; V4_OBJECT(QV4::Object) }; @@ -312,7 +314,7 @@ static QV4::ReturnedValue particleData_lifeLeft(QV4::CallContext *ctx) if (!r || !r->d()->datum) return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); - return QV4::Encode(r->d()->datum->lifeLeft()); + return QV4::Encode(r->d()->datum->lifeLeft(r->d()->particleSystem)); } static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx) @@ -323,7 +325,7 @@ static QV4::ReturnedValue particleData_curSize(QV4::CallContext *ctx) if (!r || !r->d()->datum) return ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); - return QV4::Encode(r->d()->datum->curSize()); + return QV4::Encode(r->d()->datum->curSize(r->d()->particleSystem)); } #define COLOR_GETTER_AND_SETTER(VAR, NAME) static QV4::ReturnedValue particleData_get_ ## NAME (QV4::CallContext *ctx) \ { \ @@ -397,7 +399,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ if (!r || !r->d()->datum) \ ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object")); \ \ - return QV4::Encode(r->d()->datum-> GETTER ());\ + return QV4::Encode(r->d()->datum-> GETTER (r->d()->particleSystem));\ }\ \ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ @@ -407,7 +409,7 @@ static QV4::ReturnedValue particleData_set_ ## VARIABLE (QV4::CallContext *ctx)\ if (!r || !r->d()->datum)\ ctx->engine()->throwError(QStringLiteral("Not a valid ParticleData object"));\ \ - r->d()->datum-> SETTER (ctx->argc() ? ctx->args()[0].toNumber() : qQNaN());\ + r->d()->datum-> SETTER (ctx->argc() ? ctx->args()[0].toNumber() : qQNaN(), r->d()->particleSystem);\ return QV4::Encode::undefined(); \ } @@ -503,7 +505,7 @@ QV4ParticleDataDeletable::~QV4ParticleDataDeletable() V4_DEFINE_EXTENSION(QV4ParticleDataDeletable, particleV4Data); -QQuickV4ParticleData::QQuickV4ParticleData(QV8Engine* engine, QQuickParticleData* datum) +QQuickV4ParticleData::QQuickV4ParticleData(QV8Engine* engine, QQuickParticleData* datum, QQuickParticleSystem *system) { if (!engine || !datum) return; @@ -511,7 +513,7 @@ QQuickV4ParticleData::QQuickV4ParticleData(QV8Engine* engine, QQuickParticleData QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); QV4::Scope scope(v4); QV4ParticleDataDeletable *d = particleV4Data(scope.engine); - QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QV4ParticleData>(datum)); + QV4::ScopedObject o(scope, v4->memoryManager->allocObject<QV4ParticleData>(datum, system)); QV4::ScopedObject p(scope, d->proto.value()); o->setPrototype(p); m_v4Value = o; diff --git a/src/particles/qquickv4particledata_p.h b/src/particles/qquickv4particledata_p.h index b93c0333d7..0d88f0f9cc 100644 --- a/src/particles/qquickv4particledata_p.h +++ b/src/particles/qquickv4particledata_p.h @@ -58,9 +58,10 @@ QT_BEGIN_NAMESPACE class QQuickParticleData; +class QQuickParticleSystem; class QQuickV4ParticleData { public: - QQuickV4ParticleData(QV8Engine*,QQuickParticleData*); + QQuickV4ParticleData(QV8Engine*, QQuickParticleData*, QQuickParticleSystem *system); ~QQuickV4ParticleData(); QQmlV4Handle v4Value(); private: diff --git a/src/particles/qquickwander.cpp b/src/particles/qquickwander.cpp index 862c796dac..09d36ab2e8 100644 --- a/src/particles/qquickwander.cpp +++ b/src/particles/qquickwander.cpp @@ -151,29 +151,29 @@ bool QQuickWanderAffector::affectParticle(QQuickParticleData* data, qreal dt) qreal newX, newY; switch (m_affectedParameter){ case Position: - newX = data->curX() + dx; + newX = data->curX(m_system) + dx; if (m_xVariance > qAbs(newX) ) data->x += dx; - newY = data->curY() + dy; + newY = data->curY(m_system) + dy; if (m_yVariance > qAbs(newY) ) data->y += dy; break; default: case Velocity: - newX = data->curVX() + dx; - if (m_xVariance > qAbs(newX) ) - data->setInstantaneousVX(newX); - newY = data->curVY() + dy; - if (m_yVariance > qAbs(newY) ) - data->setInstantaneousVY(newY); + newX = data->curVX(m_system) + dx; + if (m_xVariance > qAbs(newX)) + data->setInstantaneousVX(newX, m_system); + newY = data->curVY(m_system) + dy; + if (m_yVariance > qAbs(newY)) + data->setInstantaneousVY(newY, m_system); break; case Acceleration: newX = data->ax + dx; - if (m_xVariance > qAbs(newX) ) - data->setInstantaneousAX(newX); + if (m_xVariance > qAbs(newX)) + data->setInstantaneousAX(newX, m_system); newY = data->ay + dy; - if (m_yVariance > qAbs(newY) ) - data->setInstantaneousAY(newY); + if (m_yVariance > qAbs(newY)) + data->setInstantaneousAY(newY, m_system); break; } return true; diff --git a/src/plugins/qmltooling/packetprotocol/qpacket.cpp b/src/plugins/qmltooling/packetprotocol/qpacket.cpp index c42288e920..fab0a5b189 100644 --- a/src/plugins/qmltooling/packetprotocol/qpacket.cpp +++ b/src/plugins/qmltooling/packetprotocol/qpacket.cpp @@ -108,11 +108,34 @@ QPacket::QPacket(int version, const QByteArray &data) } /*! - Returns raw packet data. + Returns a reference to the raw packet data. */ -QByteArray QPacket::data() const +const QByteArray &QPacket::data() const { return buf.data(); } +/*! + Returns a copy of the raw packet data, with extra reserved space removed. + Mind that this triggers a deep copy. Use it if you anticipate the data to be detached soon anyway. + */ +QByteArray QPacket::squeezedData() const +{ + QByteArray ret = buf.data(); + ret.squeeze(); + return ret; +} + +/*! + Clears the packet, discarding any data. + */ +void QPacket::clear() +{ + buf.reset(); + QByteArray &buffer = buf.buffer(); + // Keep the old size to prevent unnecessary allocations + buffer.reserve(buffer.capacity()); + buffer.truncate(0); +} + QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/packetprotocol/qpacket_p.h b/src/plugins/qmltooling/packetprotocol/qpacket_p.h index a079b244e8..b6fda2411d 100644 --- a/src/plugins/qmltooling/packetprotocol/qpacket_p.h +++ b/src/plugins/qmltooling/packetprotocol/qpacket_p.h @@ -61,7 +61,9 @@ class QPacket : public QDataStream public: QPacket(int version); explicit QPacket(int version, const QByteArray &ba); - QByteArray data() const; + const QByteArray &data() const; + QByteArray squeezedData() const; + void clear(); private: void init(QIODevice::OpenMode mode); diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index e89d87e76b..688ced26ec 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -67,7 +67,7 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin // (see tst_qqmldebugtrace::trace() benchmark) static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteArray> &messages) { - QByteArray data; + QQmlDebugPacket ds; Q_ASSERT_X(((d->messageType | d->detailType) & (1 << 31)) == 0, Q_FUNC_INFO, "You can use at most 31 message types and 31 detail types."); for (uint decodedMessageType = 0; (d->messageType >> decodedMessageType) != 0; @@ -81,7 +81,6 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteA continue; //### using QDataStream is relatively expensive - QQmlDebugPacket ds; ds << d->time << decodedMessageType << decodedDetailType; switch (decodedMessageType) { @@ -99,7 +98,8 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteA Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); break; } - messages << ds.data(); + messages.append(ds.squeezedData()); + ds.clear(); } } } @@ -107,7 +107,7 @@ static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteA qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { while (next != data.length()) { - if (data[next].time > until) + if (data[next].time > until || messages.length() > s_numMessagesPerBatch) return data[next].time; qQmlProfilerDataToByteArrays(&(data[next++]), messages); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp index fc2ba1e094..9e1c8af3e6 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp @@ -342,12 +342,15 @@ void QQmlProfilerServiceImpl::sendMessages() while (!m_startTimes.empty()) { QQmlAbstractProfilerAdapter *first = m_startTimes.begin().value(); m_startTimes.erase(m_startTimes.begin()); - if (!m_startTimes.empty()) { - qint64 next = first->sendMessages(m_startTimes.begin().key(), messages); - if (next != -1) - m_startTimes.insert(next, first); - } else { - first->sendMessages(std::numeric_limits<qint64>::max(), messages); + qint64 next = first->sendMessages(m_startTimes.isEmpty() ? + std::numeric_limits<qint64>::max() : + m_startTimes.begin().key(), messages); + if (next != -1) + m_startTimes.insert(next, first); + + if (messages.length() >= QQmlAbstractProfilerAdapter::s_numMessagesPerBatch) { + emit messagesToClient(name(), messages); + messages.clear(); } } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp index ffacc58817..b50eef5545 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp @@ -39,7 +39,6 @@ #include "qv4profileradapter.h" #include "qqmlprofilerservice.h" -#include "qqmldebugpacket.h" QT_BEGIN_NAMESPACE @@ -68,27 +67,28 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut QVector<QV4::Profiling::MemoryAllocationProperties>))); } -qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages) +qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages, + QQmlDebugPacket &d) { while (m_memoryData.length() > m_memoryPos && m_memoryData[m_memoryPos].timestamp <= until) { - QQmlDebugPacket d; QV4::Profiling::MemoryAllocationProperties &props = m_memoryData[m_memoryPos]; d << props.timestamp << MemoryAllocation << props.type << props.size; ++m_memoryPos; - messages.append(d.data()); + messages.append(d.squeezedData()); + d.clear(); } return m_memoryData.length() == m_memoryPos ? -1 : m_memoryData[m_memoryPos].timestamp; } qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &messages, - qint64 callNext) + qint64 callNext, QQmlDebugPacket &d) { if (callNext == -1) { m_functionCallData.clear(); m_functionCallPos = 0; } - qint64 memoryNext = appendMemoryEvents(until, messages); + qint64 memoryNext = appendMemoryEvents(until, messages, d); if (memoryNext == -1) { m_memoryData.clear(); @@ -101,42 +101,43 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { + QQmlDebugPacket d; while (true) { while (!m_stack.isEmpty() && (m_functionCallPos == m_functionCallData.length() || m_stack.top() <= m_functionCallData[m_functionCallPos].start)) { - if (m_stack.top() > until) - return finalizeMessages(until, messages, m_stack.top()); + if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch) + return finalizeMessages(until, messages, m_stack.top(), d); - appendMemoryEvents(m_stack.top(), messages); - QQmlDebugPacket d; + appendMemoryEvents(m_stack.top(), messages, d); d << m_stack.pop() << RangeEnd << Javascript; - messages.append(d.data()); + messages.append(d.squeezedData()); + d.clear(); } while (m_functionCallPos != m_functionCallData.length() && (m_stack.empty() || m_functionCallData[m_functionCallPos].start < m_stack.top())) { const QV4::Profiling::FunctionCallProperties &props = m_functionCallData[m_functionCallPos]; - if (props.start > until) - return finalizeMessages(until, messages, props.start); - - appendMemoryEvents(props.start, messages); - - QQmlDebugPacket d_start; - d_start << props.start << RangeStart << Javascript; - messages.push_back(d_start.data()); - QQmlDebugPacket d_location; - d_location << props.start << RangeLocation << Javascript << props.file << props.line - << props.column; - messages.push_back(d_location.data()); - QQmlDebugPacket d_data; - d_data << props.start << RangeData << Javascript << props.name; - messages.push_back(d_data.data()); + if (props.start > until || messages.length() > s_numMessagesPerBatch) + return finalizeMessages(until, messages, props.start, d); + + appendMemoryEvents(props.start, messages, d); + + d << props.start << RangeStart << Javascript; + messages.push_back(d.squeezedData()); + d.clear(); + d << props.start << RangeLocation << Javascript << props.file << props.line + << props.column; + messages.push_back(d.squeezedData()); + d.clear(); + d << props.start << RangeData << Javascript << props.name; + messages.push_back(d.squeezedData()); + d.clear(); m_stack.push(props.end); ++m_functionCallPos; } if (m_stack.empty() && m_functionCallPos == m_functionCallData.length()) - return finalizeMessages(until, messages, -1); + return finalizeMessages(until, messages, -1, d); } } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h index 303ccab72c..f2985af98b 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h @@ -53,6 +53,7 @@ #include <private/qv4profiling_p.h> #include <private/qqmlabstractprofileradapter_p.h> +#include "qqmldebugpacket.h" #include <QStack> #include <QList> @@ -86,8 +87,9 @@ private: int m_functionCallPos; int m_memoryPos; QStack<qint64> m_stack; - qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages); - qint64 finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext); + qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages, QQmlDebugPacket &d); + qint64 finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext, + QQmlDebugPacket &d); static quint64 translateFeatures(quint64 qmlFeatures); }; diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp index 5ca64fda15..9a2afd367d 100644 --- a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp @@ -79,6 +79,7 @@ QQuickProfilerAdapter::~QQuickProfilerAdapter() static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, QList<QByteArray> &messages) { + QQmlDebugPacket ds; Q_ASSERT_X(((data.messageType | data.detailType) & (1 << 31)) == 0, Q_FUNC_INFO, "You can use at most 31 message types and 31 detail types."); for (uint decodedMessageType = 0; (data.messageType >> decodedMessageType) != 0; @@ -91,8 +92,6 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, if ((data.detailType & (1 << decodedDetailType)) == 0) continue; - //### using QDataStream is relatively expensive - QQmlDebugPacket ds; ds << data.time << decodedMessageType << decodedDetailType; switch (decodedMessageType) { @@ -145,7 +144,8 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); break; } - messages << ds.data(); + messages.append(ds.squeezedData()); + ds.clear(); } } } @@ -153,7 +153,7 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { while (next < m_data.size()) { - if (m_data[next].time <= until) + if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch) qQuickProfilerDataToByteArrays(m_data[next++], messages); else return m_data[next].time; diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index a5f9ed9a1a..bc259afaa4 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -186,6 +186,7 @@ private: QStringList m_clientPlugins; bool m_gotHello; bool m_blockingMode; + bool m_clientSupportsMultiPackets; QHash<QJSEngine *, EngineCondition> m_engineConditions; @@ -274,7 +275,8 @@ static void cleanupOnShutdown() QQmlDebugServerImpl::QQmlDebugServerImpl() : m_connection(0), m_gotHello(false), - m_blockingMode(false) + m_blockingMode(false), + m_clientSupportsMultiPackets(false) { static bool postRoutineAdded = false; if (!postRoutineAdded) { @@ -327,7 +329,6 @@ bool QQmlDebugServerImpl::open(const QVariantHash &configuration = QVariantHash( return true; } -#define qUsage qWarning().noquote().nospace void QQmlDebugServerImpl::parseArguments() { // format: qmljsdebugger=port:<port_from>[,port_to],host:<ip address>][,block] @@ -376,8 +377,9 @@ void QQmlDebugServerImpl::parseArguments() } else if (!services.isEmpty()) { services.append(strArgument); } else { - qUsage() << tr("QML Debugger: Invalid argument \"%1\" detected. Ignoring the same.") - .arg(strArgument); + const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." + " Ignoring the same.").arg(strArgument); + qWarning("%s", qPrintable(message)); } } @@ -389,43 +391,47 @@ void QQmlDebugServerImpl::parseArguments() else m_thread.setPortRange(portFrom, portTo, hostAddress); } else { - qUsage() << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args); - qUsage() << tr("The format is \"-qmljsdebugger=[file:<file>|port:<port_from>][,<port_to>]" - "[,host:<ip address>][,block][,services:<service>][,<service>]*\"\n"); - qUsage() << tr("\"file:\" can be used to specify the name of a file the debugger will try " - "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" - "\"port:\" arguments will be ignored.\n"); - qUsage() << tr("\"host:\" and \"port:\" can be used to specify an address and a single " - "port or a range of ports the debugger will try to bind to with a " - "QTcpServer.\n"); - qUsage() << tr("\"block\" makes the debugger and some services wait for clients to be " - "connected and ready before the first QML engine starts.\n"); - qUsage() << tr("\"services:\" can be used to specify which debug services the debugger " - "should load. Some debug services interact badly with others. The V4 " - "debugger should not be loaded when using the QML profiler as it will force " - "any V4 engines to use the JavaScript interpreter rather than the JIT. The " - "following debug services are available by default:"); - qUsage() << QQmlEngineDebugService::s_key << tr("\t- The QML debugger"); - qUsage() << QV4DebugService::s_key << tr("\t- The V4 debugger"); - qUsage() << QQmlInspectorService::s_key << tr("\t- The QML inspector"); - qUsage() << QQmlProfilerService::s_key << tr("\t- The QML profiler"); - qUsage() << QQmlEngineControlService::s_key - << tr("\t- Allows the client to delay the starting and stopping of\n" - "\t\t QML engines until other services are ready. QtCreator\n" - "\t\t uses this service with the QML profiler in order to\n" - "\t\t profile multiple QML engines at the same time."); - qUsage() << QDebugMessageService::s_key - << tr("\t- Sends qDebug() and similar messages over the QML debug\n" - "\t\t connection. QtCreator uses this for showing debug\n" - "\t\t messages in the JavaScript console."); - qUsage() << tr("Other services offered by qmltooling plugins that implement " - "QQmlDebugServiceFactory and which can be found in the standard plugin " - "paths will also be available and can be specified. If no \"services\" " - "argument is given, all services found this way, including the default " - "ones, are loaded."); + QString usage; + QTextStream str(&usage); + str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n' + << tr("The format is \"-qmljsdebugger=[file:<file>|port:<port_from>][,<port_to>]" + "[,host:<ip address>][,block][,services:<service>][,<service>]*\"") << '\n' + << tr("\"file:\" can be used to specify the name of a file the debugger will try " + "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" + "\"port:\" arguments will be ignored.") << '\n' + << tr("\"host:\" and \"port:\" can be used to specify an address and a single " + "port or a range of ports the debugger will try to bind to with a " + "QTcpServer.") << '\n' + << tr("\"block\" makes the debugger and some services wait for clients to be " + "connected and ready before the first QML engine starts.") << '\n' + << tr("\"services:\" can be used to specify which debug services the debugger " + "should load. Some debug services interact badly with others. The V4 " + "debugger should not be loaded when using the QML profiler as it will force " + "any V4 engines to use the JavaScript interpreter rather than the JIT. The " + "following debug services are available by default:") << '\n' + << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n' + << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n' + << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n' + << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n' + << QQmlEngineControlService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Allows the client to delay the starting and stopping of\n" + "\t\t QML engines until other services are ready. QtCreator\n" + "\t\t uses this service with the QML profiler in order to\n" + "\t\t profile multiple QML engines at the same time.") + << '\n' << QDebugMessageService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Sends qDebug() and similar messages over the QML debug\n" + "\t\t connection. QtCreator uses this for showing debug\n" + "\t\t messages in the JavaScript console.") << '\n' + << tr("Other services offered by qmltooling plugins that implement " + "QQmlDebugServiceFactory and which can be found in the standard plugin " + "paths will also be available and can be specified. If no \"services\" " + "argument is given, all services found this way, including the default " + "ones, are loaded."); + qWarning("%s", qPrintable(usage)); } } -#undef qUsage void QQmlDebugServerImpl::receiveMessage() { @@ -456,6 +462,11 @@ void QQmlDebugServerImpl::receiveMessage() s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion; } + if (!in.atEnd()) + in >> m_clientSupportsMultiPackets; + else + m_clientSupportsMultiPackets = false; + // Send the hello answer immediately, since it needs to arrive before // the plugins below start sending messages. @@ -516,14 +527,16 @@ void QQmlDebugServerImpl::receiveMessage() } else { if (m_gotHello) { - QByteArray message; - in >> message; - QHash<QString, QQmlDebugService *>::Iterator iter = m_plugins.find(name); if (iter == m_plugins.end()) { qWarning() << "QML Debugger: Message received for missing plugin" << name << '.'; } else { - (*iter)->messageReceived(message); + QQmlDebugService *service = *iter; + QByteArray message; + while (!in.atEnd()) { + in >> message; + service->messageReceived(message); + } } } else { qWarning("QML Debugger: Invalid hello message."); @@ -686,8 +699,16 @@ void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &mes void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArray> &messages) { if (canSendMessage(name)) { - foreach (const QByteArray &message, messages) - doSendMessage(name, message); + if (m_clientSupportsMultiPackets) { + QQmlDebugPacket out; + out << name; + foreach (const QByteArray &message, messages) + out << message; + m_protocol->send(out.data()); + } else { + foreach (const QByteArray &message, messages) + doSendMessage(name, message); + } m_connection->flush(); } } diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index a34c1cbf0e..1960f1d65b 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1589,7 +1589,9 @@ enum MetaObjectResolverFlags { static void initMetaObjectResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlPropertyCache *metaObject); -static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member) +static QV4::IR::DiscoveredType resolveQmlType(QQmlEnginePrivate *qmlEngine, + const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) { QV4::IR::Type result = QV4::IR::VarType; @@ -1600,7 +1602,6 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe int value = type->enumValue(qmlEngine, *member->name, &ok); if (ok) { member->setEnumValue(value); - resolver->clear(); return QV4::IR::SInt32Type; } } @@ -1611,25 +1612,30 @@ static QV4::IR::Type resolveQmlType(QQmlEnginePrivate *qmlEngine, QV4::IR::Membe tdata->release(); // Decrease the reference count added from QQmlTypeLoader::getType() // When a singleton tries to reference itself, it may not be complete yet. if (tdata->isComplete()) { - initMetaObjectResolver(resolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId)); - resolver->flags |= AllPropertiesAreFinal; - return resolver->resolveMember(qmlEngine, resolver, member); + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, qmlEngine->propertyCacheForType(tdata->compiledData()->metaTypeId)); + newResolver->flags |= AllPropertiesAreFinal; + return newResolver->resolveMember(qmlEngine, newResolver, member); } } else if (type->isSingleton()) { const QMetaObject *singletonMeta = type->singletonInstanceInfo()->instanceMetaObject; if (singletonMeta) { // QJSValue-based singletons cannot be accelerated - initMetaObjectResolver(resolver, qmlEngine->cache(singletonMeta)); + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, qmlEngine->cache(singletonMeta)); member->kind = QV4::IR::Member::MemberOfSingletonObject; - return resolver->resolveMember(qmlEngine, resolver, member); + return newResolver->resolveMember(qmlEngine, newResolver, member); } } else if (const QMetaObject *attachedMeta = type->attachedPropertiesType(qmlEngine)) { QQmlPropertyCache *cache = qmlEngine->cache(attachedMeta); - initMetaObjectResolver(resolver, cache); + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, cache); member->setAttachedPropertiesId(type->attachedPropertiesId(qmlEngine)); - return resolver->resolveMember(qmlEngine, resolver, member); + return newResolver->resolveMember(qmlEngine, newResolver, member); } - resolver->clear(); return result; } @@ -1643,7 +1649,9 @@ static void initQmlTypeResolver(QV4::IR::MemberExpressionResolver *resolver, QQm resolver->flags = 0; } -static QV4::IR::Type resolveImportNamespace(QQmlEnginePrivate *, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member) +static QV4::IR::DiscoveredType resolveImportNamespace( + QQmlEnginePrivate *, const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) { QV4::IR::Type result = QV4::IR::VarType; QQmlTypeNameCache *typeNamespace = static_cast<QQmlTypeNameCache*>(resolver->extraData); @@ -1660,19 +1668,21 @@ static QV4::IR::Type resolveImportNamespace(QQmlEnginePrivate *, QV4::IR::Member // through the singleton getter in the run-time. Until then we // can't accelerate access :( if (!r.type->isSingleton()) { - initQmlTypeResolver(resolver, r.type); - return QV4::IR::QObjectType; + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initQmlTypeResolver(newResolver, r.type); + return QV4::IR::DiscoveredType(newResolver); } } else { Q_ASSERT(false); // How can this happen? } } - resolver->clear(); return result; } -static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver, QQmlTypeNameCache *imports, const void *importNamespace) +static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resolver, + QQmlTypeNameCache *imports, const void *importNamespace) { resolver->resolveMember = &resolveImportNamespace; resolver->data = const_cast<void*>(importNamespace); @@ -1680,7 +1690,9 @@ static void initImportNamespaceResolver(QV4::IR::MemberExpressionResolver *resol resolver->flags = 0; } -static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4::IR::MemberExpressionResolver *resolver, QV4::IR::Member *member) +static QV4::IR::DiscoveredType resolveMetaObjectProperty( + QQmlEnginePrivate *qmlEngine, const QV4::IR::MemberExpressionResolver *resolver, + QV4::IR::Member *member) { QV4::IR::Type result = QV4::IR::VarType; QQmlPropertyCache *metaObject = static_cast<QQmlPropertyCache*>(resolver->data); @@ -1694,7 +1706,6 @@ static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4 int value = metaEnum.keyToValue(enumName.constData(), &ok); if (ok) { member->setEnumValue(value); - resolver->clear(); return QV4::IR::SInt32Type; } } @@ -1739,21 +1750,25 @@ static QV4::IR::Type resolveMetaObjectProperty(QQmlEnginePrivate *qmlEngine, QV4 default: if (property->isQObject()) { if (QQmlPropertyCache *cache = qmlEngine->propertyCacheForType(property->propType)) { - initMetaObjectResolver(resolver, cache); - return QV4::IR::QObjectType; + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, cache); + return QV4::IR::DiscoveredType(newResolver); } } else if (const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(property->propType)) { if (QQmlPropertyCache *cache = qmlEngine->cache(valueTypeMetaObject)) { - initMetaObjectResolver(resolver, cache); - resolver->flags |= ResolveTypeInformationOnly; - return QV4::IR::QObjectType; + auto newResolver = resolver->owner->New<QV4::IR::MemberExpressionResolver>(); + newResolver->owner = resolver->owner; + initMetaObjectResolver(newResolver, cache); + newResolver->flags |= ResolveTypeInformationOnly; + return QV4::IR::DiscoveredType(newResolver); } } break; } } } - resolver->clear(); + return result; } @@ -1809,6 +1824,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int result = _block->TEMP(result->index); if (mapping.type) { result->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); + result->memberResolver->owner = _function; initMetaObjectResolver(result->memberResolver, mapping.type); result->memberResolver->flags |= AllPropertiesAreFinal; } @@ -1831,6 +1847,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int result = _block->TEMP(result->index); result->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); + result->memberResolver->owner = _function; initQmlTypeResolver(result->memberResolver, r.type); return result; } else { @@ -1839,6 +1856,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int namespaceName->freeOfSideEffects = true; QV4::IR::Temp *result = _block->TEMP(_block->newTemp()); result->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); + result->memberResolver->owner = _function; initImportNamespaceResolver(result->memberResolver, imports, r.importNamespace); _block->MOVE(result, namespaceName); @@ -1855,6 +1873,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (pd) { QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); + base->memberResolver->owner = _function; initMetaObjectResolver(base->memberResolver, _scopeObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlScopeObject); } @@ -1868,6 +1887,7 @@ QV4::IR::Expr *JSCodeGen::fallbackNameLookup(const QString &name, int line, int if (pd) { QV4::IR::Temp *base = _block->TEMP(_qmlContextTemp); base->memberResolver = _function->New<QV4::IR::MemberExpressionResolver>(); + base->memberResolver->owner = _function; initMetaObjectResolver(base->memberResolver, _contextObject); return _block->MEMBER(base, _function->newString(name), pd, QV4::IR::Member::MemberOfQmlContextObject); } diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 33716d57b8..a71793f2b6 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -2731,8 +2731,8 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR: if (function->basicBlockCount() > 10) return false; - foreach (QV4::IR::BasicBlock *bb, function->basicBlocks()) { - foreach (QV4::IR::Stmt *s, bb->statements()) { + for (QV4::IR::BasicBlock *bb : function->basicBlocks()) { + for (QV4::IR::Stmt *s : bb->statements()) { s->accept(this); if (!_canSimplify) return false; @@ -2901,8 +2901,8 @@ void QQmlIRFunctionCleanser::clean() module->functions = newFunctions; foreach (QV4::IR::Function *function, module->functions) { - foreach (QV4::IR::BasicBlock *block, function->basicBlocks()) { - foreach (QV4::IR::Stmt *s, block->statements()) { + for (QV4::IR::BasicBlock *block : function->basicBlocks()) { + for (QV4::IR::Stmt *s : block->statements()) { s->accept(this); } } diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index b3468848ca..be10d50e9b 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -255,16 +255,16 @@ protected: if (IR::Jump *jump = s->asJump()) { IR::MoveMapping moves; - foreach (IR::Stmt *succStmt, jump->target->statements()) { + for (IR::Stmt *succStmt : jump->target->statements()) { if (IR::Phi *phi = succStmt->asPhi()) { forceActivation(*phi->targetTemp); - for (int i = 0, ei = phi->d->incoming.size(); i != ei; ++i) { - IR::Expr *e = phi->d->incoming[i]; + for (int i = 0, ei = phi->incoming.size(); i != ei; ++i) { + IR::Expr *e = phi->incoming[i]; if (IR::Temp *t = e->asTemp()) { forceActivation(*t); } if (jump->target->in[i] == _currentBasicBlock) - moves.add(phi->d->incoming[i], phi->targetTemp); + moves.add(phi->incoming[i], phi->targetTemp); } } else { break; @@ -303,7 +303,7 @@ protected: #if !defined(QT_NO_DEBUG) Q_ASSERT(_stackSlotForTemp.contains(phi->targetTemp->index)); Q_ASSERT(_slotIsInUse[_stackSlotForTemp[phi->targetTemp->index]]); - foreach (IR::Expr *e, phi->d->incoming) { + foreach (IR::Expr *e, phi->incoming) { if (IR::Temp *t = e->asTemp()) Q_ASSERT(_stackSlotForTemp.contains(t->index)); } @@ -385,7 +385,7 @@ void InstructionSelection::run(int functionIndex) addInstruction(push); currentLine = 0; - QVector<IR::BasicBlock *> basicBlocks = _function->basicBlocks(); + const QVector<IR::BasicBlock *> &basicBlocks = _function->basicBlocks(); for (int i = 0, ei = basicBlocks.size(); i != ei; ++i) { blockNeedsDebugInstruction = irModule->debugMode; _block = basicBlocks[i]; @@ -404,7 +404,7 @@ void InstructionSelection::run(int functionIndex) exceptionHandler = _block->catchBlock; } - foreach (IR::Stmt *s, _block->statements()) { + for (IR::Stmt *s : _block->statements()) { _currentStatement = s; if (s->location.isValid()) { diff --git a/src/qml/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 9ef3ef6721..674fc01623 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -145,11 +145,11 @@ public: { _stackSlotForTemp.reserve(function->tempCount); - foreach (IR::BasicBlock *bb, function->basicBlocks()) { + for (IR::BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; _currentBasicBlock = bb; - foreach (IR::Stmt *s, bb->statements()) + for (IR::Stmt *s : bb->statements()) process(s); } diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index 4c87b7557e..b28db59190 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -511,344 +511,23 @@ void Function::setStatementCount(int cnt) _statementCount = cnt; } -BasicBlock::~BasicBlock() -{ - for (Stmt *s : qAsConst(_statements)) { - Phi *p = s->asPhi(); - if (p) - p->destroyData(); - } -} - -unsigned BasicBlock::newTemp() -{ - Q_ASSERT(!isRemoved()); - return function->tempCount++; -} - -Temp *BasicBlock::TEMP(unsigned index) -{ - Q_ASSERT(!isRemoved()); - Temp *e = function->New<Temp>(); - e->init(Temp::VirtualRegister, index); - return e; -} - -ArgLocal *BasicBlock::ARG(unsigned index, unsigned scope) -{ - Q_ASSERT(!isRemoved()); - ArgLocal *e = function->New<ArgLocal>(); - e->init(scope ? ArgLocal::ScopedFormal : ArgLocal::Formal, index, scope); - return e; -} - -ArgLocal *BasicBlock::LOCAL(unsigned index, unsigned scope) -{ - Q_ASSERT(!isRemoved()); - ArgLocal *e = function->New<ArgLocal>(); - e->init(scope ? ArgLocal::ScopedLocal : ArgLocal::Local, index, scope); - return e; -} - -Expr *BasicBlock::CONST(Type type, double value) -{ - Q_ASSERT(!isRemoved()); - Const *e = function->New<Const>(); - if (type == NumberType) { - int ival = (int)value; - // +0 != -0, so we need to convert to double when negating 0 - if (ival == value && !(value == 0 && isNegative(value))) - type = SInt32Type; - else - type = DoubleType; - } else if (type == NullType) { - value = 0; - } else if (type == UndefinedType) { - value = qQNaN(); - } - - e->init(type, value); - return e; -} - -Expr *BasicBlock::STRING(const QString *value) -{ - Q_ASSERT(!isRemoved()); - String *e = function->New<String>(); - e->init(value); - return e; -} - -Expr *BasicBlock::REGEXP(const QString *value, int flags) -{ - Q_ASSERT(!isRemoved()); - RegExp *e = function->New<RegExp>(); - e->init(value, flags); - return e; -} - -Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column) -{ - Q_ASSERT(!isRemoved()); - Name *e = function->New<Name>(); - e->init(function->newString(id), line, column); - return e; -} - -Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column) -{ - Q_ASSERT(!isRemoved()); - Name *e = function->New<Name>(); - e->initGlobal(function->newString(id), line, column); - return e; -} - - -Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column) -{ - Q_ASSERT(!isRemoved()); - Name *e = function->New<Name>(); - e->init(builtin, line, column); - return e; -} - -Closure *BasicBlock::CLOSURE(int functionInModule) -{ - Q_ASSERT(!isRemoved()); - Closure *clos = function->New<Closure>(); - clos->init(functionInModule, function->module->functions.at(functionInModule)->name); - return clos; -} - -Expr *BasicBlock::CONVERT(Expr *expr, Type type) -{ - Q_ASSERT(!isRemoved()); - Convert *e = function->New<Convert>(); - e->init(expr, type); - return e; -} - -Expr *BasicBlock::UNOP(AluOp op, Expr *expr) -{ - Q_ASSERT(!isRemoved()); - Unop *e = function->New<Unop>(); - e->init(op, expr); - return e; -} - -Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right) -{ - Q_ASSERT(!isRemoved()); - Binop *e = function->New<Binop>(); - e->init(op, left, right); - return e; -} - -Expr *BasicBlock::CALL(Expr *base, ExprList *args) -{ - Q_ASSERT(!isRemoved()); - Call *e = function->New<Call>(); - e->init(base, args); - int argc = 0; - for (ExprList *it = args; it; it = it->next) - ++argc; - function->maxNumberOfArguments = qMax(function->maxNumberOfArguments, argc); - return e; -} - -Expr *BasicBlock::NEW(Expr *base, ExprList *args) -{ - Q_ASSERT(!isRemoved()); - New *e = function->New<New>(); - e->init(base, args); - return e; -} - -Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index) -{ - Q_ASSERT(!isRemoved()); - Subscript *e = function->New<Subscript>(); - e->init(base, index); - return e; -} - -Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue) -{ - Q_ASSERT(!isRemoved()); - Member*e = function->New<Member>(); - e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue); - return e; -} - -Stmt *BasicBlock::EXP(Expr *expr) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Exp *s = function->NewStmt<Exp>(); - s->init(expr); - appendStatement(s); - return s; -} - -Stmt *BasicBlock::MOVE(Expr *target, Expr *source) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Move *s = function->NewStmt<Move>(); - s->init(target, source); - appendStatement(s); - return s; -} - -Stmt *BasicBlock::JUMP(BasicBlock *target) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Jump *s = function->NewStmt<Jump>(); - s->init(target); - appendStatement(s); - - Q_ASSERT(! out.contains(target)); - out.append(target); - - Q_ASSERT(! target->in.contains(this)); - target->in.append(this); - - return s; -} - -Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - if (iftrue == iffalse) { - MOVE(TEMP(newTemp()), cond); - return JUMP(iftrue); - } - - CJump *s = function->NewStmt<CJump>(); - s->init(cond, iftrue, iffalse, this); - appendStatement(s); - - Q_ASSERT(! out.contains(iftrue)); - out.append(iftrue); - - Q_ASSERT(! iftrue->in.contains(this)); - iftrue->in.append(this); - - Q_ASSERT(! out.contains(iffalse)); - out.append(iffalse); - - Q_ASSERT(! iffalse->in.contains(this)); - iffalse->in.append(this); - - return s; -} - -Stmt *BasicBlock::RET(Expr *expr) -{ - Q_ASSERT(!isRemoved()); - if (isTerminated()) - return 0; - - Ret *s = function->NewStmt<Ret>(); - s->init(expr); - appendStatement(s); - return s; -} - void BasicBlock::setStatements(const QVector<Stmt *> &newStatements) { Q_ASSERT(!isRemoved()); Q_ASSERT(newStatements.size() >= _statements.size()); - // FIXME: this gets quite inefficient for large basic-blocks, so this function/case should be re-worked. for (Stmt *s : qAsConst(_statements)) { - Phi *p = s->asPhi(); - if (!p) - continue; - - if (!newStatements.contains(p)) - p->destroyData(); + if (Phi *p = s->asPhi()) { + if (!newStatements.contains(p)) { + // phi-node was not copied over, so: + p->destroyData(); + } + } else { + break; + } } _statements = newStatements; } -void BasicBlock::appendStatement(Stmt *statement) -{ - Q_ASSERT(!isRemoved()); - if (nextLocation.startLine) - statement->location = nextLocation; - _statements.append(statement); -} - -void BasicBlock::prependStatement(Stmt *stmt) -{ - Q_ASSERT(!isRemoved()); - _statements.prepend(stmt); -} - -void BasicBlock::prependStatements(const QVector<Stmt *> &stmts) -{ - Q_ASSERT(!isRemoved()); - QVector<Stmt *> newStmts = stmts; - newStmts += _statements; - _statements = newStmts; -} - -void BasicBlock::insertStatementBefore(Stmt *before, Stmt *newStmt) -{ - int idx = _statements.indexOf(before); - Q_ASSERT(idx >= 0); - _statements.insert(idx, newStmt); -} - -void BasicBlock::insertStatementBefore(int index, Stmt *newStmt) -{ - Q_ASSERT(index >= 0); - _statements.insert(index, newStmt); -} - -void BasicBlock::insertStatementBeforeTerminator(Stmt *stmt) -{ - Q_ASSERT(!isRemoved()); - _statements.insert(_statements.size() - 1, stmt); -} - -void BasicBlock::replaceStatement(int index, Stmt *newStmt) -{ - Q_ASSERT(!isRemoved()); - Phi *p = _statements[index]->asPhi(); - if (p) - p->destroyData(); - _statements[index] = newStmt; -} - -void BasicBlock::removeStatement(Stmt *stmt) -{ - Q_ASSERT(!isRemoved()); - Phi *p = stmt->asPhi(); - if (p) - p->destroyData(); - _statements.remove(_statements.indexOf(stmt)); -} - -void BasicBlock::removeStatement(int idx) -{ - Q_ASSERT(!isRemoved()); - Phi *p = _statements[idx]->asPhi(); - if (p) - p->destroyData(); - _statements.remove(idx); -} - CloneExpr::CloneExpr(BasicBlock *block) : block(block), cloned(0) { @@ -1084,13 +763,13 @@ void IRPrinter::visitPhi(Phi *s) s->targetTemp->accept(this); *out << " = phi "; - for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) { + for (int i = 0, ei = s->incoming.size(); i < ei; ++i) { if (i > 0) *out << ", "; if (currentBB) *out << 'L' << currentBB->in.at(i)->index() << ": "; - if (s->d->incoming[i]) - s->d->incoming[i]->accept(this); + if (s->incoming[i]) + s->incoming[i]->accept(this); } } diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 974e8dfe0d..eafecae494 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -244,13 +244,37 @@ struct StmtVisitor { virtual void visitPhi(Phi *) = 0; }; +struct MemberExpressionResolver; + +struct DiscoveredType { + int type; + MemberExpressionResolver *memberResolver; + + DiscoveredType() : type(UnknownType), memberResolver(0) {} + DiscoveredType(Type t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } + explicit DiscoveredType(int t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } + explicit DiscoveredType(MemberExpressionResolver *memberResolver) + : type(QObjectType) + , memberResolver(memberResolver) + { Q_ASSERT(memberResolver); } + + bool test(Type t) const { return type & t; } + bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); } + + bool operator!=(Type other) const { return type != other; } + bool operator==(Type other) const { return type == other; } + bool operator==(const DiscoveredType &other) const { return type == other.type; } + bool operator!=(const DiscoveredType &other) const { return type != other.type; } +}; struct MemberExpressionResolver { - typedef Type (*ResolveFunction)(QQmlEnginePrivate *engine, MemberExpressionResolver *resolver, Member *member); + typedef DiscoveredType (*ResolveFunction)(QQmlEnginePrivate *engine, + const MemberExpressionResolver *resolver, + Member *member); MemberExpressionResolver() - : resolveMember(0), data(0), extraData(0), flags(0) {} + : resolveMember(0), data(0), extraData(0), owner(nullptr), flags(0) {} bool isValid() const { return !!resolveMember; } void clear() { *this = MemberExpressionResolver(); } @@ -258,6 +282,7 @@ struct MemberExpressionResolver ResolveFunction resolveMember; void *data; // Could be pointer to meta object, importNameSpace, etc. - depends on resolveMember implementation void *extraData; // Could be QQmlTypeNameCache + Function *owner; unsigned int flags; }; @@ -751,23 +776,21 @@ struct Ret: Stmt { virtual Ret *asRet() { return this; } }; +// Phi nodes can only occur at the start of a basic block. If there are any, they need to be +// subsequent to eachother, and the first phi node should be the first statement in the basic-block. +// A number of loops rely on this behavior, so they don't need to walk through the whole list +// of instructions in a basic-block (e.g. the calls to destroyData in BasicBlock::~BasicBlock). struct Phi: Stmt { Temp *targetTemp; - struct Data { - QVector<Expr *> incoming; // used by Phi nodes - }; + VarLengthArray<Expr *, 4> incoming; - Data *d; - - Phi(int id): Stmt(id), d(0) {} + Phi(int id): Stmt(id) {} virtual void accept(StmtVisitor *v) { v->visitPhi(this); } virtual Phi *asPhi() { return this; } - void destroyData() { - delete d; - d = 0; - } + void destroyData() + { incoming.~VarLengthArray(); } }; struct Q_QML_PRIVATE_EXPORT Module { @@ -813,7 +836,17 @@ public: , _groupStart(false) , _isRemoved(false) {} - ~BasicBlock(); + + ~BasicBlock() + { + for (Stmt *s : qAsConst(_statements)) { + if (Phi *p = s->asPhi()) { + p->destroyData(); + } else { + break; + } + } + } const QVector<Stmt *> &statements() const { @@ -836,15 +869,73 @@ public: return i; } - void appendStatement(Stmt *statement); - void prependStatement(Stmt *stmt); - void prependStatements(const QVector<Stmt *> &stmts); - void insertStatementBefore(Stmt *before, Stmt *newStmt); - void insertStatementBefore(int index, Stmt *newStmt); - void insertStatementBeforeTerminator(Stmt *stmt); - void replaceStatement(int index, Stmt *newStmt); - void removeStatement(Stmt *stmt); - void removeStatement(int idx); + void appendStatement(Stmt *statement) + { + Q_ASSERT(!isRemoved()); + if (nextLocation.startLine) + statement->location = nextLocation; + _statements.append(statement); + } + + void prependStatement(Stmt *stmt) + { + Q_ASSERT(!isRemoved()); + _statements.prepend(stmt); + } + + void prependStatements(const QVector<Stmt *> &stmts) + { + Q_ASSERT(!isRemoved()); + QVector<Stmt *> newStmts = stmts; + newStmts += _statements; + _statements = newStmts; + } + + void insertStatementBefore(Stmt *before, Stmt *newStmt) + { + int idx = _statements.indexOf(before); + Q_ASSERT(idx >= 0); + _statements.insert(idx, newStmt); + } + + void insertStatementBefore(int index, Stmt *newStmt) + { + Q_ASSERT(index >= 0); + _statements.insert(index, newStmt); + } + + void insertStatementBeforeTerminator(Stmt *stmt) + { + Q_ASSERT(!isRemoved()); + _statements.insert(_statements.size() - 1, stmt); + } + + void replaceStatement(int index, Stmt *newStmt) + { + Q_ASSERT(!isRemoved()); + if (Phi *p = _statements[index]->asPhi()) { + p->destroyData(); + } + _statements[index] = newStmt; + } + + void removeStatement(Stmt *stmt) + { + Q_ASSERT(!isRemoved()); + if (Phi *p = stmt->asPhi()) { + p->destroyData(); + } + _statements.remove(_statements.indexOf(stmt)); + } + + void removeStatement(int idx) + { + Q_ASSERT(!isRemoved()); + if (Phi *p = _statements[idx]->asPhi()) { + p->destroyData(); + } + _statements.remove(idx); + } inline bool isEmpty() const { Q_ASSERT(!isRemoved()); @@ -1209,6 +1300,251 @@ protected: BasicBlock *currentBB; }; +inline unsigned BasicBlock::newTemp() +{ + Q_ASSERT(!isRemoved()); + return function->tempCount++; +} + +inline Temp *BasicBlock::TEMP(unsigned index) +{ + Q_ASSERT(!isRemoved()); + Temp *e = function->New<Temp>(); + e->init(Temp::VirtualRegister, index); + return e; +} + +inline ArgLocal *BasicBlock::ARG(unsigned index, unsigned scope) +{ + Q_ASSERT(!isRemoved()); + ArgLocal *e = function->New<ArgLocal>(); + e->init(scope ? ArgLocal::ScopedFormal : ArgLocal::Formal, index, scope); + return e; +} + +inline ArgLocal *BasicBlock::LOCAL(unsigned index, unsigned scope) +{ + Q_ASSERT(!isRemoved()); + ArgLocal *e = function->New<ArgLocal>(); + e->init(scope ? ArgLocal::ScopedLocal : ArgLocal::Local, index, scope); + return e; +} + +inline Expr *BasicBlock::CONST(Type type, double value) +{ + Q_ASSERT(!isRemoved()); + Const *e = function->New<Const>(); + if (type == NumberType) { + int ival = (int)value; + // +0 != -0, so we need to convert to double when negating 0 + if (ival == value && !(value == 0 && isNegative(value))) + type = SInt32Type; + else + type = DoubleType; + } else if (type == NullType) { + value = 0; + } else if (type == UndefinedType) { + value = qQNaN(); + } + + e->init(type, value); + return e; +} + +inline Expr *BasicBlock::STRING(const QString *value) +{ + Q_ASSERT(!isRemoved()); + String *e = function->New<String>(); + e->init(value); + return e; +} + +inline Expr *BasicBlock::REGEXP(const QString *value, int flags) +{ + Q_ASSERT(!isRemoved()); + RegExp *e = function->New<RegExp>(); + e->init(value, flags); + return e; +} + +inline Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column) +{ + Q_ASSERT(!isRemoved()); + Name *e = function->New<Name>(); + e->init(function->newString(id), line, column); + return e; +} + +inline Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column) +{ + Q_ASSERT(!isRemoved()); + Name *e = function->New<Name>(); + e->initGlobal(function->newString(id), line, column); + return e; +} + + +inline Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column) +{ + Q_ASSERT(!isRemoved()); + Name *e = function->New<Name>(); + e->init(builtin, line, column); + return e; +} + +inline Closure *BasicBlock::CLOSURE(int functionInModule) +{ + Q_ASSERT(!isRemoved()); + Closure *clos = function->New<Closure>(); + clos->init(functionInModule, function->module->functions.at(functionInModule)->name); + return clos; +} + +inline Expr *BasicBlock::CONVERT(Expr *expr, Type type) +{ + Q_ASSERT(!isRemoved()); + Convert *e = function->New<Convert>(); + e->init(expr, type); + return e; +} + +inline Expr *BasicBlock::UNOP(AluOp op, Expr *expr) +{ + Q_ASSERT(!isRemoved()); + Unop *e = function->New<Unop>(); + e->init(op, expr); + return e; +} + +inline Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right) +{ + Q_ASSERT(!isRemoved()); + Binop *e = function->New<Binop>(); + e->init(op, left, right); + return e; +} + +inline Expr *BasicBlock::CALL(Expr *base, ExprList *args) +{ + Q_ASSERT(!isRemoved()); + Call *e = function->New<Call>(); + e->init(base, args); + int argc = 0; + for (ExprList *it = args; it; it = it->next) + ++argc; + function->maxNumberOfArguments = qMax(function->maxNumberOfArguments, argc); + return e; +} + +inline Expr *BasicBlock::NEW(Expr *base, ExprList *args) +{ + Q_ASSERT(!isRemoved()); + New *e = function->New<New>(); + e->init(base, args); + return e; +} + +inline Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index) +{ + Q_ASSERT(!isRemoved()); + Subscript *e = function->New<Subscript>(); + e->init(base, index); + return e; +} + +inline Expr *BasicBlock::MEMBER(Expr *base, const QString *name, QQmlPropertyData *property, uchar kind, int attachedPropertiesIdOrEnumValue) +{ + Q_ASSERT(!isRemoved()); + Member*e = function->New<Member>(); + e->init(base, name, property, kind, attachedPropertiesIdOrEnumValue); + return e; +} + +inline Stmt *BasicBlock::EXP(Expr *expr) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Exp *s = function->NewStmt<Exp>(); + s->init(expr); + appendStatement(s); + return s; +} + +inline Stmt *BasicBlock::MOVE(Expr *target, Expr *source) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Move *s = function->NewStmt<Move>(); + s->init(target, source); + appendStatement(s); + return s; +} + +inline Stmt *BasicBlock::JUMP(BasicBlock *target) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Jump *s = function->NewStmt<Jump>(); + s->init(target); + appendStatement(s); + + Q_ASSERT(! out.contains(target)); + out.append(target); + + Q_ASSERT(! target->in.contains(this)); + target->in.append(this); + + return s; +} + +inline Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + if (iftrue == iffalse) { + MOVE(TEMP(newTemp()), cond); + return JUMP(iftrue); + } + + CJump *s = function->NewStmt<CJump>(); + s->init(cond, iftrue, iffalse, this); + appendStatement(s); + + Q_ASSERT(! out.contains(iftrue)); + out.append(iftrue); + + Q_ASSERT(! iftrue->in.contains(this)); + iftrue->in.append(this); + + Q_ASSERT(! out.contains(iffalse)); + out.append(iffalse); + + Q_ASSERT(! iffalse->in.contains(this)); + iffalse->in.append(this); + + return s; +} + +inline Stmt *BasicBlock::RET(Expr *expr) +{ + Q_ASSERT(!isRemoved()); + if (isTerminated()) + return 0; + + Ret *s = function->NewStmt<Ret>(); + s->init(expr); + appendStatement(s); + return s; +} + } // end of namespace IR } // end of namespace QV4 diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 7881ab951a..6a4c1c54d6 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -56,7 +56,6 @@ #include <cmath> #include <iostream> #include <cassert> -#include <algorithm> QT_USE_NAMESPACE @@ -87,120 +86,6 @@ static void showMeTheCode(IR::Function *function, const char *marker) } } -#if !defined(BROKEN_STD_VECTOR_BOOL_OR_BROKEN_STD_FIND) -// Sanity: -class BitVector -{ - std::vector<bool> bits; - -public: - BitVector(int size = 0, bool value = false) - : bits(size, value) - {} - - void reserve(int size) - { bits.reserve(size); } - - int size() const - { - Q_ASSERT(bits.size() < INT_MAX); - return static_cast<int>(bits.size()); - } - - void resize(int newSize) - { bits.resize(newSize); } - - void assign(int newSize, bool value) - { bits.assign(newSize, value); } - - int findNext(int start, bool value, bool wrapAround) const - { - // The ++operator of std::vector<bool>::iterator in libc++ has a bug when using it on an - // iterator pointing to the last element. It will not be set to ::end(), but beyond - // that. (It will be set to the first multiple of the native word size that is bigger - // than size().) - // - // See http://llvm.org/bugs/show_bug.cgi?id=19663 - // - // The work-around is to calculate the distance, and compare it to the size() to see if it's - // beyond the end, or take the minimum of the distance and the size. - - size_t pos = std::distance(bits.begin(), - std::find(bits.begin() + start, bits.end(), value)); - if (wrapAround && pos >= static_cast<size_t>(size())) - pos = std::distance(bits.begin(), - std::find(bits.begin(), bits.begin() + start, value)); - - pos = qMin(pos, static_cast<size_t>(size())); - - Q_ASSERT(pos <= static_cast<size_t>(size())); - Q_ASSERT(pos < INT_MAX); - - return static_cast<int>(pos); - } - - bool at(int idx) const - { return bits.at(idx); } - - void setBit(int idx) - { bits[idx] = true; } - - void clearBit(int idx) - { bits[idx] = false; } -}; -#else // Insanity: -class BitVector -{ - QBitArray bits; - -public: - BitVector(int size = 0, bool value = false) - : bits(size, value) - {} - - void reserve(int size) - { Q_UNUSED(size); } - - int size() const - { return bits.size(); } - - void resize(int newSize) - { bits.resize(newSize); } - - void assign(int newSize, bool value) - { - bits.resize(newSize); - bits.fill(value); - } - - int findNext(int start, bool value, bool wrapAround) const - { - for (int i = start, ei = size(); i < ei; ++i) { - if (at(i) == value) - return i; - } - - if (wrapAround) { - for (int i = 0, ei = start; i < ei; ++i) { - if (at(i) == value) - return i; - } - } - - return size(); - } - - bool at(int idx) const - { return bits.at(idx); } - - void setBit(int idx) - { bits[idx] = true; } - - void clearBit(int idx) - { bits[idx] = false; } -}; -#endif - class ProcessedBlocks { BitVector processed; @@ -557,7 +442,7 @@ class DominatorTree BasicBlockIndex p = d->parent[n]; BasicBlockIndex s = p; - foreach (BasicBlock *v, function->basicBlock(n)->in) { + for (BasicBlock *v : function->basicBlock(n)->in) { BasicBlockIndex ss = InvalidBasicBlockIndex; if (d->dfnum[v->index()] <= d->dfnum[n]) ss = v->index(); @@ -617,7 +502,7 @@ public: // compute children of each node in the dominator tree std::vector<std::vector<BasicBlockIndex> > children; // BasicBlock index -> children children.resize(function->basicBlockCount()); - foreach (BasicBlock *n, function->basicBlocks()) { + for (BasicBlock *n : function->basicBlocks()) { if (n->isRemoved()) continue; const BasicBlockIndex nodeIndex = n->index(); @@ -633,7 +518,7 @@ public: nodeStatus.resize(function->basicBlockCount()); std::vector<BasicBlockIndex> worklist; worklist.reserve(function->basicBlockCount()); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; BasicBlockIndex nodeIndex = bb->index(); @@ -667,7 +552,7 @@ public: if (np.todo.empty()) { BasicBlockSet &S = DF[node]; S.init(function); - foreach (BasicBlock *y, function->basicBlock(node)->out) + for (BasicBlock *y : function->basicBlock(node)->out) if (idom[y->index()] != node) S.insert(y); for (BasicBlockIndex child : np.children) { @@ -689,7 +574,7 @@ public: buf.open(QIODevice::WriteOnly); QTextStream qout(&buf); qout << "Dominator Frontiers:" << endl; - foreach (BasicBlock *n, function->basicBlocks()) { + for (BasicBlock *n : function->basicBlocks()) { if (n->isRemoved()) continue; @@ -706,7 +591,7 @@ public: } if (DebugDominatorFrontiers && DebugCodeCanUseLotsOfCpu) { - foreach (BasicBlock *n, function->basicBlocks()) { + for (BasicBlock *n : function->basicBlocks()) { if (n->isRemoved()) continue; const BasicBlockSet &fBlocks = DF[n->index()]; @@ -714,7 +599,7 @@ public: BasicBlock *fBlock = *it; Q_ASSERT(!dominates(n, fBlock) || fBlock == n); bool hasDominatedSucc = false; - foreach (BasicBlock *succ, fBlock->in) { + for (BasicBlock *succ : fBlock->in) { if (dominates(n, succ)) { hasDominatedSucc = true; break; @@ -747,7 +632,7 @@ public: buf.open(QIODevice::WriteOnly); QTextStream qout(&buf); qout << "Immediate dominators:" << endl; - foreach (BasicBlock *to, function->basicBlocks()) { + for (BasicBlock *to : function->basicBlocks()) { if (to->isRemoved()) continue; @@ -881,7 +766,7 @@ private: { std::vector<int> nodeDepths(size_t(function->basicBlockCount()), -1); nodeDepths[0] = 0; - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -945,8 +830,7 @@ private: std::vector<BasicBlockIndex> prefix; prefix.reserve(32); - for (int i = 0, ei = node->in.size(); i != ei; ++i) { - BasicBlock *in = node->in.at(i); + for (BasicBlock *in : node->in) { if (node == in) // back-edge to self continue; if (dominates(node->index(), in->index())) // a known back-edge @@ -1055,13 +939,13 @@ public: for (size_t i = 0; i != ei; ++i) A_orig[i].reserve(8); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; currentBB = bb; killed.assign(function->tempCount, false); - foreach (Stmt *s, bb->statements()) + for (Stmt *s : bb->statements()) s->accept(this); } } @@ -1381,16 +1265,15 @@ public: void insertPhiNode(const Temp &a, BasicBlock *y, IR::Function *f) { Phi *phiNode = f->NewStmt<Phi>(); - phiNode->d = new Phi::Data; phiNode->targetTemp = f->New<Temp>(); phiNode->targetTemp->init(a.kind, a.index); y->prependStatement(phiNode); - phiNode->d->incoming.resize(y->in.size()); + phiNode->incoming.resize(y->in.size()); for (int i = 0, ei = y->in.size(); i < ei; ++i) { Temp *t = f->New<Temp>(); t->init(a.kind, a.index); - phiNode->d->incoming[i] = t; + phiNode->incoming[i] = t; } } @@ -1565,7 +1448,7 @@ private: processed.markAsProcessed(bb); BasicBlock *next = 0; - foreach (BasicBlock *out, bb->out) { + for (BasicBlock *out : bb->out) { if (processed.alreadyProcessed(out)) continue; if (!next) @@ -1581,17 +1464,17 @@ private: { currentBB = bb; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { currentStmt = s; s->accept(this); } - foreach (BasicBlock *Y, bb->out) { + for (BasicBlock *Y : bb->out) { const int j = Y->in.indexOf(bb); Q_ASSERT(j >= 0 && j < Y->in.size()); - foreach (Stmt *s, Y->statements()) { + for (Stmt *s : Y->statements()) { if (Phi *phi = s->asPhi()) { - Temp *t = phi->d->incoming[j]->asTemp(); + Temp *t = phi->incoming[j]->asTemp(); unsigned newTmp = currentNumber(*t); // qDebug()<<"I: replacing phi use"<<a<<"with"<<newTmp<<"in L"<<Y->index; t->index = newTmp; @@ -1845,11 +1728,11 @@ public: { grow(); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (!s) continue; @@ -1905,7 +1788,7 @@ public: void applyToFunction() { - foreach (BasicBlock *bb, theFunction->basicBlocks()) { + for (BasicBlock *bb : theFunction->basicBlocks()) { if (bb->isRemoved()) continue; @@ -1979,6 +1862,11 @@ public: return worklistSize == 0; } + unsigned size() const + { + return worklistSize; + } + Stmt *takeNext(Stmt *last) { if (isEmpty()) @@ -2185,27 +2073,6 @@ protected: } }; -struct DiscoveredType { - int type; - MemberExpressionResolver *memberResolver; - - DiscoveredType() : type(UnknownType), memberResolver(0) {} - DiscoveredType(Type t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } - explicit DiscoveredType(int t) : type(t), memberResolver(0) { Q_ASSERT(type != QObjectType); } - explicit DiscoveredType(MemberExpressionResolver *memberResolver) - : type(QObjectType) - , memberResolver(memberResolver) - { Q_ASSERT(memberResolver); } - - bool test(Type t) const { return type & t; } - bool isNumber() const { return (type & NumberType) && !(type & ~NumberType); } - - bool operator!=(Type other) const { return type != other; } - bool operator==(Type other) const { return type == other; } - bool operator==(const DiscoveredType &other) const { return type == other.type; } - bool operator!=(const DiscoveredType &other) const { return type != other.type; } -}; - class PropagateTempTypes: public StmtVisitor, ExprVisitor { const DefUses &defUses; @@ -2274,7 +2141,7 @@ protected: virtual void visitRet(Ret *s) { s->expr->accept(this); } virtual void visitPhi(Phi *s) { s->targetTemp->accept(this); - foreach (Expr *e, s->d->incoming) + foreach (Expr *e, s->incoming) e->accept(this); } }; @@ -2306,6 +2173,7 @@ class TypeInference: public StmtVisitor, public ExprVisitor {} }; TypingResult _ty; + Stmt *_currentStmt; public: TypeInference(QQmlEnginePrivate *qmlEngine, const DefUses &defUses) @@ -2314,6 +2182,7 @@ public: , _tempTypes(_defUses.tempCount()) , _worklist(0) , _ty(UnknownType) + , _currentStmt(nullptr) {} void run(StatementWorklist &w) { @@ -2330,7 +2199,10 @@ public: QTextStream qout(&buf); qout<<"Typing stmt "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); + + qDebug("%u left in the worklist", _worklist->size()); } if (!run(s)) { @@ -2341,6 +2213,7 @@ public: QTextStream qout(&buf); qout<<"Pushing back stmt: "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); } } else { @@ -2350,6 +2223,7 @@ public: QTextStream qout(&buf); qout<<"Finished: "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); } } @@ -2373,7 +2247,9 @@ private: bool run(Stmt *s) { TypingResult ty; std::swap(_ty, ty); - s->accept(this); + std::swap(_currentStmt, s); + _currentStmt->accept(this); + std::swap(_currentStmt, s); std::swap(_ty, ty); return ty.fullyTyped; } @@ -2407,11 +2283,16 @@ private: QTextStream qout(&buf); qout << "Pushing back dependent stmt: "; IRPrinter(&qout).print(s); + qout.flush(); qDebug("%s", buf.data().constData()); } } - *_worklist += _defUses.uses(*t); + for (Stmt *s : qAsConst(_defUses.uses(*t))) { + if (s != _currentStmt) { + *_worklist += s; + } + } } } else { e->type = (Type) ty.type; @@ -2547,7 +2428,7 @@ protected: if (_ty.fullyTyped && _ty.type.memberResolver && _ty.type.memberResolver->isValid()) { MemberExpressionResolver *resolver = _ty.type.memberResolver; - _ty.type.type = resolver->resolveMember(qmlEngine, resolver, e); + _ty.type = resolver->resolveMember(qmlEngine, resolver, e); } else _ty.type = VarType; } @@ -2569,9 +2450,9 @@ protected: virtual void visitCJump(CJump *s) { _ty = run(s->cond); } virtual void visitRet(Ret *s) { _ty = run(s->expr); } virtual void visitPhi(Phi *s) { - _ty = run(s->d->incoming[0]); - for (int i = 1, ei = s->d->incoming.size(); i != ei; ++i) { - TypingResult ty = run(s->d->incoming[i]); + _ty = run(s->incoming[0]); + for (int i = 1, ei = s->incoming.size(); i != ei; ++i) { + TypingResult ty = run(s->incoming[i]); if (!ty.fullyTyped && _ty.fullyTyped) { // When one of the temps not fully typed, we already know that we cannot completely type this node. // So, pick the type we calculated upto this point, and wait until the unknown one will be typed. @@ -2834,12 +2715,12 @@ public: void run(IR::Function *f, StatementWorklist &worklist) { _f = f; - foreach (BasicBlock *bb, f->basicBlocks()) { + for (BasicBlock *bb : f->basicBlocks()) { if (bb->isRemoved()) continue; _conversions.clear(); - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { _currStmt = s; s->accept(this); } @@ -2890,7 +2771,7 @@ public: _defUses.addUse(*source, conversion.stmt); if (Phi *phi = conversion.stmt->asPhi()) { - int idx = phi->d->incoming.indexOf(t); + int idx = phi->incoming.indexOf(t); Q_ASSERT(idx != -1); bb->in[idx]->insertStatementBeforeTerminator(convCall); } else { @@ -3042,14 +2923,15 @@ protected: virtual void visitRet(Ret *s) { run(s->expr); } virtual void visitPhi(Phi *s) { Type ty = s->targetTemp->type; - for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i) - run(s->d->incoming[i], ty); + for (int i = 0, ei = s->incoming.size(); i != ei; ++i) + run(s->incoming[i], ty); } }; void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &worklist, DefUses &defUses) { - foreach (BasicBlock *toBB, f->basicBlocks()) { + const QVector<BasicBlock *> copy = f->basicBlocks(); + for (BasicBlock *toBB : copy) { if (toBB->isRemoved()) continue; if (toBB->in.size() < 2) @@ -3117,7 +2999,7 @@ void splitCriticalEdges(IR::Function *f, DominatorTree &df, StatementWorklist &w df.setImmediateDominator(newBB, fromBB); bool toNeedsNewIdom = true; - foreach (BasicBlock *bb, toBB->in) { + for (BasicBlock *bb : toBB->in) { if (bb != newBB && !df.dominates(toBB, bb)) { toNeedsNewIdom = false; break; @@ -3227,7 +3109,7 @@ public: backedges.clear(); - foreach (BasicBlock *in, bb->in) + for (BasicBlock *in : bb->in) if (dt.dominates(bb, in)) backedges.push_back(in); @@ -3304,7 +3186,7 @@ private: // those predecessors are not in the current subloop. It might be the case // that they are in other loops, which we will then add as a subloop to the // current loop. - foreach (BasicBlock *predIn, predIt->in) + for (BasicBlock *predIn : predIt->in) if (predIn->containingGroup() != subloop) worklist.push_back(predIn); } else { @@ -3315,7 +3197,7 @@ private: predIt->setContainingGroup(loopHead); // Add all incoming edges to the worklist. - foreach (BasicBlock *bb, predIt->in) + for (BasicBlock *bb : predIt->in) worklist.push_back(bb); } } @@ -3327,7 +3209,7 @@ private: void createLoopInfos(IR::Function *function) { - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; if (BasicBlock *loopHeader = bb->containingGroup()) @@ -3400,7 +3282,7 @@ class BlockScheduler { Q_ASSERT(candidate->containingGroup() == currentGroup.group); - foreach (BasicBlock *in, candidate->in) { + for (BasicBlock *in : candidate->in) { if (emitted.alreadyProcessed(in)) continue; @@ -3510,7 +3392,7 @@ public: void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) { foreach (BasicBlock *bb, basicBlocks) { if (bb && bb->out.size() > 1) { - foreach (BasicBlock *bb2, bb->out) { + for (BasicBlock *bb2 : bb->out) { if (bb2 && bb2->in.size() > 1) { qDebug() << "found critical edge between block" << bb->index() << "and block" << bb2->index(); @@ -3545,28 +3427,28 @@ static void cleanupBasicBlocks(IR::Function *function) reachableBlocks.setBit(bb->index()); - foreach (BasicBlock *outBB, bb->out) { + for (BasicBlock *outBB : bb->out) { if (!reachableBlocks.at(outBB->index())) postponed.append(outBB); } } - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) // the block has already been removed, so ignore it continue; if (reachableBlocks.at(bb->index())) // the block is reachable, so ignore it continue; - foreach (BasicBlock *outBB, bb->out) { + for (BasicBlock *outBB : bb->out) { if (outBB->isRemoved() || !reachableBlocks.at(outBB->index())) continue; // We do not need to unlink from blocks that are scheduled to be removed. int idx = outBB->in.indexOf(bb); if (idx != -1) { outBB->in.remove(idx); - foreach (Stmt *s, outBB->statements()) { + for (Stmt *s : outBB->statements()) { if (Phi *phi = s->asPhi()) - phi->d->incoming.remove(idx); + phi->incoming.remove(idx); else break; } @@ -3581,9 +3463,9 @@ static void cleanupBasicBlocks(IR::Function *function) inline Const *isConstPhi(Phi *phi) { - if (Const *c = phi->d->incoming[0]->asConst()) { - for (int i = 1, ei = phi->d->incoming.size(); i != ei; ++i) { - if (Const *cc = phi->d->incoming[i]->asConst()) { + if (Const *c = phi->incoming[0]->asConst()) { + for (int i = 1, ei = phi->incoming.size(); i != ei; ++i) { + if (Const *cc = phi->incoming[i]->asConst()) { if (c->value != cc->value) return 0; if (!(c->type == cc->type || (c->type & NumberType && cc->type & NumberType))) @@ -3684,8 +3566,8 @@ protected: virtual void visitCJump(CJump *s) { check(s->cond); } virtual void visitRet(Ret *s) { check(s->expr); } virtual void visitPhi(Phi *s) { - for (int i = 0, ei = s->d->incoming.size(); i != ei; ++i) - check(s->d->incoming[i]); + for (int i = 0, ei = s->incoming.size(); i != ei; ++i) + check(s->incoming[i]); } private: @@ -3746,11 +3628,11 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs if (!outStmt) continue; if (Phi *phi = outStmt->asPhi()) { - if (Temp *t = phi->d->incoming[idx]->asTemp()) { + if (Temp *t = phi->incoming[idx]->asTemp()) { defUses.removeUse(phi, *t); W += defUses.defStmt(*t); } - phi->d->incoming.remove(idx); + phi->incoming.remove(idx); W += phi; } else { break; @@ -3800,14 +3682,14 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs continue; // unlink all incoming edges - foreach (BasicBlock *in, bb->in) { + for (BasicBlock *in : bb->in) { int idx = in->out.indexOf(bb); if (idx != -1) in->out.remove(idx); } // unlink all outgoing edges, including "arguments" to phi statements - foreach (BasicBlock *out, bb->out) { + for (BasicBlock *out : bb->out) { if (out->isRemoved()) continue; @@ -3823,7 +3705,7 @@ void unlink(BasicBlock *from, BasicBlock *to, IR::Function *func, DefUses &defUs } // unlink all defs/uses from the statements in the basic block - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (!s) continue; @@ -3938,7 +3820,7 @@ void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops = Util(qout).genLoop(l); } - foreach (BasicBlock *bb, f->basicBlocks()) { + for (BasicBlock *bb : f->basicBlocks()) { if (bb->isRemoved()) continue; @@ -3949,7 +3831,7 @@ void cfg2dot(IR::Function *f, const QVector<LoopDetection::LoopInfo *> &loops = else qout << ", shape=circle"; qout << "];\n"; - foreach (BasicBlock *out, bb->out) + for (BasicBlock *out : bb->out) qout << " L" << idx << " -> L" << out->index() << "\n"; } @@ -3987,9 +3869,9 @@ void optimizeSSA(StatementWorklist &W, DefUses &defUses, DominatorTree &df) } // copy propagation: - if (phi->d->incoming.size() == 1) { + if (phi->incoming.size() == 1) { Temp *t = phi->targetTemp; - Expr *e = phi->d->incoming.first(); + Expr *e = phi->incoming.first(); QVector<Stmt *> newT2Uses; replaceUses(t, e, W, &newT2Uses); @@ -4420,14 +4302,14 @@ private: void buildIntervals(BasicBlock *bb, BasicBlock *loopEnd) { LiveRegs live; - foreach (BasicBlock *successor, bb->out) { + for (BasicBlock *successor : bb->out) { live.unite(_liveIn[successor->index()]); const int bbIndex = successor->in.indexOf(bb); Q_ASSERT(bbIndex >= 0); - foreach (Stmt *s, successor->statements()) { + for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { - if (Temp *t = phi->d->incoming.at(bbIndex)->asTemp()) + if (Temp *t = phi->incoming.at(bbIndex)->asTemp()) live.insert(*t); } else { break; @@ -4435,7 +4317,7 @@ private: } } - QVector<Stmt *> statements = bb->statements(); + const QVector<Stmt *> &statements = bb->statements(); foreach (const Temp &opd, live) interval(&opd).addRange(start(bb), end(bb)); @@ -4483,7 +4365,7 @@ void removeUnreachleBlocks(IR::Function *function) { QVector<BasicBlock *> newSchedule; newSchedule.reserve(function->basicBlockCount()); - foreach (BasicBlock *bb, function->basicBlocks()) + for (BasicBlock *bb : function->basicBlocks()) if (!bb->isRemoved()) newSchedule.append(bb); function->setScheduledBlocks(newSchedule); @@ -4528,9 +4410,9 @@ public: } } - foreach (BasicBlock *bb, function->basicBlocks()) + for (BasicBlock *bb : function->basicBlocks()) if (!bb->isRemoved()) - foreach (Stmt *s, bb->statements()) + for (Stmt *s : bb->statements()) s->accept(this); if (convertArgs && function->formals.size() > 0) @@ -4614,7 +4496,7 @@ public: { block = new BasicBlock(originalBlock->function, 0); - foreach (Stmt *s, originalBlock->statements()) { + for (Stmt *s : originalBlock->statements()) { s->accept(this); clonedStmt->location = s->location; } @@ -4644,9 +4526,8 @@ protected: clonedStmt = phi; phi->targetTemp = clone(stmt->targetTemp); - phi->d = new Phi::Data; - foreach (Expr *in, stmt->d->incoming) - phi->d->incoming.append(clone(in)); + foreach (Expr *in, stmt->incoming) + phi->incoming.append(clone(in)); block->appendStatement(phi); } @@ -4731,7 +4612,8 @@ private: // the terminators will automatically insert that edge). The blocks where the originals // pointed to will have an extra incoming edge from the copied blocks. - foreach (BasicBlock *in, loop->loopHeader->in) { + BasicBlock::IncomingEdges inCopy = loop->loopHeader->in; + for (BasicBlock *in : inCopy) { if (unpeeled.loopHeader != in // this can happen for really tight loops (where there are no body blocks). This is a back-edge in that case. && !unpeeled.loopBody.contains(in) // if the edge is not coming from within the copied set, leave it alone && !dt.dominates(loop->loopHeader, in)) // an edge coming from within the loop (so a back-edge): this is handled when rewiring all outgoing edges @@ -4805,7 +4687,7 @@ static void verifyCFG(IR::Function *function) if (!DoVerification) return; - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) { Q_ASSERT(bb->in.isEmpty()); Q_ASSERT(bb->out.isEmpty()); @@ -4837,14 +4719,14 @@ static void verifyCFG(IR::Function *function) } // Check the outgoing edges: - foreach (BasicBlock *out, bb->out) { + for (BasicBlock *out : bb->out) { Q_UNUSED(out); Q_ASSERT(!out->isRemoved()); Q_ASSERT(out->in.contains(bb)); } // Check the incoming edges: - foreach (BasicBlock *in, bb->in) { + for (BasicBlock *in : bb->in) { Q_UNUSED(in); Q_ASSERT(!in->isRemoved()); Q_ASSERT(in->out.contains(bb)); @@ -4861,7 +4743,7 @@ static void verifyImmediateDominators(const DominatorTree &dt, IR::Function *fun dt.dumpImmediateDominators(); DominatorTree referenceTree(function); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; @@ -4882,11 +4764,11 @@ static void verifyNoPointerSharing(IR::Function *function) public: void operator()(IR::Function *f) { - foreach (BasicBlock *bb, f->basicBlocks()) { + for (BasicBlock *bb : f->basicBlocks()) { if (bb->isRemoved()) continue; - foreach (Stmt *s, bb->statements()) + for (Stmt *s : bb->statements()) s->accept(this); } } @@ -4901,7 +4783,7 @@ static void verifyNoPointerSharing(IR::Function *function) { check(s); s->targetTemp->accept(this); - foreach (Expr *e, s->d->incoming) + foreach (Expr *e, s->incoming) e->accept(this); } @@ -4950,11 +4832,11 @@ class RemoveLineNumbers: public SideEffectsChecker, public StmtVisitor public: static void run(IR::Function *function) { - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (!hasSideEffects(s)) { s->location = QQmlJS::AST::SourceLocation(); } @@ -5166,13 +5048,13 @@ LifeTimeIntervals::LifeTimeIntervals(IR::Function *function) // basic-block. void LifeTimeIntervals::renumber(IR::Function *function) { - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { if (bb->isRemoved()) continue; _basicBlockPosition[bb->index()].start = _lastPosition + 1; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { if (s->asPhi()) continue; @@ -5202,7 +5084,7 @@ void Optimizer::run(QQmlEnginePrivate *qmlEngine, bool doTypeInference, bool pee function->removeSharedExpressions(); int statementCount = 0; - foreach (BasicBlock *bb, function->basicBlocks()) + for (BasicBlock *bb : function->basicBlocks()) if (!bb->isRemoved()) statementCount += bb->statementCount(); // showMeTheCode(function); @@ -5332,15 +5214,15 @@ void Optimizer::convertOutOfSSA() { // There should be no critical edges at this point. - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { MoveMapping moves; - foreach (BasicBlock *successor, bb->out) { + for (BasicBlock *successor : bb->out) { const int inIdx = successor->in.indexOf(bb); Q_ASSERT(inIdx >= 0); - foreach (Stmt *s, successor->statements()) { + for (Stmt *s : successor->statements()) { if (Phi *phi = s->asPhi()) { - moves.add(clone(phi->d->incoming[inIdx], function), + moves.add(clone(phi->incoming[inIdx], function), clone(phi->targetTemp, function)->asTemp()); } else { break; @@ -5368,7 +5250,7 @@ void Optimizer::convertOutOfSSA() { moves.insertMoves(bb, function, true); } - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { while (!bb->isEmpty()) { if (bb->statements().first()->asPhi()) { bb->removeStatement(0); diff --git a/src/qml/debugger/qqmlabstractprofileradapter_p.h b/src/qml/debugger/qqmlabstractprofileradapter_p.h index bd93da324d..1104608055 100644 --- a/src/qml/debugger/qqmlabstractprofileradapter_p.h +++ b/src/qml/debugger/qqmlabstractprofileradapter_p.h @@ -64,6 +64,8 @@ class Q_QML_PRIVATE_EXPORT QQmlAbstractProfilerAdapter : public QObject, public Q_OBJECT public: + static const int s_numMessagesPerBatch = 1000; + QQmlAbstractProfilerAdapter(QObject *parent = 0) : QObject(parent), service(0), waiting(true), featuresEnabled(0) {} virtual ~QQmlAbstractProfilerAdapter() {} diff --git a/src/qml/debugger/qqmldebug.cpp b/src/qml/debugger/qqmldebug.cpp index 64a951d53b..9276bd0544 100644 --- a/src/qml/debugger/qqmldebug.cpp +++ b/src/qml/debugger/qqmldebug.cpp @@ -134,22 +134,11 @@ void QQmlDebuggingEnabler::setServices(const QStringList &services) */ bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const QString &hostName) { -#ifndef QQML_NO_DEBUG_PROTOCOL - QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer")); - QQmlDebugConnector *connector = QQmlDebugConnector::instance(); - if (connector) { - QVariantHash configuration; - configuration[QLatin1String("portFrom")] = configuration[QLatin1String("portTo")] = port; - configuration[QLatin1String("block")] = (mode == WaitForClient); - configuration[QLatin1String("hostAddress")] = hostName; - return connector->open(configuration); - } -#else - Q_UNUSED(port); - Q_UNUSED(mode); - Q_UNUSED(hostName); -#endif - return false; + QVariantHash configuration; + configuration[QLatin1String("portFrom")] = configuration[QLatin1String("portTo")] = port; + configuration[QLatin1String("block")] = (mode == WaitForClient); + configuration[QLatin1String("hostAddress")] = hostName; + return startDebugConnector(QLatin1String("QQmlDebugServer"), configuration); } /*! @@ -164,18 +153,33 @@ bool QQmlDebuggingEnabler::startTcpDebugServer(int port, StartMode mode, const Q */ bool QQmlDebuggingEnabler::connectToLocalDebugger(const QString &socketFileName, StartMode mode) { + QVariantHash configuration; + configuration[QLatin1String("fileName")] = socketFileName; + configuration[QLatin1String("block")] = (mode == WaitForClient); + return startDebugConnector(QLatin1String("QQmlDebugServer"), configuration); +} + +/*! + * \since 5.7 + * + * Enables debugging for QML engines created after calling this function. A debug connector plugin + * specified by \a pluginName will be loaded and started using the given \a configuration. Supported + * configuration entries and their semantics depend on the plugin being loaded. You can only start + * one debug connector at a time. A debug connector may have already been started if the + * -qmljsdebugger= command line argument was given. This method returns \c true if a new debug + * connector was successfully started, or \c false otherwise. + */ +bool QQmlDebuggingEnabler::startDebugConnector(const QString &pluginName, + const QVariantHash &configuration) +{ #ifndef QQML_NO_DEBUG_PROTOCOL - QQmlDebugConnector::setPluginKey(QLatin1String("QQmlDebugServer")); + QQmlDebugConnector::setPluginKey(pluginName); QQmlDebugConnector *connector = QQmlDebugConnector::instance(); - if (connector) { - QVariantHash configuration; - configuration[QLatin1String("fileName")] = socketFileName; - configuration[QLatin1String("block")] = (mode == WaitForClient); + if (connector) return connector->open(configuration); - } #else - Q_UNUSED(fileName); - Q_UNUSED(mode); + Q_UNUSED(pluginName); + Q_UNUSED(configuration); #endif return false; } diff --git a/src/qml/debugger/qqmldebug.h b/src/qml/debugger/qqmldebug.h index eebebefe62..660b9e4d46 100644 --- a/src/qml/debugger/qqmldebug.h +++ b/src/qml/debugger/qqmldebug.h @@ -42,6 +42,7 @@ #include <QtQml/qtqmlglobal.h> #include <QtCore/qstring.h> +#include <QtCore/qvariant.h> QT_BEGIN_NAMESPACE @@ -65,6 +66,8 @@ struct Q_QML_EXPORT QQmlDebuggingEnabler const QString &hostName = QString()); static bool connectToLocalDebugger(const QString &socketFileName, StartMode mode = DoNotWaitForClient); + static bool startDebugConnector(const QString &pluginName, + const QVariantHash &configuration = QVariantHash()); }; // Execute code in constructor before first QQmlEngine is instantiated diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp index 6edd28ea01..e6d1a218ad 100644 --- a/src/qml/debugger/qqmldebugconnector.cpp +++ b/src/qml/debugger/qqmldebugconnector.cpp @@ -127,18 +127,15 @@ QQmlDebugConnector *QQmlDebugConnector::instance() } if (!params->instance) { - const QString serverConnector = QStringLiteral("QQmlDebugServer"); - const QString nativeConnector = QStringLiteral("QQmlNativeDebugConnector"); - const bool isNative = params->arguments.startsWith(QLatin1String("native")); if (!params->pluginKey.isEmpty()) { - if (params->pluginKey == serverConnector || params->pluginKey == nativeConnector) - params->instance = loadQQmlDebugConnector(params->pluginKey); - else - return 0; // We cannot load anything else, yet + params->instance = loadQQmlDebugConnector(params->pluginKey); } else if (params->arguments.isEmpty()) { return 0; // no explicit class name given and no command line arguments } else { - params->instance = loadQQmlDebugConnector(isNative ? nativeConnector : serverConnector); + params->instance = loadQQmlDebugConnector( + params->arguments.startsWith(QLatin1String("native")) ? + QStringLiteral("QQmlNativeDebugConnector") : + QStringLiteral("QQmlDebugServer")); } if (params->instance) { diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc index 31133c862f..f32574fcc1 100644 --- a/src/qml/doc/src/qmltypereference.qdoc +++ b/src/qml/doc/src/qmltypereference.qdoc @@ -55,7 +55,7 @@ are also provided by the \c QtQuick namespace which may be imported as follows: \qml -import QtQuick 2.5 +import QtQuick 2.7 \endqml See the \l{Qt Quick} module documentation for more information about the \c diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index a6e085a913..131e0a5b0a 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -180,9 +180,9 @@ public: _calls.reserve(function->statementCount() / 3); _hints.resize(function->tempCount); - foreach (BasicBlock *bb, function->basicBlocks()) { + for (BasicBlock *bb : function->basicBlocks()) { _currentBB = bb; - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { _currentStmt = s; s->accept(this); } @@ -702,8 +702,8 @@ protected: // IRDecoder virtual void visitPhi(IR::Phi *s) { addDef(s->targetTemp, true); - for (int i = 0, ei = s->d->incoming.size(); i < ei; ++i) { - Expr *e = s->d->incoming.at(i); + for (int i = 0, ei = s->incoming.size(); i < ei; ++i) { + Expr *e = s->incoming.at(i); if (Temp *t = e->asTemp()) { // The actual use of an incoming value in a phi node is right before the terminator // of the other side of the incoming edge. @@ -821,8 +821,8 @@ class ResolutionPhase: protected StmtVisitor, protected ExprVisitor { const QVector<const RegisterInfo *> &_fpRegs; Stmt *_currentStmt; - QVector<Move *> _loads; - QVector<Move *> _stores; + std::vector<Move *> _loads; + std::vector<Move *> _stores; QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtStart; QHash<BasicBlock *, QList<const LifeTimeInterval *> > _liveAtEnd; @@ -872,7 +872,7 @@ private: { QVector<Stmt *> newStatements; - foreach (BasicBlock *bb, _function->basicBlocks()) { + for (BasicBlock *bb : _function->basicBlocks()) { _currentStmt = 0; QVector<Stmt *> statements = bb->statements(); @@ -892,13 +892,13 @@ private: else addNewIntervals(defPosition(_currentStmt)); _currentStmt->accept(this); - foreach (Move *load, _loads) + for (Move *load : _loads) newStatements.append(load); if (_currentStmt->asPhi()) newStatements.prepend(_currentStmt); else newStatements.append(_currentStmt); - foreach (Move *store, _stores) + for (Move *store : _stores) newStatements.append(store); } @@ -912,7 +912,7 @@ private: os << "Intervals live at the start of L" << bb->index() << ":" << endl; if (_liveAtStart[bb].isEmpty()) os << "\t(none)" << endl; - foreach (const LifeTimeInterval *i, _liveAtStart[bb]) { + for (const LifeTimeInterval *i : _liveAtStart.value(bb)) { os << "\t"; i->dump(os); os << endl; @@ -920,7 +920,7 @@ private: os << "Intervals live at the end of L" << bb->index() << ":" << endl; if (_liveAtEnd[bb].isEmpty()) os << "\t(none)" << endl; - foreach (const LifeTimeInterval *i, _liveAtEnd[bb]) { + for (const LifeTimeInterval *i : _liveAtEnd.value(bb)) { os << "\t"; i->dump(os); os << endl; @@ -943,7 +943,7 @@ private: Q_ASSERT(pReg); int spillSlot = _assignedSpillSlots[i->temp().index]; if (spillSlot != RegisterAllocator::InvalidSpillSlot) - _stores.append(generateSpill(spillSlot, i->temp().type, pReg->reg<int>())); + _stores.push_back(generateSpill(spillSlot, i->temp().type, pReg->reg<int>())); } void addNewIntervals(int position) @@ -976,15 +976,15 @@ private: void resolve() { - foreach (BasicBlock *bb, _function->basicBlocks()) { - foreach (BasicBlock *bbOut, bb->out) + for (BasicBlock *bb : _function->basicBlocks()) { + for (BasicBlock *bbOut : bb->out) resolveEdge(bb, bbOut); } } Phi *findDefPhi(const Temp &t, BasicBlock *bb) const { - foreach (Stmt *s, bb->statements()) { + for (Stmt *s : bb->statements()) { Phi *phi = s->asPhi(); if (!phi) return 0; @@ -1017,21 +1017,21 @@ private: int successorStart = _intervals->startPosition(successor); Q_ASSERT(successorStart > 0); - foreach (const LifeTimeInterval *it, _liveAtStart[successor]) { + for (const LifeTimeInterval *it : _liveAtStart.value(successor)) { bool isPhiTarget = false; Expr *moveFrom = 0; if (it->start() == successorStart) { if (Phi *phi = findDefPhi(it->temp(), successor)) { isPhiTarget = true; - Expr *opd = phi->d->incoming[successor->in.indexOf(predecessor)]; + Expr *opd = phi->incoming[successor->in.indexOf(predecessor)]; if (opd->asConst()) { moveFrom = opd; } else { Temp *t = opd->asTemp(); Q_ASSERT(t); - foreach (const LifeTimeInterval *it2, _liveAtEnd[predecessor]) { + for (const LifeTimeInterval *it2 : _liveAtEnd.value(predecessor)) { if (it2->temp() == *t && it2->reg() != LifeTimeInterval::InvalidRegister && it2->covers(predecessorEnd)) { @@ -1046,7 +1046,7 @@ private: } } } else { - foreach (const LifeTimeInterval *predIt, _liveAtEnd[predecessor]) { + for (const LifeTimeInterval *predIt : _liveAtEnd.value(predecessor)) { if (predIt->temp() == it->temp()) { if (predIt->reg() != LifeTimeInterval::InvalidRegister && predIt->covers(predecessorEnd)) { @@ -1191,7 +1191,7 @@ protected: Q_ASSERT(i->isSplitFromInterval()); const RegisterInfo *pReg = platformRegister(*i); Q_ASSERT(pReg); - _loads.append(generateUnspill(i->temp(), pReg->reg<int>())); + _loads.push_back(generateUnspill(i->temp(), pReg->reg<int>())); } if (i->reg() != LifeTimeInterval::InvalidRegister && @@ -1303,7 +1303,7 @@ void RegisterAllocator::run(IR::Function *function, const Optimizer &opt) qout << "Ranges:" << endl; QVector<LifeTimeInterval *> intervals = _unhandled; std::reverse(intervals.begin(), intervals.end()); - foreach (const LifeTimeInterval *r, intervals) { + for (const LifeTimeInterval *r : qAsConst(intervals)) { r->dump(qout); qout << endl; } @@ -1490,11 +1490,11 @@ void RegisterAllocator::linearScan() } } - foreach (LifeTimeInterval *r, _active) + for (LifeTimeInterval *r : qAsConst(_active)) if (!r->isFixedInterval()) _handled.append(r); _active.clear(); - foreach (LifeTimeInterval *r, _inactive) + for (LifeTimeInterval *r : qAsConst(_inactive)) if (!r->isFixedInterval()) _handled.append(r); _inactive.clear(); @@ -1922,7 +1922,7 @@ void RegisterAllocator::dump(IR::Function *function) const qout << "Ranges:" << endl; QVector<LifeTimeInterval *> handled = _handled; std::sort(handled.begin(), handled.end(), LifeTimeInterval::lessThanForTemp); - foreach (const LifeTimeInterval *r, handled) { + for (const LifeTimeInterval *r : qAsConst(handled)) { r->dump(qout); qout << endl; } diff --git a/src/qml/jsapi/qjsengine.h b/src/qml/jsapi/qjsengine.h index 300990873d..6ecd0c7ec0 100644 --- a/src/qml/jsapi/qjsengine.h +++ b/src/qml/jsapi/qjsengine.h @@ -111,7 +111,7 @@ private: friend inline bool qjsvalue_cast_helper(const QJSValue &, int, void *); protected: - QJSEngine(QJSEnginePrivate &dd, QObject *parent = 0); + QJSEngine(QJSEnginePrivate &dd, QObject *parent = Q_NULLPTR); private: QV8Engine *d; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 317eb7a8a7..55ea1f91c3 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -576,15 +576,6 @@ ExecutionContext *ExecutionEngine::pushGlobalContext() return currentContext; } -ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const -{ - Value *offset = static_cast<Value *>(context) + 1; - Q_ASSERT(offset->isInteger()); - int o = offset->integerValue(); - return o ? context - o : 0; -} - - Heap::Object *ExecutionEngine::newObject() { return memoryManager->allocObject<Object>(); @@ -770,27 +761,6 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) return obj->d(); } -Heap::QmlContext *ExecutionEngine::qmlContext() const -{ - Heap::ExecutionContext *ctx = current; - - // get the correct context when we're within a builtin function - if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = parentContext(currentContext)->d(); - - if (!ctx->outer) - return 0; - - while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) - ctx = ctx->outer; - - Q_ASSERT(ctx); - if (ctx->type != Heap::ExecutionContext::Type_QmlContext) - return 0; - - return static_cast<Heap::QmlContext *>(ctx); -} - QObject *ExecutionEngine::qmlScopeObject() const { Heap::QmlContext *ctx = qmlContext(); diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 12ed98e6e7..7da4a1c3c1 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -500,6 +500,35 @@ inline void ExecutionEngine::popContext() current = currentContext->d(); } +inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const +{ + Value *offset = static_cast<Value *>(context) + 1; + Q_ASSERT(offset->isInteger()); + int o = offset->integerValue(); + return o ? context - o : 0; +} + +inline Heap::QmlContext *ExecutionEngine::qmlContext() const +{ + Heap::ExecutionContext *ctx = current; + + // get the correct context when we're within a builtin function + if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) + ctx = parentContext(currentContext)->d(); + + if (!ctx->outer) + return 0; + + while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext) + ctx = ctx->outer; + + Q_ASSERT(ctx); + if (ctx->type != Heap::ExecutionContext::Type_QmlContext) + return 0; + + return static_cast<Heap::QmlContext *>(ctx); +} + inline void Heap::Base::mark(QV4::ExecutionEngine *engine) { diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index dd86c50270..470791fb00 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -141,8 +141,8 @@ struct ReadAccessor { { Q_ASSERT(property.accessors); - property.accessors->read(object, property.accessorData, output); - if (n) property.accessors->notifier(object, property.accessorData, n); + property.accessors->read(object, output); + if (n) property.accessors->notifier(object, n); } }; diff --git a/src/qml/jsruntime/qv4util_p.h b/src/qml/jsruntime/qv4util_p.h index 3ffcc8a846..59c12c5e46 100644 --- a/src/qml/jsruntime/qv4util_p.h +++ b/src/qml/jsruntime/qv4util_p.h @@ -51,6 +51,9 @@ // #include "qv4global_p.h" +#include <QtCore/QBitArray> +#include <algorithm> +#include <vector> QT_BEGIN_NAMESPACE @@ -76,6 +79,130 @@ private: TemporaryAssignment operator=(const TemporaryAssignment<T>&); }; +#if !defined(BROKEN_STD_VECTOR_BOOL_OR_BROKEN_STD_FIND) +// Sanity: +class BitVector +{ + std::vector<bool> bits; + +public: + BitVector(int size = 0, bool value = false) + : bits(size, value) + {} + + void reserve(int size) + { bits.reserve(size); } + + int size() const + { + Q_ASSERT(bits.size() < INT_MAX); + return static_cast<int>(bits.size()); + } + + void resize(int newSize) + { bits.resize(newSize); } + + void resize(int newSize, bool newValue) + { bits.resize(newSize, newValue); } + + void assign(int newSize, bool value) + { bits.assign(newSize, value); } + + int findNext(int start, bool value, bool wrapAround) const + { + // The ++operator of std::vector<bool>::iterator in libc++ has a bug when using it on an + // iterator pointing to the last element. It will not be set to ::end(), but beyond + // that. (It will be set to the first multiple of the native word size that is bigger + // than size().) + // + // See http://llvm.org/bugs/show_bug.cgi?id=19663 + // + // The work-around is to calculate the distance, and compare it to the size() to see if it's + // beyond the end, or take the minimum of the distance and the size. + + size_t pos = std::distance(bits.begin(), + std::find(bits.begin() + start, bits.end(), value)); + if (wrapAround && pos >= static_cast<size_t>(size())) + pos = std::distance(bits.begin(), + std::find(bits.begin(), bits.begin() + start, value)); + + pos = qMin(pos, static_cast<size_t>(size())); + + Q_ASSERT(pos <= static_cast<size_t>(size())); + Q_ASSERT(pos < INT_MAX); + + return static_cast<int>(pos); + } + + bool at(int idx) const + { return bits.at(idx); } + + void setBit(int idx) + { bits[idx] = true; } + + void clearBit(int idx) + { bits[idx] = false; } +}; +#else // Insanity: +class BitVector +{ + QBitArray bits; + +public: + BitVector(int size = 0, bool value = false) + : bits(size, value) + {} + + void reserve(int size) + { Q_UNUSED(size); } + + int size() const + { return bits.size(); } + + void resize(int newSize) + { bits.resize(newSize); } + + void resize(int newSize, bool newValue) + { + int oldSize = bits.size(); + bits.resize(newSize); + bits.fill(newValue, oldSize, bits.size()); + } + + void assign(int newSize, bool value) + { + bits.resize(newSize); + bits.fill(value); + } + + int findNext(int start, bool value, bool wrapAround) const + { + for (int i = start, ei = size(); i < ei; ++i) { + if (at(i) == value) + return i; + } + + if (wrapAround) { + for (int i = 0, ei = start; i < ei; ++i) { + if (at(i) == value) + return i; + } + } + + return size(); + } + + bool at(int idx) const + { return bits.at(idx); } + + void setBit(int idx) + { bits[idx] = true; } + + void clearBit(int idx) + { bits[idx] = false; } +}; +#endif + } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index e8320b33d2..514bdafb48 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -119,11 +119,14 @@ struct Q_QML_PRIVATE_EXPORT Value Q_ALWAYS_INLINE quint32 value() const { return _val >> 32; } #endif -#ifdef QV4_USE_64_BIT_VALUE_ENCODING +#if defined(V4_BOOTSTRAP) + Q_ALWAYS_INLINE Heap::Base *m() const { Q_UNREACHABLE(); return Q_NULLPTR; } + Q_ALWAYS_INLINE void setM(Heap::Base *b) { Q_UNUSED(b); Q_UNREACHABLE(); } +#elif defined(QV4_USE_64_BIT_VALUE_ENCODING) Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; memcpy(&b, &_val, 8); return b; } Q_ALWAYS_INLINE void setM(Heap::Base *b) { memcpy(&_val, &b, 8); } #else // !QV4_USE_64_BIT_VALUE_ENCODING - Q_ALWAYS_INLINE Heap::Base *m() const { Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; } + Q_ALWAYS_INLINE Heap::Base *m() const { Q_STATIC_ASSERT(sizeof(Heap::Base*) == sizeof(quint32)); Heap::Base *b; quint32 v = value(); memcpy(&b, &v, 4); return b; } Q_ALWAYS_INLINE void setM(Heap::Base *b) { quint32 v; memcpy(&v, &b, 4); setValue(v); } #endif diff --git a/src/qml/parser/qqmljsmemorypool_p.h b/src/qml/parser/qqmljsmemorypool_p.h index 3659271bc6..08609e2961 100644 --- a/src/qml/parser/qqmljsmemorypool_p.h +++ b/src/qml/parser/qqmljsmemorypool_p.h @@ -94,7 +94,7 @@ public: inline void *allocate(size_t size) { size = (size + 7) & ~7; - if (_ptr && (_ptr + size < _end)) { + if (Q_LIKELY(_ptr && (_ptr + size < _end))) { void *addr = _ptr; _ptr += size; return addr; @@ -111,7 +111,7 @@ public: template <typename Tp> Tp *New() { return new (this->allocate(sizeof(Tp))) Tp(); } private: - void *allocate_helper(size_t size) + Q_NEVER_INLINE void *allocate_helper(size_t size) { Q_ASSERT(size < BLOCK_SIZE); diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h index 4ddac0c2c6..6ff3e4a11b 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -54,7 +54,6 @@ #include <QtCore/qglobal.h> #include <QtCore/qstring.h> #include <private/qv4string_p.h> -#include <private/qv4scopedvalue_p.h> #include <private/qflagpointer_p.h> diff --git a/src/qml/qml/qqml.h b/src/qml/qml/qqml.h index a71d06f7de..8fb710ad9d 100644 --- a/src/qml/qml/qqml.h +++ b/src/qml/qml/qqml.h @@ -111,10 +111,11 @@ int qmlRegisterType() qRegisterNormalizedMetaType<T *>(pointerName.constData()), qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, QString(), - 0, 0, 0, 0, &T::staticMetaObject, + Q_NULLPTR, 0, 0, Q_NULLPTR, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -123,9 +124,9 @@ int qmlRegisterType() QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, 0 }; @@ -144,7 +145,8 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin qRegisterNormalizedMetaType<T *>(pointerName.constData()), qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, reason, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -156,9 +158,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, 0 }; @@ -175,7 +177,8 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin qRegisterNormalizedMetaType<T *>(pointerName.constData()), qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, reason, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -187,9 +190,9 @@ int qmlRegisterUncreatableType(const char *uri, int versionMajor, int versionMin QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, metaObjectRevision }; @@ -213,7 +216,8 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve qRegisterNormalizedMetaType<T *>(pointerName.constData()), qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, reason, uri, versionMajor, versionMinor, qmlName, &T::staticMetaObject, @@ -227,7 +231,7 @@ int qmlRegisterExtendedUncreatableType(const char *uri, int versionMajor, int ve QQmlPrivate::createParent<E>, &E::staticMetaObject, - 0, + Q_NULLPTR, 0 }; @@ -256,9 +260,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, 0 }; @@ -287,9 +291,9 @@ int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const c QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, metaObjectRevision }; @@ -318,9 +322,9 @@ int qmlRegisterRevision(const char *uri, int versionMajor, int versionMinor) QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, - 0, + Q_NULLPTR, metaObjectRevision }; @@ -338,10 +342,11 @@ int qmlRegisterExtendedType() qRegisterNormalizedMetaType<T *>(pointerName.constData()), qRegisterNormalizedMetaType<QQmlListProperty<T> >(listName.constData()), - 0, 0, + 0, + Q_NULLPTR, QString(), - 0, 0, 0, 0, &T::staticMetaObject, + Q_NULLPTR, 0, 0, Q_NULLPTR, &T::staticMetaObject, QQmlPrivate::attachedPropertiesFunc<T>(), QQmlPrivate::attachedPropertiesMetaObject<T>(), @@ -352,7 +357,7 @@ int qmlRegisterExtendedType() QQmlPrivate::createParent<E>, &E::staticMetaObject, - 0, + Q_NULLPTR, 0 }; @@ -391,7 +396,7 @@ int qmlRegisterExtendedType(const char *uri, int versionMajor, int versionMinor, QQmlPrivate::createParent<E>, &E::staticMetaObject, - 0, + Q_NULLPTR, 0 }; @@ -441,7 +446,7 @@ int qmlRegisterCustomType(const char *uri, int versionMajor, int versionMinor, QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueSource>::cast(), QQmlPrivate::StaticCastSelector<T,QQmlPropertyValueInterceptor>::cast(), - 0, 0, + Q_NULLPTR, Q_NULLPTR, parser, 0 @@ -536,7 +541,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - callback, 0, 0, 0, 0 + callback, Q_NULLPTR, Q_NULLPTR, 0, 0 }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); @@ -554,7 +559,7 @@ inline int qmlRegisterSingletonType(const char *uri, int versionMajor, int versi uri, versionMajor, versionMinor, typeName, - 0, callback, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0 + Q_NULLPTR, callback, &T::staticMetaObject, qRegisterNormalizedMetaType<T *>(pointerName.constData()), 0 }; return QQmlPrivate::qmlregister(QQmlPrivate::SingletonRegistration, &api); diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h index cae4e2c2ff..55562a5307 100644 --- a/src/qml/qml/qqmlaccessors_p.h +++ b/src/qml/qml/qqmlaccessors_p.h @@ -103,7 +103,7 @@ class QQmlNotifier; } while (false); #define QML_PRIVATE_ACCESSOR(clazz, cpptype, name, variable) \ - static void clazz ## _ ## name ## Read(QObject *o, qintptr, void *rv) \ + static void clazz ## _ ## name ## Read(QObject *o, void *rv) \ { \ clazz ## Private *d = clazz ## Private::get(static_cast<clazz *>(o)); \ *static_cast<cpptype *>(rv) = d->variable; \ @@ -114,8 +114,8 @@ class QQmlNotifier; class QQmlAccessors { public: - void (*read)(QObject *object, qintptr property, void *output); - void (*notifier)(QObject *object, qintptr property, QQmlNotifier **notifier); + void (*read)(QObject *object, void *output); + void (*notifier)(QObject *object, QQmlNotifier **notifier); }; namespace QQmlAccessorProperties { diff --git a/src/qml/qml/qqmlapplicationengine.h b/src/qml/qml/qqmlapplicationengine.h index 59667a1841..ff7dce5f8b 100644 --- a/src/qml/qml/qqmlapplicationengine.h +++ b/src/qml/qml/qqmlapplicationengine.h @@ -53,9 +53,9 @@ class Q_QML_EXPORT QQmlApplicationEngine : public QQmlEngine { Q_OBJECT public: - QQmlApplicationEngine(QObject *parent=0); - QQmlApplicationEngine(const QUrl &url, QObject *parent=0); - QQmlApplicationEngine(const QString &filePath, QObject *parent=0); + QQmlApplicationEngine(QObject *parent = Q_NULLPTR); + QQmlApplicationEngine(const QUrl &url, QObject *parent = Q_NULLPTR); + QQmlApplicationEngine(const QString &filePath, QObject *parent = Q_NULLPTR); ~QQmlApplicationEngine(); QList<QObject*> rootObjects(); diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 0e226320d6..aefbf20aff 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -72,12 +72,12 @@ public: enum CompilationMode { PreferSynchronous, Asynchronous }; Q_ENUM(CompilationMode) - QQmlComponent(QObject *parent = 0); - QQmlComponent(QQmlEngine *, QObject *parent=0); - QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = 0); - QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = 0); - QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = 0); - QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = 0); + QQmlComponent(QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QString &fileName, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QString &fileName, CompilationMode mode, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QUrl &url, QObject *parent = Q_NULLPTR); + QQmlComponent(QQmlEngine *, const QUrl &url, CompilationMode mode, QObject *parent = Q_NULLPTR); virtual ~QQmlComponent(); enum Status { Null, Ready, Loading, Error }; @@ -96,12 +96,12 @@ public: QUrl url() const; - virtual QObject *create(QQmlContext *context = 0); + virtual QObject *create(QQmlContext *context = Q_NULLPTR); virtual QObject *beginCreate(QQmlContext *); virtual void completeCreate(); - void create(QQmlIncubator &, QQmlContext *context = 0, - QQmlContext *forContext = 0); + void create(QQmlIncubator &, QQmlContext *context = Q_NULLPTR, + QQmlContext *forContext = Q_NULLPTR); QQmlContext *creationContext() const; diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index f759f46af5..65a337f4e5 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -95,7 +95,7 @@ QQmlContextPrivate::QQmlContextPrivate() by name in the context, as though they were all individually added through calls to QQmlContext::setContextProperty(). Changes to the property's values are detected through the property's notify signal. Setting a context object is both - faster and easier than manually adding and maintaing context property values. + faster and easier than manually adding and maintaining context property values. The following example has the same effect as the previous one, but it uses a context object. diff --git a/src/qml/qml/qqmlcontext.h b/src/qml/qml/qqmlcontext.h index c6b5d44f5a..781eac44fc 100644 --- a/src/qml/qml/qqmlcontext.h +++ b/src/qml/qml/qqmlcontext.h @@ -62,8 +62,8 @@ class Q_QML_EXPORT QQmlContext : public QObject Q_DECLARE_PRIVATE(QQmlContext) public: - QQmlContext(QQmlEngine *parent, QObject *objParent=0); - QQmlContext(QQmlContext *parent, QObject *objParent=0); + QQmlContext(QQmlEngine *parent, QObject *objParent = Q_NULLPTR); + QQmlContext(QQmlContext *parent, QObject *objParent = Q_NULLPTR); virtual ~QQmlContext(); bool isValid() const; diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 057f4b54c0..48d596418d 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -66,6 +66,7 @@ #include <private/qflagpointer_p.h> #include <private/qqmlguard_p.h> +#include <private/qv4compileddata_p.h> #include <private/qv4identifier_p.h> QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index 28bd66047e..132af78f80 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -97,7 +97,7 @@ class Q_QML_EXPORT QQmlEngine : public QJSEngine Q_PROPERTY(QString offlineStoragePath READ offlineStoragePath WRITE setOfflineStoragePath) Q_OBJECT public: - QQmlEngine(QObject *p = 0); + explicit QQmlEngine(QObject *p = Q_NULLPTR); virtual ~QQmlEngine(); QQmlContext *rootContext() const; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 7258ffe6ed..795a505742 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -375,7 +375,7 @@ const QQmlEnginePrivate *QQmlEnginePrivate::get(const QQmlEngine *e) { Q_ASSERT(e); - return e->d_func(); + return e ? e->d_func() : nullptr; } QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlContext *c) diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h index 0aff4884f9..5239d59c8a 100644 --- a/src/qml/qml/qqmlexpression.h +++ b/src/qml/qml/qqmlexpression.h @@ -60,8 +60,8 @@ class Q_QML_EXPORT QQmlExpression : public QObject Q_OBJECT public: QQmlExpression(); - QQmlExpression(QQmlContext *, QObject *, const QString &, QObject * = 0); - explicit QQmlExpression(const QQmlScriptString &, QQmlContext * = 0, QObject * = 0, QObject * = 0); + QQmlExpression(QQmlContext *, QObject *, const QString &, QObject * = Q_NULLPTR); + explicit QQmlExpression(const QQmlScriptString &, QQmlContext * = Q_NULLPTR, QObject * = Q_NULLPTR, QObject * = Q_NULLPTR); virtual ~QQmlExpression(); QQmlEngine *engine() const; @@ -84,7 +84,7 @@ public: void clearError(); QQmlError error() const; - QVariant evaluate(bool *valueIsUndefined = 0); + QVariant evaluate(bool *valueIsUndefined = Q_NULLPTR); Q_SIGNALS: void valueChanged(); diff --git a/src/qml/qml/qqmlextensionplugin.h b/src/qml/qml/qqmlextensionplugin.h index d0ee16ac50..de482d0352 100644 --- a/src/qml/qml/qqmlextensionplugin.h +++ b/src/qml/qml/qqmlextensionplugin.h @@ -58,7 +58,7 @@ class Q_QML_EXPORT QQmlExtensionPlugin Q_INTERFACES(QQmlExtensionInterface) Q_INTERFACES(QQmlTypesExtensionInterface) public: - explicit QQmlExtensionPlugin(QObject *parent = 0); + explicit QQmlExtensionPlugin(QObject *parent = Q_NULLPTR); ~QQmlExtensionPlugin(); QUrl baseUrl() const; diff --git a/src/qml/qml/qqmlfileselector.h b/src/qml/qml/qqmlfileselector.h index 34ba4d7a56..03b951420e 100644 --- a/src/qml/qml/qqmlfileselector.h +++ b/src/qml/qml/qqmlfileselector.h @@ -54,7 +54,7 @@ class Q_QML_EXPORT QQmlFileSelector : public QObject Q_OBJECT Q_DECLARE_PRIVATE(QQmlFileSelector) public: - QQmlFileSelector(QQmlEngine* engine, QObject* parent=0); + explicit QQmlFileSelector(QQmlEngine *engine, QObject *parent = Q_NULLPTR); ~QQmlFileSelector(); QFileSelector *selector() const Q_DECL_NOTHROW; void setSelector(QFileSelector *selector); diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 0014ccd3ba..d6c81bcc49 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -888,6 +888,11 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res } #endif +static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why) +{ + return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why); +} + /*! Import an extension defined by a qmldir file. @@ -949,7 +954,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, // The reason is that the lower level may add url and line/column numbering information. QQmlError poppedError = errors->takeFirst(); QQmlError error; - error.setDescription(QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description())); + error.setDescription(msgCannotLoadPlugin(uri, poppedError.description())); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } @@ -1020,10 +1025,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath, if (errors) { QQmlError error; - error.setDescription( - QQmlImportDatabase::tr( - "plugin cannot be loaded for module \"%1\": library loading is disabled") - .arg(uri)); + error.setDescription(msgCannotLoadPlugin(uri, QQmlImportDatabase::tr("library loading is disabled"))); error.setUrl(QUrl::fromLocalFile(qmldirFilePath)); errors->prepend(error); } diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index aef0916239..15d0a571a5 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -298,7 +298,7 @@ void QQmlPropertyCapture::registerQmlDependencies(QV4::ExecutionEngine *engine, // Let the caller check and avoid the function call :) Q_ASSERT(compiledFunction->hasQmlDependencies()); - QQmlEnginePrivate *ep = engine->qmlEngine() ? QQmlEnginePrivate::get(engine->qmlEngine()) : 0; + QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->qmlEngine()); if (!ep) return; QQmlPropertyCapture *capture = ep->propertyCapture; diff --git a/src/qml/qml/qqmllist.h b/src/qml/qml/qqmllist.h index dd548168c3..e3955deee5 100644 --- a/src/qml/qml/qqmllist.h +++ b/src/qml/qml/qqmllist.h @@ -61,15 +61,41 @@ public: typedef void (*ClearFunction)(QQmlListProperty<T> *); QQmlListProperty() - : object(0), data(0), append(0), count(0), at(0), clear(0), dummy1(0), dummy2(0) {} + : object(Q_NULLPTR), + data(Q_NULLPTR), + append(Q_NULLPTR), + count(Q_NULLPTR), + at(Q_NULLPTR), + clear(Q_NULLPTR), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} QQmlListProperty(QObject *o, QList<T *> &list) : object(o), data(&list), append(qlist_append), count(qlist_count), at(qlist_at), - clear(qlist_clear), dummy1(0), dummy2(0) {} + clear(qlist_clear), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} QQmlListProperty(QObject *o, void *d, AppendFunction a, CountFunction c, AtFunction t, ClearFunction r ) - : object(o), data(d), append(a), count(c), at(t), clear(r), dummy1(0), dummy2(0) {} + : object(o), + data(d), + append(a), + count(c), + at(t), + clear(r), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} QQmlListProperty(QObject *o, void *d, CountFunction c, AtFunction t) - : object(o), data(d), append(0), count(c), at(t), clear(0), dummy1(0), dummy2(0) {} + : object(o), + data(d), + append(Q_NULLPTR), + count(c), at(t), + clear(Q_NULLPTR), + dummy1(Q_NULLPTR), + dummy2(Q_NULLPTR) + {} bool operator==(const QQmlListProperty &o) const { return object == o.object && data == o.data && @@ -114,7 +140,7 @@ class Q_QML_EXPORT QQmlListReference { public: QQmlListReference(); - QQmlListReference(QObject *, const char *property, QQmlEngine * = 0); + QQmlListReference(QObject *, const char *property, QQmlEngine * = Q_NULLPTR); QQmlListReference(const QQmlListReference &); QQmlListReference &operator=(const QQmlListReference &); ~QQmlListReference(); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 1a7896bde8..29fff04325 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -716,6 +716,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *property, con QQmlTypeNameCache::Result res = context->imports->query(stringAt(binding->propertyNameIndex)); if (res.isValid()) attachedType = res.type; + else + return false; } const int id = attachedType->attachedPropertiesId(QQmlEnginePrivate::get(engine)); QObject *qmlObject = qmlAttachedPropertiesObjectById(id, _qobject); diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index 357b5ae577..3be52cf461 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -698,7 +698,6 @@ void QQmlPropertyCache::append(const QMetaObject *metaObject, if (accessorProperty) { data->flags |= QQmlPropertyData::HasAccessors; data->accessors = accessorProperty->accessors; - data->accessorData = accessorProperty->data; } else if (old) { data->markAsOverrideOf(old); } diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h index 0b3573c58c..4ff5ee89f9 100644 --- a/src/qml/qml/qqmlpropertycache_p.h +++ b/src/qml/qml/qqmlpropertycache_p.h @@ -209,7 +209,6 @@ public: }; struct { // When HasAccessors QQmlAccessors *accessors; - qintptr accessorData; }; }; int coreIndex; diff --git a/src/qml/types/qqmllistmodelworkeragent_p.h b/src/qml/types/qqmllistmodelworkeragent_p.h index 0c639b140d..f9872a6ad4 100644 --- a/src/qml/types/qqmllistmodelworkeragent_p.h +++ b/src/qml/types/qqmllistmodelworkeragent_p.h @@ -97,7 +97,8 @@ public: VariantRef &operator=(const VariantRef &o) { if (o.a) o.a->addref(); - if (a) a->release(); a = o.a; + if (a) a->release(); + a = o.a; return *this; } diff --git a/src/qml/util/qqmlpropertymap.h b/src/qml/util/qqmlpropertymap.h index ea1561bc60..01048f3662 100644 --- a/src/qml/util/qqmlpropertymap.h +++ b/src/qml/util/qqmlpropertymap.h @@ -55,7 +55,7 @@ class Q_QML_EXPORT QQmlPropertyMap : public QObject { Q_OBJECT public: - explicit QQmlPropertyMap(QObject *parent = 0); + explicit QQmlPropertyMap(QObject *parent = Q_NULLPTR); virtual ~QQmlPropertyMap(); QVariant value(const QString &key) const; diff --git a/src/qmldebug/qqmldebugconnection.cpp b/src/qmldebug/qqmldebugconnection.cpp index 37b66889cd..35a540bff8 100644 --- a/src/qmldebug/qqmldebugconnection.cpp +++ b/src/qmldebug/qqmldebugconnection.cpp @@ -106,7 +106,8 @@ void QQmlDebugConnection::socketConnected() { Q_D(QQmlDebugConnection); QPacket pack(d->currentDataStreamVersion); - pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion; + pack << serverId << 0 << protocolVersion << d->plugins.keys() << d->maximumDataStreamVersion + << true; // We accept multiple messages per packet d->protocol->send(pack.data()); d->flush(); } @@ -221,9 +222,6 @@ void QQmlDebugConnection::protocolReadyRead() qWarning() << "QQmlDebugConnection: Unknown control message id" << op; } } else { - QByteArray message; - pack >> message; - QHash<QString, QQmlDebugClient *>::Iterator iter = d->plugins.find(name); if (iter == d->plugins.end()) { // We can get more messages for plugins we have removed because it takes time to @@ -232,7 +230,12 @@ void QQmlDebugConnection::protocolReadyRead() qWarning() << "QQmlDebugConnection: Message received for missing plugin" << name; } else { - (*iter)->messageReceived(message); + QQmlDebugClient *client = *iter; + QByteArray message; + while (!pack.atEnd()) { + pack >> message; + client->messageReceived(message); + } } } } diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 630e0f58bc..6e6e66e026 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! -\qmlmodule QtQuick 2.5 +\qmlmodule QtQuick 2.7 \title Qt Quick QML Types \ingroup qmlmodules \brief Provides graphical QML types. @@ -34,11 +34,11 @@ The \l{Qt Quick} module provides graphical primitive types. These types are only available in a QML document if that document imports the \c QtQuick namespace. -The current version of the \c QtQuick module is version 2.5, and thus it may be +The current version of the \c QtQuick module is version 2.7, and thus it may be imported via the following statement: \qml -import QtQuick 2.5 +import QtQuick 2.7 \endqml Visit the \l {Qt Quick} module documentation for more diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index f5df5763bb..c32e9546a5 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -316,8 +316,6 @@ struct AnimatedSpriteVertices { //TODO: Implicitly size element to size of sprite QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) : QQuickItem(parent) - , m_node(0) - , m_material(0) , m_sprite(new QQuickSprite(this)) , m_spriteEngine(0) , m_curFrame(0) @@ -331,9 +329,9 @@ QQuickAnimatedSprite::QQuickAnimatedSprite(QQuickItem *parent) : { setFlag(ItemHasContents); connect(this, SIGNAL(widthChanged()), - this, SLOT(sizeVertices())); + this, SLOT(reset())); connect(this, SIGNAL(heightChanged()), - this, SLOT(sizeVertices())); + this, SLOT(reset())); } bool QQuickAnimatedSprite::isCurrentFrameChangedConnected() @@ -461,12 +459,9 @@ static QSGGeometry::AttributeSet AnimatedSprite_AttributeSet = AnimatedSprite_Attributes }; -void QQuickAnimatedSprite::sizeVertices() +void QQuickAnimatedSprite::sizeVertices(QSGGeometryNode *node) { - if (!m_node) - return; - - AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) m_node->geometry()->vertexData(); + AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) node->geometry()->vertexData(); p->v1.x = 0; p->v1.y = 0; @@ -494,21 +489,21 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() return 0; } - m_material = new QQuickAnimatedSpriteMaterial(); + QQuickAnimatedSpriteMaterial *material = new QQuickAnimatedSpriteMaterial(); QImage image = m_spriteEngine->assembledImage(); //Engine prints errors if there are any if (image.isNull()) return 0; m_sheetSize = QSizeF(image.size()); - m_material->texture = window()->createTextureFromImage(image); + material->texture = window()->createTextureFromImage(image); m_spriteEngine->start(0); - m_material->animT = 0; - m_material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); - m_material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); - m_material->animX2 = m_material->animX1; - m_material->animY2 = m_material->animY1; - m_material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); - m_material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); + material->animT = 0; + material->animX1 = m_spriteEngine->spriteX() / m_sheetSize.width(); + material->animY1 = m_spriteEngine->spriteY() / m_sheetSize.height(); + material->animX2 = material->animX1; + material->animY2 = material->animY1; + material->animW = m_spriteEngine->spriteWidth() / m_sheetSize.width(); + material->animH = m_spriteEngine->spriteHeight() / m_sheetSize.height(); int vCount = 4; int iCount = 6; @@ -517,7 +512,7 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() AnimatedSpriteVertices *p = (AnimatedSpriteVertices *) g->vertexData(); - QRectF texRect = m_material->texture->normalizedTextureSubRect(); + QRectF texRect = material->texture->normalizedTextureSubRect(); p->v1.tx = texRect.topLeft().x(); p->v1.ty = texRect.topLeft().y(); @@ -540,51 +535,51 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() indices[5] = 2; - m_node = new QSGGeometryNode(); - m_node->setGeometry(g); - m_node->setMaterial(m_material); - m_node->setFlag(QSGGeometryNode::OwnsMaterial); - m_node->setFlag(QSGGeometryNode::OwnsGeometry); - sizeVertices(); - return m_node; + QSGGeometryNode *node = new QSGGeometryNode(); + node->setGeometry(g); + node->setMaterial(material); + node->setFlag(QSGGeometryNode::OwnsMaterial); + node->setFlag(QSGGeometryNode::OwnsGeometry); + sizeVertices(node); + return node; } void QQuickAnimatedSprite::reset() { m_pleaseReset = true; + update(); } -QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *, UpdatePaintNodeData *) +QSGNode *QQuickAnimatedSprite::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { if (m_pleaseReset) { - delete m_node; + delete oldNode; - m_node = 0; - m_material = 0; + oldNode = 0; m_pleaseReset = false; } - prepareNextFrame(); + QSGGeometryNode *node = static_cast<QSGGeometryNode *>(oldNode); + if (!node) + node = buildNode(); + + if (node) + prepareNextFrame(node); if (m_running) { if (!m_paused) update(); - if (m_node) { - m_node->markDirty(QSGNode::DirtyMaterial); + if (node) { + node->markDirty(QSGNode::DirtyMaterial); } } - return m_node; + return node; } -void QQuickAnimatedSprite::prepareNextFrame() +void QQuickAnimatedSprite::prepareNextFrame(QSGGeometryNode *node) { - if (m_node == 0) - m_node = buildNode(); - if (m_node == 0) //error creating node - return; - int timeInt = m_timestamp.elapsed() + m_pauseOffset; qreal time = timeInt / 1000.; @@ -700,14 +695,15 @@ void QQuickAnimatedSprite::prepareNextFrame() } } - m_material->animX1 = x1; - m_material->animY1 = y1; - m_material->animX2 = x2; - m_material->animY2 = y2; - m_material->animW = w; - m_material->animH = h; - m_material->animT = m_interpolate ? progress : 0.0; - m_material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); + QQuickAnimatedSpriteMaterial *material = static_cast<QQuickAnimatedSpriteMaterial *>(node->material()); + material->animX1 = x1; + material->animY1 = y1; + material->animX2 = x2; + material->animY2 = y2; + material->animW = w; + material->animH = h; + material->animT = m_interpolate ? progress : 0.0; + material->texture->setFiltering(smooth() ? QSGTexture::Linear : QSGTexture::Nearest); } QT_END_NAMESPACE diff --git a/src/quick/items/qquickanimatedsprite_p.h b/src/quick/items/qquickanimatedsprite_p.h index 6b49d903df..1e5981c1a4 100644 --- a/src/quick/items/qquickanimatedsprite_p.h +++ b/src/quick/items/qquickanimatedsprite_p.h @@ -357,19 +357,19 @@ public Q_SLOTS: private Q_SLOTS: void createEngine(); - void sizeVertices(); + void sizeVertices(QSGGeometryNode *node); -protected: +protected Q_SLOTS: void reset(); + +protected: void componentComplete() Q_DECL_OVERRIDE; QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; private: bool isCurrentFrameChangedConnected(); - void prepareNextFrame(); + void prepareNextFrame(QSGGeometryNode *node); void reloadImage(); QSGGeometryNode* buildNode(); - QSGGeometryNode *m_node; - QQuickAnimatedSpriteMaterial *m_material; QQuickSprite* m_sprite; QQuickSpriteEngine* m_spriteEngine; QElapsedTimer m_timestamp; diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp index 5bfbaf74b2..4aa54b71df 100644 --- a/src/quick/items/qquickdrag.cpp +++ b/src/quick/items/qquickdrag.cpp @@ -46,6 +46,7 @@ #include <QtQuick/private/qquickevents_p_p.h> #include <private/qquickitemchangelistener_p.h> #include <private/qv8engine_p.h> +#include <private/qv4scopedvalue_p.h> #include <QtCore/qmimedata.h> #include <QtQml/qqmlinfo.h> #include <QtGui/qdrag.h> diff --git a/src/quick/items/qquickevents.cpp b/src/quick/items/qquickevents.cpp index 7706412a5f..5061c19f1e 100644 --- a/src/quick/items/qquickevents.cpp +++ b/src/quick/items/qquickevents.cpp @@ -263,6 +263,56 @@ Item { \endqml */ +/*! + \qmlproperty int QtQuick::MouseEvent::source + \since 5.7 + + This property holds the source of the mouse event. + + The mouse event source can be used to distinguish between genuine and + artificial mouse events. When using other pointing devices such as + touchscreens and graphics tablets, if the application does not make use of + the actual touch or tablet events, mouse events may be synthesized by the + operating system or by Qt itself. + + The value can be one of: + + \value Qt.MouseEventNotSynthesized The most common value. On platforms where + such information is available, this value indicates that the event + represents a genuine mouse event from the system. + + \value Qt.MouseEventSynthesizedBySystem Indicates that the mouse event was + synthesized from a touch or tablet event by the platform. + + \value Qt.MouseEventSynthesizedByQt Indicates that the mouse event was + synthesized from an unhandled touch or tablet event by Qt. + + \value Qt.MouseEventSynthesizedByApplication Indicates that the mouse event + was synthesized by the application. This allows distinguishing + application-generated mouse events from the ones that are coming from the + system or are synthesized by Qt. + + For example, to react only to events which come from an actual mouse: + \qml + MouseArea { + onPressed: if (mouse.source !== Qt.MouseEventNotSynthesized) { + mouse.accepted = false + } + + onClicked: doSomething() + } + \endqml + + If the handler for the press event rejects the event, it will be propagated + further, and then another Item underneath can handle synthesized events + from touchscreens. For example, if a Flickable is used underneath (and the + MouseArea is not a child of the Flickable), it can be useful for the + MouseArea to handle genuine mouse events in one way, while allowing touch + events to fall through to the Flickable underneath, so that the ability to + flick on a touchscreen is retained. In that case the ability to drag the + Flickable via mouse would be lost, but it does not prevent Flickable from + receiving mouse wheel events. +*/ /*! \qmltype WheelEvent diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h index f0d7769705..b28ab555b0 100644 --- a/src/quick/items/qquickevents_p_p.h +++ b/src/quick/items/qquickevents_p_p.h @@ -103,6 +103,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject Q_PROPERTY(int button READ button) Q_PROPERTY(int buttons READ buttons) Q_PROPERTY(int modifiers READ modifiers) + Q_PROPERTY(int source READ source REVISION 7) Q_PROPERTY(bool wasHeld READ wasHeld) Q_PROPERTY(bool isClick READ isClick) Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted) @@ -111,13 +112,14 @@ public: QQuickMouseEvent(qreal x, qreal y, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers , bool isClick=false, bool wasHeld=false) : _x(x), _y(y), _button(button), _buttons(buttons), _modifiers(modifiers) - , _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {} + , _source(Qt::MouseEventNotSynthesized), _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {} qreal x() const { return _x; } qreal y() const { return _y; } int button() const { return _button; } int buttons() const { return _buttons; } int modifiers() const { return _modifiers; } + int source() const { return _source; } bool wasHeld() const { return _wasHeld; } bool isClick() const { return _isClick; } @@ -125,6 +127,7 @@ public: void setX(qreal x) { _x = x; } void setY(qreal y) { _y = y; } void setPosition(const QPointF &point) { _x = point.x(); _y = point.y(); } + void setSource(Qt::MouseEventSource s) { _source = s; } bool isAccepted() { return _accepted; } void setAccepted(bool accepted) { _accepted = accepted; } @@ -135,6 +138,7 @@ private: Qt::MouseButton _button; Qt::MouseButtons _buttons; Qt::KeyboardModifiers _modifiers; + Qt::MouseEventSource _source; bool _wasHeld; bool _isClick; bool _accepted; diff --git a/src/quick/items/qquickframebufferobject.h b/src/quick/items/qquickframebufferobject.h index 446cfed22b..13eeb931ad 100644 --- a/src/quick/items/qquickframebufferobject.h +++ b/src/quick/items/qquickframebufferobject.h @@ -75,7 +75,7 @@ public: void *data; }; - QQuickFramebufferObject(QQuickItem *parent = 0); + QQuickFramebufferObject(QQuickItem *parent = Q_NULLPTR); bool textureFollowsItemSize() const; void setTextureFollowsItemSize(bool follows); diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index ca7c5b224c..da89a51f24 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -109,7 +109,7 @@ void debugFocusTree(QQuickItem *item, QQuickItem *scope = 0, int depth = 1) } } -static void QQuickItem_parentNotifier(QObject *o, qintptr, QQmlNotifier **n) +static void QQuickItem_parentNotifier(QObject *o, QQmlNotifier **n) { QQuickItemPrivate *d = QQuickItemPrivate::get(static_cast<QQuickItem *>(o)); *n = &d->parentNotifier; diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 839cdf2d90..4fd65fbb01 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -59,7 +59,7 @@ class Q_QUICK_EXPORT QQuickTransform : public QObject { Q_OBJECT public: - QQuickTransform(QObject *parent = 0); + explicit QQuickTransform(QObject *parent = Q_NULLPTR); ~QQuickTransform(); void appendToItem(QQuickItem *); @@ -195,7 +195,7 @@ public: }; Q_ENUM(TransformOrigin) - QQuickItem(QQuickItem *parent = 0); + explicit QQuickItem(QQuickItem *parent = Q_NULLPTR); virtual ~QQuickItem(); QQuickWindow *window() const; @@ -441,7 +441,7 @@ protected: virtual void updatePolish(); protected: - QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = 0); + QQuickItem(QQuickItemPrivate &dd, QQuickItem *parent = Q_NULLPTR); private: Q_PRIVATE_SLOT(d_func(), void _q_resourceObjectDeleted(QObject *)) diff --git a/src/quick/items/qquickitemgrabresult.h b/src/quick/items/qquickitemgrabresult.h index 15399010dd..42d71862de 100644 --- a/src/quick/items/qquickitemgrabresult.h +++ b/src/quick/items/qquickitemgrabresult.h @@ -79,7 +79,7 @@ private Q_SLOTS: private: friend class QQuickItem; - QQuickItemGrabResult(QObject *parent = 0); + QQuickItemGrabResult(QObject *parent = Q_NULLPTR); }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index 465db4dd76..00837363ab 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -290,6 +290,8 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) qmlRegisterType<QQuickGridView, 7>(uri, 2, 7, "GridView"); qmlRegisterType<QQuickTextInput, 7>(uri, 2, 7, "TextInput"); qmlRegisterType<QQuickTextEdit, 7>(uri, 2, 7, "TextEdit"); + + qmlRegisterUncreatableType<QQuickMouseEvent, 7>(uri, 2, 7, nullptr, QQuickMouseEvent::tr("MouseEvent is only available within handlers in MouseArea")); } static void initResources() diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 188b347a20..aff03b7539 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1052,7 +1052,8 @@ QQuickItem *QQuickItemView::itemAt(qreal x, qreal y) const void QQuickItemView::forceLayout() { Q_D(QQuickItemView); - d->applyPendingChanges(); + if (isComponentComplete() && (d->currentChanges.hasPendingChanges() || d->forceLayout)) + d->layout(); } void QQuickItemViewPrivate::applyPendingChanges() diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 42de98eff7..920a86881b 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -685,7 +685,7 @@ void QQuickMouseArea::mousePressEvent(QMouseEvent *event) d->startScene = event->windowPos(); d->pressAndHoldTimer.start(QGuiApplication::styleHints()->mousePressAndHoldInterval(), this); setKeepMouseGrab(d->stealMouse); - event->setAccepted(setPressed(event->button(), true)); + event->setAccepted(setPressed(event->button(), true, event->source())); } } @@ -762,6 +762,7 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event) #endif QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress); + me.setSource(event->source()); emit mouseXChanged(&me); me.setPosition(d->lastPos); emit mouseYChanged(&me); @@ -777,7 +778,7 @@ void QQuickMouseArea::mouseReleaseEvent(QMouseEvent *event) QQuickItem::mouseReleaseEvent(event); } else { d->saveEvent(event); - setPressed(event->button(), false); + setPressed(event->button(), false, event->source()); if (!d->pressed) { // no other buttons are pressed #ifndef QT_NO_DRAGANDDROP @@ -802,6 +803,7 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event) if (d->enabled) { d->saveEvent(event); QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false); + me.setSource(event->source()); me.setAccepted(d->isDoubleClickConnected()); emit this->doubleClicked(&me); if (!me.isAccepted()) @@ -996,6 +998,7 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event) if (d->pressed && dragged == false && d->hovered == true) { d->longPress = true; QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress); + me.setSource(Qt::MouseEventSynthesizedByQt); me.setAccepted(d->isPressAndHoldConnected()); emit pressAndHold(&me); if (!me.isAccepted()) @@ -1158,7 +1161,7 @@ void QQuickMouseArea::setAcceptedButtons(Qt::MouseButtons buttons) } } -bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p) +bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source) { Q_D(QQuickMouseArea); @@ -1173,6 +1176,7 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p) if (wasPressed != p) { QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress); + me.setSource(source); if (p) { d->pressed |= button; if (!d->doubleClick) diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h index ae3e3b1e5a..5cd86541d4 100644 --- a/src/quick/items/qquickmousearea_p.h +++ b/src/quick/items/qquickmousearea_p.h @@ -155,7 +155,7 @@ Q_SIGNALS: protected: void setHovered(bool); - bool setPressed(Qt::MouseButton button, bool); + bool setPressed(Qt::MouseButton button, bool p, Qt::MouseEventSource source); bool sendMouseEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquickpainteditem.h b/src/quick/items/qquickpainteditem.h index 1e384a45e3..f9e3c91a42 100644 --- a/src/quick/items/qquickpainteditem.h +++ b/src/quick/items/qquickpainteditem.h @@ -57,7 +57,7 @@ class Q_QUICK_EXPORT QQuickPaintedItem : public QQuickItem Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged) public: - QQuickPaintedItem(QQuickItem *parent = 0); + explicit QQuickPaintedItem(QQuickItem *parent = Q_NULLPTR); virtual ~QQuickPaintedItem(); enum RenderTarget { @@ -118,7 +118,7 @@ Q_SIGNALS: void textureSizeChanged(); protected: - QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = 0); + QQuickPaintedItem(QQuickPaintedItemPrivate &dd, QQuickItem *parent = Q_NULLPTR); QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) Q_DECL_OVERRIDE; void releaseResources() Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp index 2594cc7f14..8ac002ed2c 100644 --- a/src/quick/items/qquickrendercontrol.cpp +++ b/src/quick/items/qquickrendercontrol.cpp @@ -57,6 +57,8 @@ #include <QtQuick/private/qquickwindow_p.h> #include <QtCore/private/qobject_p.h> +#include <private/qquickshadereffectnode_p.h> + QT_BEGIN_NAMESPACE #ifndef QT_NO_OPENGL extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); @@ -184,6 +186,8 @@ void QQuickRenderControlPrivate::windowDestroyed() delete QQuickWindowPrivate::get(window)->animationController; QQuickWindowPrivate::get(window)->animationController = 0; + QQuickShaderEffectMaterial::cleanupMaterialCache(); + window = 0; } } diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h index c5691b1329..31ea176cc1 100644 --- a/src/quick/items/qquickrendercontrol.h +++ b/src/quick/items/qquickrendercontrol.h @@ -55,7 +55,7 @@ class Q_QUICK_EXPORT QQuickRenderControl : public QObject Q_OBJECT public: - QQuickRenderControl(QObject *parent = 0); + explicit QQuickRenderControl(QObject *parent = Q_NULLPTR); ~QQuickRenderControl(); void prepareThread(QThread *targetThread); @@ -68,8 +68,8 @@ public: QImage grab(); - static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = 0); - virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return 0; } + static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = Q_NULLPTR); + virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return Q_NULLPTR; } Q_SIGNALS: void renderRequested(); diff --git a/src/quick/items/qquickscalegrid_p_p.h b/src/quick/items/qquickscalegrid_p_p.h index 8064a31377..a424002dfb 100644 --- a/src/quick/items/qquickscalegrid_p_p.h +++ b/src/quick/items/qquickscalegrid_p_p.h @@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE -class QQuickScaleGrid : public QObject +class Q_AUTOTEST_EXPORT QQuickScaleGrid : public QObject { Q_OBJECT diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index 05900bc12b..0cfb85db97 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -958,6 +958,12 @@ void QQuickShaderEffect::updateGeometry() update(); } +void QQuickShaderEffect::updateGeometryIfAtlased() +{ + if (m_supportsAtlasTextures) + updateGeometry(); +} + void QQuickShaderEffect::updateLogAndStatus(const QString &log, int status) { m_log = parseLog() + log; @@ -1006,6 +1012,8 @@ QSGNode *QQuickShaderEffect::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeDa m_dirtyUniforms = true; m_dirtyGeometry = true; connect(node, SIGNAL(logAndStatusChanged(QString,int)), this, SLOT(updateLogAndStatus(QString,int))); + connect(node, &QQuickShaderEffectNode::dirtyTexture, + this, &QQuickShaderEffect::updateGeometryIfAtlased); } QQuickShaderEffectMaterial *material = static_cast<QQuickShaderEffectMaterial *>(node->material()); diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index 23557e52fa..fb266d4c44 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -173,6 +173,7 @@ protected: private Q_SLOTS: void updateGeometry(); + void updateGeometryIfAtlased(); void updateLogAndStatus(const QString &log, int status); void sourceDestroyed(QObject *object); void propertyChanged(int mappedId); diff --git a/src/quick/items/qquickshadereffectnode.cpp b/src/quick/items/qquickshadereffectnode.cpp index 8040bbe754..66154fac6d 100644 --- a/src/quick/items/qquickshadereffectnode.cpp +++ b/src/quick/items/qquickshadereffectnode.cpp @@ -497,6 +497,7 @@ QQuickShaderEffectNode::~QQuickShaderEffectNode() void QQuickShaderEffectNode::markDirtyTexture() { markDirty(DirtyMaterial); + Q_EMIT dirtyTexture(); } void QQuickShaderEffectNode::textureProviderDestroyed(QObject *object) diff --git a/src/quick/items/qquickshadereffectnode_p.h b/src/quick/items/qquickshadereffectnode_p.h index 570a0c3213..cc016d13a7 100644 --- a/src/quick/items/qquickshadereffectnode_p.h +++ b/src/quick/items/qquickshadereffectnode_p.h @@ -148,6 +148,7 @@ public: Q_SIGNALS: void logAndStatusChanged(const QString &, int status); + void dirtyTexture(); private Q_SLOTS: void markDirtyTexture(); diff --git a/src/quick/items/qquickshadereffectsource.cpp b/src/quick/items/qquickshadereffectsource.cpp index 0dd783da0a..338e4dc3a7 100644 --- a/src/quick/items/qquickshadereffectsource.cpp +++ b/src/quick/items/qquickshadereffectsource.cpp @@ -268,6 +268,8 @@ QSGTextureProvider *QQuickShaderEffectSource::textureProvider() const Modifying this property makes most sense when the item is used as a source texture of a \l ShaderEffect. + The default value is \c{ShaderEffectSource.ClampToEdge}. + \list \li ShaderEffectSource.ClampToEdge - GL_CLAMP_TO_EDGE both horizontally and vertically \li ShaderEffectSource.RepeatHorizontally - GL_REPEAT horizontally, GL_CLAMP_TO_EDGE vertically diff --git a/src/quick/items/qquicksprite.cpp b/src/quick/items/qquicksprite.cpp index 6429c0d668..63d3180842 100644 --- a/src/quick/items/qquicksprite.cpp +++ b/src/quick/items/qquicksprite.cpp @@ -224,6 +224,11 @@ QQuickSprite::QQuickSprite(QObject *parent) { } +/*! \internal */ +QQuickSprite::~QQuickSprite() +{ +} + int QQuickSprite::variedDuration() const //Deals with precedence when multiple durations are set { if (m_frameSync) diff --git a/src/quick/items/qquicksprite_p.h b/src/quick/items/qquicksprite_p.h index 3a91b3374a..1b8c8cee84 100644 --- a/src/quick/items/qquicksprite_p.h +++ b/src/quick/items/qquicksprite_p.h @@ -61,7 +61,8 @@ QT_BEGIN_NAMESPACE -class QQuickSprite : public QQuickStochasticState +// exported, since it's used in QtQuickParticles +class Q_QUICK_EXPORT QQuickSprite : public QQuickStochasticState { Q_OBJECT Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) @@ -84,6 +85,7 @@ class QQuickSprite : public QQuickStochasticState public: explicit QQuickSprite(QObject *parent = 0); + ~QQuickSprite(); QUrl source() const { diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index d2b719e8ef..a44f549b37 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1567,8 +1567,7 @@ void QQuickTextEdit::setReadOnly(bool r) if (!r) flags = flags | Qt::TextEditable; d->control->setTextInteractionFlags(flags); - if (!r) - d->control->moveCursor(QTextCursor::End); + d->control->moveCursor(QTextCursor::End); #ifndef QT_NO_IM updateInputMethod(Qt::ImEnabled); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 3b1901e075..fec9beedf6 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -43,7 +43,7 @@ #include "qquicktextutil_p.h" #include <private/qqmlglobal_p.h> - +#include <private/qv4scopedvalue_p.h> #include <QtCore/qcoreapplication.h> #include <QtCore/qmimedata.h> @@ -711,8 +711,7 @@ void QQuickTextInput::setReadOnly(bool ro) setFlag(QQuickItem::ItemAcceptsInputMethod, !ro); #endif d->m_readOnly = ro; - if (!ro) - d->setCursorPosition(d->end()); + d->setCursorPosition(d->end()); #ifndef QT_NO_IM updateInputMethod(Qt::ImEnabled); #endif @@ -1970,11 +1969,15 @@ bool QQuickTextInput::isRightToLeft(int start, int end) \qmlmethod QtQuick::TextInput::cut() Moves the currently selected text to the system clipboard. + + \note If the echo mode is set to a mode other than Normal then cut + will not work. This is to prevent using cut as a method of bypassing + password features of the line control. */ void QQuickTextInput::cut() { Q_D(QQuickTextInput); - if (!d->m_readOnly) { + if (!d->m_readOnly && d->m_echoMode == QQuickTextInput::Normal) { d->copy(); d->del(); } @@ -1984,6 +1987,10 @@ void QQuickTextInput::cut() \qmlmethod QtQuick::TextInput::copy() Copies the currently selected text to the system clipboard. + + \note If the echo mode is set to a mode other than Normal then copy + will not work. This is to prevent using copy as a method of bypassing + password features of the line control. */ void QQuickTextInput::copy() { @@ -4363,10 +4370,7 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) } } else if (event == QKeySequence::Cut) { - if (!m_readOnly) { - copy(); - del(); - } + q->cut(); } else if (event == QKeySequence::DeleteEndOfLine) { if (!m_readOnly) diff --git a/src/quick/items/qquickview.h b/src/quick/items/qquickview.h index 29ce5b4935..1fcc34e3a1 100644 --- a/src/quick/items/qquickview.h +++ b/src/quick/items/qquickview.h @@ -60,9 +60,9 @@ class Q_QUICK_EXPORT QQuickView : public QQuickWindow Q_PROPERTY(Status status READ status NOTIFY statusChanged) Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true) public: - explicit QQuickView(QWindow *parent = 0); + explicit QQuickView(QWindow *parent = Q_NULLPTR); QQuickView(QQmlEngine* engine, QWindow *parent); - QQuickView(const QUrl &source, QWindow *parent = 0); + explicit QQuickView(const QUrl &source, QWindow *parent = Q_NULLPTR); virtual ~QQuickView(); QUrl source() const; diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 67947fc8b6..a932e7a508 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1822,7 +1822,7 @@ bool QQuickWindowPrivate::deliverWheelEvent(QQuickItem *item, QWheelEvent *event if (item->contains(p)) { QWheelEvent wheel(p, p, event->pixelDelta(), event->angleDelta(), event->delta(), - event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source()); + event->orientation(), event->buttons(), event->modifiers(), event->phase(), event->source(), event->inverted()); wheel.accept(); q->sendEvent(item, &wheel); if (wheel.isAccepted()) { diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 42617c9dbc..a4060541c0 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -95,7 +95,7 @@ public: }; Q_ENUM(SceneGraphError) - QQuickWindow(QWindow *parent = 0); + explicit QQuickWindow(QWindow *parent = Q_NULLPTR); explicit QQuickWindow(QQuickRenderControl *renderControl); virtual ~QQuickWindow(); @@ -129,7 +129,7 @@ public: // Scene graph specific functions QSGTexture *createTextureFromImage(const QImage &image) const; QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options) const; - QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption(0)) const; + QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; void setClearBeforeRendering(bool enabled); bool clearBeforeRendering() const; @@ -176,7 +176,7 @@ public Q_SLOTS: void releaseResources(); protected: - QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = 0); + QQuickWindow(QQuickWindowPrivate &dd, QWindow *parent = Q_NULLPTR); void exposeEvent(QExposeEvent *) Q_DECL_OVERRIDE; void resizeEvent(QResizeEvent *) Q_DECL_OVERRIDE; diff --git a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h index 50b9879659..eb9e7cea7c 100644 --- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h +++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h @@ -90,7 +90,7 @@ Q_SIGNALS: void sceneGraphChanged(); protected: - QSGAbstractRenderer(QObject *parent = 0); + explicit QSGAbstractRenderer(QObject *parent = Q_NULLPTR); virtual void nodeChanged(QSGNode *node, QSGNode::DirtyState state) = 0; private: diff --git a/src/quick/scenegraph/coreapi/qsgnode.h b/src/quick/scenegraph/coreapi/qsgnode.h index 74480aaca7..349753a361 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.h +++ b/src/quick/scenegraph/coreapi/qsgnode.h @@ -151,7 +151,7 @@ public: QT_DEPRECATED void clearDirty() { } void markDirty(DirtyState bits); - QT_DEPRECATED DirtyState dirtyState() const { return 0; } + QT_DEPRECATED DirtyState dirtyState() const { return Q_NULLPTR; } virtual bool isSubtreeBlocked() const; diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index edf3739d6c..06c4129a33 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -138,7 +138,7 @@ Atlas::Atlas(const QSize &size) if (QOpenGLContext::currentContext()->isOpenGLES()) { #endif -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) +#if defined(Q_OS_ANDROID) QString *deviceName = static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); static bool wrongfullyReportsBgra8888Support = deviceName != 0 diff --git a/src/quick/scenegraph/util/qsgengine.h b/src/quick/scenegraph/util/qsgengine.h index beeb8a543f..89af71fb47 100644 --- a/src/quick/scenegraph/util/qsgengine.h +++ b/src/quick/scenegraph/util/qsgengine.h @@ -63,15 +63,15 @@ public: }; Q_DECLARE_FLAGS(CreateTextureOptions, CreateTextureOption) - QSGEngine(QObject *parent = 0); + explicit QSGEngine(QObject *parent = Q_NULLPTR); ~QSGEngine(); void initialize(QOpenGLContext *context); void invalidate(); QSGAbstractRenderer *createRenderer() const; - QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption(0)) const; - QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption(0)) const; + QSGTexture *createTextureFromImage(const QImage &image, CreateTextureOptions options = CreateTextureOption()) const; + QSGTexture *createTextureFromId(uint id, const QSize &size, CreateTextureOptions options = CreateTextureOption()) const; }; QT_END_NAMESPACE diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 751406f12c..1ec1db5ab5 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -731,7 +731,7 @@ void QSGPlainTexture::bind() GLenum externalFormat = GL_RGBA; GLenum internalFormat = GL_RGBA; -#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_NO_SDK) +#if defined(Q_OS_ANDROID) QString *deviceName = static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); static bool wrongfullyReportsBgra8888Support = deviceName != 0 diff --git a/src/quick/util/qquickimageprovider.h b/src/quick/util/qquickimageprovider.h index 0813711e48..d4719a7f5b 100644 --- a/src/quick/util/qquickimageprovider.h +++ b/src/quick/util/qquickimageprovider.h @@ -87,7 +87,7 @@ Q_SIGNALS: class Q_QUICK_EXPORT QQuickImageProvider : public QQmlImageProviderBase { public: - QQuickImageProvider(ImageType type, Flags flags = 0); + QQuickImageProvider(ImageType type, Flags flags = Flags()); virtual ~QQuickImageProvider(); ImageType imageType() const; diff --git a/src/quick/util/qquickprofiler.cpp b/src/quick/util/qquickprofiler.cpp index dc72b5f287..f8d090cc2c 100644 --- a/src/quick/util/qquickprofiler.cpp +++ b/src/quick/util/qquickprofiler.cpp @@ -99,22 +99,22 @@ QQuickProfiler::~QQuickProfiler() void QQuickProfiler::startProfilingImpl(quint64 features) { QMutexLocker lock(&m_dataMutex); - m_data.clear(); featuresEnabled = features; } void QQuickProfiler::stopProfilingImpl() { - { - QMutexLocker lock(&m_dataMutex); - featuresEnabled = 0; - } + QMutexLocker lock(&m_dataMutex); + featuresEnabled = 0; emit dataReady(m_data); + m_data.clear(); } void QQuickProfiler::reportDataImpl() { + QMutexLocker lock(&m_dataMutex); emit dataReady(m_data); + m_data.clear(); } void QQuickProfiler::setTimer(const QElapsedTimer &t) diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index 2ee635d71a..0119aecb7e 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -61,10 +61,9 @@ QT_BEGIN_NAMESPACE /*! \qmltype PropertyChanges - \instantiates QQuickPropertyChanges \inqmlmodule QtQuick \ingroup qtquick-states - \brief Describes new property bindings or values for a state + \brief Describes new property bindings or values for a state. PropertyChanges is used to define the property values or bindings in a \l State. This enables an item's property values to be changed when it diff --git a/src/quickwidgets/qquickwidget.cpp b/src/quickwidgets/qquickwidget.cpp index c4e6e4ed98..0a10ec5e9c 100644 --- a/src/quickwidgets/qquickwidget.cpp +++ b/src/quickwidgets/qquickwidget.cpp @@ -990,7 +990,9 @@ QSize QQuickWidget::initialSize() const } /*! - Returns the view's root \l {QQuickItem} {item}. + Returns the view's root \l {QQuickItem} {item}. Can be null + when setContents/setSource has not been called, if they were called with + broken QtQuick code or while the QtQuick contents are being created. */ QQuickItem *QQuickWidget::rootObject() const { diff --git a/src/quickwidgets/qquickwidget.h b/src/quickwidgets/qquickwidget.h index 688cafd475..0732c506bb 100644 --- a/src/quickwidgets/qquickwidget.h +++ b/src/quickwidgets/qquickwidget.h @@ -64,9 +64,9 @@ class Q_QUICKWIDGETS_EXPORT QQuickWidget : public QWidget Q_PROPERTY(QUrl source READ source WRITE setSource DESIGNABLE true) public: - explicit QQuickWidget(QWidget *parent = 0); + explicit QQuickWidget(QWidget *parent = Q_NULLPTR); QQuickWidget(QQmlEngine* engine, QWidget *parent); - QQuickWidget(const QUrl &source, QWidget *parent = 0); + explicit QQuickWidget(const QUrl &source, QWidget *parent = Q_NULLPTR); virtual ~QQuickWidget(); QUrl source() const; |