aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndy Nichols <andy.nichols@theqtcompany.com>2016-04-05 12:09:51 +0200
committerAndy Nichols <andy.nichols@theqtcompany.com>2016-04-05 12:11:13 +0200
commit60da655dff4ffcc94d32a05bb5fa32240b0eaa0b (patch)
tree3f3f9d427570d505d8249053e9646af69a95e783 /src
parent17d435fd8b2ed3a8ac6f93d17d0e78cd61bd7851 (diff)
parentfcbbedc3c21ff69d9251264dd708d6ca66c09359 (diff)
Merge remote-tracking branch 'origin/5.7' into dev
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/masm/stubs/ExecutableAllocator.h4
-rw-r--r--src/3rdparty/masm/stubs/wtf/PassOwnPtr.h4
-rw-r--r--src/3rdparty/masm/stubs/wtf/PassRefPtr.h3
-rw-r--r--src/imports/testlib/SignalSpy.qml13
-rw-r--r--src/particles/qquickage.cpp30
-rw-r--r--src/particles/qquickcustomaffector.cpp34
-rw-r--r--src/particles/qquickcustomparticle.cpp11
-rw-r--r--src/particles/qquickfriction.cpp8
-rw-r--r--src/particles/qquickgravity.cpp4
-rw-r--r--src/particles/qquickimageparticle.cpp65
-rw-r--r--src/particles/qquickitemparticle.cpp46
-rw-r--r--src/particles/qquickparticleaffector.cpp34
-rw-r--r--src/particles/qquickparticleemitter.cpp26
-rw-r--r--src/particles/qquickparticleemitter_p.h26
-rw-r--r--src/particles/qquickparticlepainter.cpp52
-rw-r--r--src/particles/qquickparticlepainter_p.h37
-rw-r--r--src/particles/qquickparticlesystem.cpp324
-rw-r--r--src/particles/qquickparticlesystem_p.h284
-rw-r--r--src/particles/qquickpointattractor.cpp16
-rw-r--r--src/particles/qquickspritegoal.cpp2
-rw-r--r--src/particles/qquicktrailemitter.cpp21
-rw-r--r--src/particles/qquickturbulence.cpp8
-rw-r--r--src/particles/qquickv4particledata.cpp16
-rw-r--r--src/particles/qquickv4particledata_p.h3
-rw-r--r--src/particles/qquickwander.cpp24
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacket.cpp27
-rw-r--r--src/plugins/qmltooling/packetprotocol/qpacket_p.h4
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp8
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp15
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp55
-rw-r--r--src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h6
-rw-r--r--src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp8
-rw-r--r--src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp111
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp66
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp8
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp14
-rw-r--r--src/qml/compiler/qv4isel_util_p.h4
-rw-r--r--src/qml/compiler/qv4jsir.cpp343
-rw-r--r--src/qml/compiler/qv4jsir_p.h380
-rw-r--r--src/qml/compiler/qv4ssa.cpp338
-rw-r--r--src/qml/debugger/qqmlabstractprofileradapter_p.h2
-rw-r--r--src/qml/debugger/qqmldebug.cpp52
-rw-r--r--src/qml/debugger/qqmldebug.h3
-rw-r--r--src/qml/debugger/qqmldebugconnector.cpp13
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc2
-rw-r--r--src/qml/jit/qv4regalloc.cpp48
-rw-r--r--src/qml/jsapi/qjsengine.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp30
-rw-r--r--src/qml/jsruntime/qv4engine_p.h29
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp4
-rw-r--r--src/qml/jsruntime/qv4util_p.h127
-rw-r--r--src/qml/jsruntime/qv4value_p.h7
-rw-r--r--src/qml/parser/qqmljsmemorypool_p.h4
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h1
-rw-r--r--src/qml/qml/qqml.h55
-rw-r--r--src/qml/qml/qqmlaccessors_p.h6
-rw-r--r--src/qml/qml/qqmlapplicationengine.h6
-rw-r--r--src/qml/qml/qqmlcomponent.h18
-rw-r--r--src/qml/qml/qqmlcontext.cpp2
-rw-r--r--src/qml/qml/qqmlcontext.h4
-rw-r--r--src/qml/qml/qqmlcontext_p.h1
-rw-r--r--src/qml/qml/qqmlengine.h2
-rw-r--r--src/qml/qml/qqmlengine_p.h2
-rw-r--r--src/qml/qml/qqmlexpression.h6
-rw-r--r--src/qml/qml/qqmlextensionplugin.h2
-rw-r--r--src/qml/qml/qqmlfileselector.h2
-rw-r--r--src/qml/qml/qqmlimport.cpp12
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp2
-rw-r--r--src/qml/qml/qqmllist.h36
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp2
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp1
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h1
-rw-r--r--src/qml/types/qqmllistmodelworkeragent_p.h3
-rw-r--r--src/qml/util/qqmlpropertymap.h2
-rw-r--r--src/qmldebug/qqmldebugconnection.cpp13
-rw-r--r--src/quick/doc/src/qmltypereference.qdoc6
-rw-r--r--src/quick/items/qquickanimatedsprite.cpp92
-rw-r--r--src/quick/items/qquickanimatedsprite_p.h10
-rw-r--r--src/quick/items/qquickdrag.cpp1
-rw-r--r--src/quick/items/qquickevents.cpp50
-rw-r--r--src/quick/items/qquickevents_p_p.h6
-rw-r--r--src/quick/items/qquickframebufferobject.h2
-rw-r--r--src/quick/items/qquickitem.cpp2
-rw-r--r--src/quick/items/qquickitem.h6
-rw-r--r--src/quick/items/qquickitemgrabresult.h2
-rw-r--r--src/quick/items/qquickitemsmodule.cpp2
-rw-r--r--src/quick/items/qquickitemview.cpp3
-rw-r--r--src/quick/items/qquickmousearea.cpp10
-rw-r--r--src/quick/items/qquickmousearea_p.h2
-rw-r--r--src/quick/items/qquickpainteditem.h4
-rw-r--r--src/quick/items/qquickrendercontrol.cpp4
-rw-r--r--src/quick/items/qquickrendercontrol.h6
-rw-r--r--src/quick/items/qquickscalegrid_p_p.h2
-rw-r--r--src/quick/items/qquickshadereffect.cpp8
-rw-r--r--src/quick/items/qquickshadereffect_p.h1
-rw-r--r--src/quick/items/qquickshadereffectnode.cpp1
-rw-r--r--src/quick/items/qquickshadereffectnode_p.h1
-rw-r--r--src/quick/items/qquickshadereffectsource.cpp2
-rw-r--r--src/quick/items/qquicksprite.cpp5
-rw-r--r--src/quick/items/qquicksprite_p.h4
-rw-r--r--src/quick/items/qquicktextedit.cpp3
-rw-r--r--src/quick/items/qquicktextinput.cpp20
-rw-r--r--src/quick/items/qquickview.h4
-rw-r--r--src/quick/items/qquickwindow.cpp2
-rw-r--r--src/quick/items/qquickwindow.h6
-rw-r--r--src/quick/scenegraph/coreapi/qsgabstractrenderer.h2
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.h2
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgengine.h6
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp2
-rw-r--r--src/quick/util/qquickimageprovider.h2
-rw-r--r--src/quick/util/qquickprofiler.cpp10
-rw-r--r--src/quick/util/qquickpropertychanges.cpp3
-rw-r--r--src/quickwidgets/qquickwidget.cpp4
-rw-r--r--src/quickwidgets/qquickwidget.h4
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 b33f3d8b6a..c5c17615ee 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;
@@ -440,7 +440,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 ce4f81e1dd..23245e4a7b 100644
--- a/src/quick/items/qquickitemsmodule.cpp
+++ b/src/quick/items/qquickitemsmodule.cpp
@@ -285,6 +285,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 285a394cee..e36df53d38 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -54,6 +54,8 @@
#include <QtQuick/private/qquickwindow_p.h>
#include <QtCore/private/qobject_p.h>
+#include <private/qquickshadereffectnode_p.h>
+
QT_BEGIN_NAMESPACE
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
@@ -181,6 +183,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 cd2e2c1cb6..a8cf6155a0 100644
--- a/src/quick/items/qquickshadereffectsource.cpp
+++ b/src/quick/items/qquickshadereffectsource.cpp
@@ -269,6 +269,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 70f60b9ae3..cae32dfa49 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -1820,7 +1820,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 e04a4a1ce2..1024147bb4 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 e02fb819fe..d0a22c8c10 100644
--- a/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
+++ b/src/quick/scenegraph/coreapi/qsgabstractrenderer.h
@@ -86,7 +86,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 d294e6f3ca..9d14ae04df 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 57468e5799..68dc813933 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -137,7 +137,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 74390334c4..9b9c77dce4 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -716,7 +716,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 b5dd3026a9..3bce7827bc 100644
--- a/src/quickwidgets/qquickwidget.cpp
+++ b/src/quickwidgets/qquickwidget.cpp
@@ -986,7 +986,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;