Merge remote-tracking branch 'origin/dev' into scenegraphng
Change-Id: I35715e07b6f837f21cd8e8898f19d97af92c6b69
This commit is contained in:
commit
91e1a65cdb
|
@ -4628,6 +4628,7 @@ Module {
|
|||
Property { name: "pixelDelta"; type: "QPoint"; isReadonly: true }
|
||||
Property { name: "buttons"; type: "int"; isReadonly: true }
|
||||
Property { name: "modifiers"; type: "int"; isReadonly: true }
|
||||
Property { name: "inverted"; type: "bool" }
|
||||
Property { name: "accepted"; type: "bool" }
|
||||
}
|
||||
Component {
|
||||
|
|
|
@ -145,7 +145,7 @@ void SignalTransition::invoke()
|
|||
|
||||
void SignalTransition::connectTriggered()
|
||||
{
|
||||
if (!m_complete || !m_cdata)
|
||||
if (!m_complete || !m_compilationUnit)
|
||||
return;
|
||||
|
||||
QObject *target = senderObject();
|
||||
|
@ -165,7 +165,7 @@ void SignalTransition::connectTriggered()
|
|||
|
||||
QQmlBoundSignalExpression *expression = ctxtdata ?
|
||||
new QQmlBoundSignalExpression(target, signalIndex,
|
||||
ctxtdata, this, m_cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
|
||||
ctxtdata, this, m_compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
|
||||
if (expression)
|
||||
expression->setNotifyOnValueChanged(false);
|
||||
m_signalExpression = expression;
|
||||
|
@ -190,10 +190,10 @@ void SignalTransitionParser::verifyBindings(const QV4::CompiledData::Unit *qmlUn
|
|||
}
|
||||
}
|
||||
|
||||
void SignalTransitionParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
void SignalTransitionParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
{
|
||||
SignalTransition *st = qobject_cast<SignalTransition*>(object);
|
||||
st->m_cdata = cdata;
|
||||
st->m_compilationUnit = compilationUnit;
|
||||
st->m_bindings = bindings;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ private:
|
|||
QJSValue m_signal;
|
||||
QQmlScriptString m_guard;
|
||||
bool m_complete;
|
||||
QQmlRefPointer<QQmlCompiledData> m_cdata;
|
||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> m_compilationUnit;
|
||||
QList<const QV4::CompiledData::Binding *> m_bindings;
|
||||
QQmlBoundSignalExpressionPointer m_signalExpression;
|
||||
};
|
||||
|
@ -99,7 +99,7 @@ class SignalTransitionParser : public QQmlCustomParser
|
|||
{
|
||||
public:
|
||||
void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props) Q_DECL_OVERRIDE;
|
||||
void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
|
||||
void applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -114,7 +114,7 @@ void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger)
|
|||
|
||||
debugger->setBreakOnThrow(m_breakOnThrow);
|
||||
|
||||
foreach (const BreakPoint &breakPoint, m_breakPoints.values())
|
||||
for (const BreakPoint &breakPoint : qAsConst(m_breakPoints))
|
||||
if (breakPoint.enabled)
|
||||
debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition);
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
|
|||
connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
|
||||
connect(this, SIGNAL(profilingDisabledWhileWaiting()),
|
||||
engine->profiler, SLOT(stopProfiling()), Qt::DirectConnection);
|
||||
connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData()));
|
||||
connect(this, SIGNAL(dataRequested(bool)), engine->profiler, SLOT(reportData(bool)));
|
||||
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
|
||||
engine->profiler, SLOT(setTimer(QElapsedTimer)));
|
||||
connect(engine->profiler,
|
||||
|
@ -68,49 +68,65 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
|
|||
// use of QDataStream can skew results
|
||||
// (see tst_qqmldebugtrace::trace() benchmark)
|
||||
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
|
||||
const QQmlProfiler::LocationHash &locations,
|
||||
QList<QByteArray> &messages)
|
||||
QQmlProfiler::LocationHash &locations,
|
||||
QList<QByteArray> &messages,
|
||||
bool trackLocations)
|
||||
{
|
||||
QQmlDebugPacket ds;
|
||||
Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO,
|
||||
"You can use at most 31 message types.");
|
||||
for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0;
|
||||
++decodedMessageType) {
|
||||
if ((d.messageType & (1 << decodedMessageType)) == 0)
|
||||
continue;
|
||||
if (decodedMessageType == QQmlProfilerDefinitions::RangeData
|
||||
|| (d.messageType & (1 << decodedMessageType)) == 0) {
|
||||
continue; // RangeData is sent together with RangeLocation
|
||||
}
|
||||
|
||||
//### using QDataStream is relatively expensive
|
||||
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
|
||||
|
||||
QQmlProfiler::Location l = locations.value(d.locationId);
|
||||
|
||||
switch (decodedMessageType) {
|
||||
case QQmlProfilerDefinitions::RangeStart:
|
||||
case QQmlProfilerDefinitions::RangeEnd:
|
||||
break;
|
||||
case QQmlProfilerDefinitions::RangeData:
|
||||
ds << (l.location.sourceFile.isEmpty() ? l.url.toString() : l.location.sourceFile);
|
||||
break;
|
||||
case QQmlProfilerDefinitions::RangeLocation:
|
||||
ds << (l.url.isEmpty() ? l.location.sourceFile : l.url.toString())
|
||||
<< static_cast<qint32>(l.location.line) << static_cast<qint32>(l.location.column);
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type.");
|
||||
break;
|
||||
if (decodedMessageType == QQmlProfilerDefinitions::RangeEnd
|
||||
|| decodedMessageType == QQmlProfilerDefinitions::RangeStart) {
|
||||
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
|
||||
if (trackLocations && d.locationId != 0)
|
||||
ds << static_cast<qint64>(d.locationId);
|
||||
} else {
|
||||
auto i = locations.find(d.locationId);
|
||||
if (i != locations.end()) {
|
||||
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
|
||||
ds << (i->url.isEmpty() ? i->location.sourceFile : i->url.toString())
|
||||
<< static_cast<qint32>(i->location.line)
|
||||
<< static_cast<qint32>(i->location.column);
|
||||
if (d.messageType & (1 << QQmlProfilerDefinitions::RangeData)) {
|
||||
// Send both, location and data ...
|
||||
if (trackLocations)
|
||||
ds << static_cast<qint64>(d.locationId);
|
||||
messages.append(ds.squeezedData());
|
||||
ds.clear();
|
||||
ds << d.time << QQmlProfilerDefinitions::RangeData
|
||||
<< static_cast<quint32>(d.detailType)
|
||||
<< (i->location.sourceFile.isEmpty() ? i->url.toString() :
|
||||
i->location.sourceFile);
|
||||
}
|
||||
if (trackLocations) {
|
||||
ds << static_cast<qint64>(d.locationId);
|
||||
locations.erase(i); // ... so that we can erase here without missing anything.
|
||||
}
|
||||
} else {
|
||||
// Skip RangeData and RangeLocation: We've already sent them
|
||||
continue;
|
||||
}
|
||||
}
|
||||
messages.append(ds.squeezedData());
|
||||
ds.clear();
|
||||
}
|
||||
}
|
||||
|
||||
qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
|
||||
qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
|
||||
bool trackLocations)
|
||||
{
|
||||
while (next != data.length()) {
|
||||
const QQmlProfilerData &nextData = data.at(next);
|
||||
if (nextData.time > until || messages.length() > s_numMessagesPerBatch)
|
||||
return nextData.time;
|
||||
qQmlProfilerDataToByteArrays(nextData, locations, messages);
|
||||
qQmlProfilerDataToByteArrays(nextData, locations, messages, trackLocations);
|
||||
++next;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,8 @@ class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter {
|
|||
Q_OBJECT
|
||||
public:
|
||||
QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine);
|
||||
qint64 sendMessages(qint64 until, QList<QByteArray> &messages) Q_DECL_OVERRIDE;
|
||||
qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
|
||||
bool trackLocations) Q_DECL_OVERRIDE;
|
||||
|
||||
public slots:
|
||||
void receiveData(const QVector<QQmlProfilerData> &new_data,
|
||||
|
|
|
@ -57,7 +57,7 @@ Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter)
|
|||
|
||||
QQmlProfilerServiceImpl::QQmlProfilerServiceImpl(QObject *parent) :
|
||||
QQmlConfigurableDebugService<QQmlProfilerService>(1, parent),
|
||||
m_waitingForStop(false)
|
||||
m_waitingForStop(false), m_useMessageTypes(false)
|
||||
{
|
||||
m_timer.start();
|
||||
QQmlAbstractProfilerAdapter *quickAdapter =
|
||||
|
@ -309,7 +309,7 @@ void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine)
|
|||
m_waitingForStop = true;
|
||||
|
||||
foreach (QQmlAbstractProfilerAdapter *profiler, reporting)
|
||||
profiler->reportData();
|
||||
profiler->reportData(m_useMessageTypes);
|
||||
|
||||
foreach (QQmlAbstractProfilerAdapter *profiler, stopping)
|
||||
profiler->stopProfiling();
|
||||
|
@ -343,7 +343,8 @@ void QQmlProfilerServiceImpl::sendMessages()
|
|||
m_startTimes.erase(m_startTimes.begin());
|
||||
qint64 next = first->sendMessages(m_startTimes.isEmpty() ?
|
||||
std::numeric_limits<qint64>::max() :
|
||||
m_startTimes.begin().key(), messages);
|
||||
m_startTimes.begin().key(), messages,
|
||||
m_useMessageTypes);
|
||||
if (next != -1)
|
||||
m_startTimes.insert(next, first);
|
||||
|
||||
|
@ -418,6 +419,8 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message)
|
|||
disconnect(this, SIGNAL(stopFlushTimer()), &m_flushTimer, SLOT(stop()));
|
||||
}
|
||||
}
|
||||
if (!stream.atEnd())
|
||||
stream >> m_useMessageTypes;
|
||||
|
||||
// If engineId == -1 objectForId() and then the cast will return 0.
|
||||
if (enabled)
|
||||
|
@ -435,14 +438,14 @@ void QQmlProfilerServiceImpl::flush()
|
|||
foreach (QQmlAbstractProfilerAdapter *profiler, m_engineProfilers) {
|
||||
if (profiler->isRunning()) {
|
||||
m_startTimes.insert(-1, profiler);
|
||||
profiler->reportData();
|
||||
profiler->reportData(m_useMessageTypes);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (QQmlAbstractProfilerAdapter *profiler, m_globalProfilers) {
|
||||
if (profiler->isRunning()) {
|
||||
m_startTimes.insert(-1, profiler);
|
||||
profiler->reportData();
|
||||
profiler->reportData(m_useMessageTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,6 +116,7 @@ private:
|
|||
QElapsedTimer m_timer;
|
||||
QTimer m_flushTimer;
|
||||
bool m_waitingForStop;
|
||||
bool m_useMessageTypes;
|
||||
|
||||
QList<QQmlAbstractProfilerAdapter *> m_globalProfilers;
|
||||
QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *> m_engineProfilers;
|
||||
|
|
|
@ -58,7 +58,7 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut
|
|||
connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling()));
|
||||
connect(this, SIGNAL(profilingDisabledWhileWaiting()), engine->profiler, SLOT(stopProfiling()),
|
||||
Qt::DirectConnection);
|
||||
connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData()));
|
||||
connect(this, SIGNAL(dataRequested(bool)), engine->profiler, SLOT(reportData(bool)));
|
||||
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
|
||||
engine->profiler, SLOT(setTimer(QElapsedTimer)));
|
||||
connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash,
|
||||
|
@ -105,13 +105,13 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes
|
|||
return callNext == -1 ? memoryNext : qMin(callNext, memoryNext);
|
||||
}
|
||||
|
||||
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
|
||||
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
|
||||
bool trackLocations)
|
||||
{
|
||||
QQmlDebugPacket d;
|
||||
|
||||
// Make it const, so that we cannot accidentally detach it.
|
||||
const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData;
|
||||
const QV4::Profiling::FunctionLocationHash &functionLocations = m_functionLocations;
|
||||
|
||||
while (true) {
|
||||
while (!m_stack.isEmpty() &&
|
||||
|
@ -133,17 +133,27 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message
|
|||
return finalizeMessages(until, messages, props.start, d);
|
||||
|
||||
appendMemoryEvents(props.start, messages, d);
|
||||
auto location = functionLocations.constFind(props.id);
|
||||
Q_ASSERT(location != functionLocations.constEnd());
|
||||
auto location = m_functionLocations.find(props.id);
|
||||
|
||||
d << props.start << RangeStart << Javascript;
|
||||
messages.push_back(d.squeezedData());
|
||||
d.clear();
|
||||
d << props.start << RangeLocation << Javascript << location->file << location->line
|
||||
<< location->column;
|
||||
messages.push_back(d.squeezedData());
|
||||
d.clear();
|
||||
d << props.start << RangeData << Javascript << location->name;
|
||||
if (trackLocations)
|
||||
d << static_cast<qint64>(props.id);
|
||||
if (location != m_functionLocations.end()) {
|
||||
messages.push_back(d.squeezedData());
|
||||
d.clear();
|
||||
d << props.start << RangeLocation << Javascript << location->file << location->line
|
||||
<< location->column;
|
||||
if (trackLocations)
|
||||
d << static_cast<qint64>(props.id);
|
||||
messages.push_back(d.squeezedData());
|
||||
d.clear();
|
||||
d << props.start << RangeData << Javascript << location->name;
|
||||
|
||||
if (trackLocations) {
|
||||
d << static_cast<qint64>(props.id);
|
||||
m_functionLocations.erase(location);
|
||||
}
|
||||
}
|
||||
messages.push_back(d.squeezedData());
|
||||
d.clear();
|
||||
m_stack.push(props.end);
|
||||
|
|
|
@ -67,7 +67,8 @@ class QV4ProfilerAdapter : public QQmlAbstractProfilerAdapter {
|
|||
public:
|
||||
QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine);
|
||||
|
||||
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages);
|
||||
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages,
|
||||
bool trackLocations) override;
|
||||
|
||||
signals:
|
||||
void v4ProfilingEnabled(quint64 v4Features);
|
||||
|
|
|
@ -61,8 +61,8 @@ QQuickProfilerAdapter::QQuickProfilerAdapter(QObject *parent) :
|
|||
QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
|
||||
connect(this, SIGNAL(profilingDisabledWhileWaiting()),
|
||||
QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection);
|
||||
connect(this, SIGNAL(dataRequested()),
|
||||
QQuickProfiler::s_instance, SLOT(reportDataImpl()), Qt::DirectConnection);
|
||||
connect(this, SIGNAL(dataRequested(bool)),
|
||||
QQuickProfiler::s_instance, SLOT(reportDataImpl(bool)), Qt::DirectConnection);
|
||||
connect(QQuickProfiler::s_instance, SIGNAL(dataReady(QVector<QQuickProfilerData>)),
|
||||
this, SLOT(receiveData(QVector<QQuickProfilerData>)), Qt::DirectConnection);
|
||||
}
|
||||
|
@ -150,8 +150,10 @@ static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data,
|
|||
}
|
||||
}
|
||||
|
||||
qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
|
||||
qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages,
|
||||
bool trackLocations)
|
||||
{
|
||||
Q_UNUSED(trackLocations);
|
||||
while (next < m_data.size()) {
|
||||
if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch)
|
||||
qQuickProfilerDataToByteArrays(m_data[next++], messages);
|
||||
|
|
|
@ -61,7 +61,7 @@ class QQuickProfilerAdapter : public QQmlAbstractProfilerAdapter {
|
|||
public:
|
||||
QQuickProfilerAdapter(QObject *parent = 0);
|
||||
~QQuickProfilerAdapter();
|
||||
qint64 sendMessages(qint64 until, QList<QByteArray> &messages);
|
||||
qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) override;
|
||||
|
||||
public slots:
|
||||
void receiveData(const QVector<QQuickProfilerData> &new_data);
|
||||
|
|
|
@ -1089,7 +1089,7 @@ void QSGD3D12RenderLoop::polishAndSync(WindowData *w, bool inExpose)
|
|||
}
|
||||
|
||||
// Flush pending touch events.
|
||||
QQuickWindowPrivate::get(window)->flushDelayedTouchEvent();
|
||||
QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
|
||||
// The delivery of the event might have caused the window to stop rendering
|
||||
w = windowFor(windows, window);
|
||||
if (!w || !w->thread || !w->thread->exposedWindow) {
|
||||
|
|
|
@ -72,23 +72,24 @@ using namespace QmlIR;
|
|||
return false; \
|
||||
}
|
||||
|
||||
void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &loc)
|
||||
void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &loc)
|
||||
{
|
||||
inheritedTypeNameIndex = typeNameIndex;
|
||||
|
||||
location.line = loc.startLine;
|
||||
location.column = loc.startColumn;
|
||||
|
||||
idIndex = id;
|
||||
idNameIndex = idIndex;
|
||||
id = -1;
|
||||
indexOfDefaultPropertyOrAlias = -1;
|
||||
defaultPropertyIsAlias = false;
|
||||
flags = QV4::CompiledData::Object::NoFlag;
|
||||
properties = pool->New<PoolList<Property> >();
|
||||
aliases = pool->New<PoolList<Alias> >();
|
||||
qmlSignals = pool->New<PoolList<Signal> >();
|
||||
bindings = pool->New<PoolList<Binding> >();
|
||||
functions = pool->New<PoolList<Function> >();
|
||||
functionsAndExpressions = pool->New<PoolList<CompiledFunctionOrExpression> >();
|
||||
runtimeFunctionIndices = 0;
|
||||
declarationsOverride = 0;
|
||||
}
|
||||
|
||||
|
@ -1237,10 +1238,10 @@ bool IRBuilder::setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST
|
|||
if (illegalNames.contains(idQString))
|
||||
COMPILE_EXCEPTION(loc, tr( "ID illegally masks global JavaScript property"));
|
||||
|
||||
if (_object->idIndex != emptyStringIndex)
|
||||
if (_object->idNameIndex != emptyStringIndex)
|
||||
COMPILE_EXCEPTION(idLocation, tr("Property value set multiple times"));
|
||||
|
||||
_object->idIndex = registerString(idQString);
|
||||
_object->idNameIndex = registerString(idQString);
|
||||
_object->locationOfIdProperty.line = idLocation.startLine;
|
||||
_object->locationOfIdProperty.column = idLocation.startColumn;
|
||||
|
||||
|
@ -1368,12 +1369,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
|
|||
const int importSize = sizeof(QV4::CompiledData::Import) * output.imports.count();
|
||||
const int objectOffsetTableSize = output.objects.count() * sizeof(quint32);
|
||||
|
||||
QHash<Object*, quint32> objectOffsets;
|
||||
QHash<const Object*, quint32> objectOffsets;
|
||||
|
||||
int objectsSize = 0;
|
||||
foreach (Object *o, output.objects) {
|
||||
objectOffsets.insert(o, unitSize + importSize + objectOffsetTableSize + objectsSize);
|
||||
objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount());
|
||||
objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
|
||||
|
||||
int signalTableSize = 0;
|
||||
for (const Signal *s = o->firstSignal(); s; s = s->next)
|
||||
|
@ -1413,14 +1414,17 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
|
|||
// write objects
|
||||
quint32 *objectTable = reinterpret_cast<quint32*>(data + qmlUnit->offsetToObjects);
|
||||
char *objectPtr = data + qmlUnit->offsetToObjects + objectOffsetTableSize;
|
||||
foreach (Object *o, output.objects) {
|
||||
for (int i = 0; i < output.objects.count(); ++i) {
|
||||
const Object *o = output.objects.at(i);
|
||||
*objectTable++ = objectOffsets.value(o);
|
||||
|
||||
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
|
||||
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
|
||||
objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
|
||||
objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias;
|
||||
objectToWrite->idIndex = o->idIndex;
|
||||
objectToWrite->flags = o->flags;
|
||||
objectToWrite->idNameIndex = o->idNameIndex;
|
||||
objectToWrite->id = o->id;
|
||||
objectToWrite->location = o->location;
|
||||
objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
|
||||
|
||||
|
@ -1446,9 +1450,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
|
|||
objectToWrite->offsetToBindings = nextOffset;
|
||||
nextOffset += objectToWrite->nBindings * sizeof(QV4::CompiledData::Binding);
|
||||
|
||||
objectToWrite->nNamedObjectsInComponent = o->namedObjectsInComponent.count;
|
||||
objectToWrite->offsetToNamedObjectsInComponent = nextOffset;
|
||||
nextOffset += objectToWrite->nNamedObjectsInComponent * sizeof(quint32);
|
||||
|
||||
quint32 *functionsTable = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToFunctions);
|
||||
for (const Function *f = o->firstFunction(); f; f = f->next)
|
||||
*functionsTable++ = o->runtimeFunctionIndices->at(f->index);
|
||||
*functionsTable++ = o->runtimeFunctionIndices.at(f->index);
|
||||
|
||||
char *propertiesPtr = objectPtr + objectToWrite->offsetToProperties;
|
||||
for (const Property *p = o->firstProperty(); p; p = p->next) {
|
||||
|
@ -1492,7 +1500,12 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
|
|||
signalPtr += size;
|
||||
}
|
||||
|
||||
objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount());
|
||||
quint32 *namedObjectInComponentPtr = reinterpret_cast<quint32*>(objectPtr + objectToWrite->offsetToNamedObjectsInComponent);
|
||||
for (int i = 0; i < o->namedObjectsInComponent.count; ++i) {
|
||||
*namedObjectInComponentPtr++ = o->namedObjectsInComponent.at(i);
|
||||
}
|
||||
|
||||
objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount(), o->namedObjectsInComponent.count);
|
||||
objectPtr += signalTableSize;
|
||||
}
|
||||
|
||||
|
@ -1509,7 +1522,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
|
|||
return qmlUnit;
|
||||
}
|
||||
|
||||
char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const
|
||||
char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const
|
||||
{
|
||||
for (const Binding *b = o->firstBinding(); b; b = b->next) {
|
||||
if (!(b->*(filter))())
|
||||
|
@ -1517,7 +1530,7 @@ char *QmlUnitGenerator::writeBindings(char *bindingPtr, Object *o, BindingFilter
|
|||
QV4::CompiledData::Binding *bindingToWrite = reinterpret_cast<QV4::CompiledData::Binding*>(bindingPtr);
|
||||
*bindingToWrite = *b;
|
||||
if (b->type == QV4::CompiledData::Binding::Type_Script)
|
||||
bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices->at(b->value.compiledScriptIndex);
|
||||
bindingToWrite->value.compiledScriptIndex = o->runtimeFunctionIndices.at(b->value.compiledScriptIndex);
|
||||
bindingPtr += sizeof(QV4::CompiledData::Binding);
|
||||
}
|
||||
return bindingPtr;
|
||||
|
|
|
@ -170,7 +170,12 @@ class FixedPoolArray
|
|||
public:
|
||||
int count;
|
||||
|
||||
void init(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
|
||||
FixedPoolArray()
|
||||
: data(0)
|
||||
, count(0)
|
||||
{}
|
||||
|
||||
void allocate(QQmlJS::MemoryPool *pool, const QVector<T> &vector)
|
||||
{
|
||||
count = vector.count();
|
||||
data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
|
||||
|
@ -183,6 +188,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
void allocate(QQmlJS::MemoryPool *pool, const Container &container)
|
||||
{
|
||||
count = container.count();
|
||||
data = reinterpret_cast<T*>(pool->allocate(count * sizeof(T)));
|
||||
typename Container::ConstIterator it = container.constBegin();
|
||||
for (int i = 0; i < count; ++i)
|
||||
new (data + i) T(*it++);
|
||||
}
|
||||
|
||||
const T &at(int index) const {
|
||||
Q_ASSERT(index >= 0 && index < count);
|
||||
return data[index];
|
||||
|
@ -274,9 +289,11 @@ struct Q_QML_PRIVATE_EXPORT Object
|
|||
Q_DECLARE_TR_FUNCTIONS(Object)
|
||||
public:
|
||||
quint32 inheritedTypeNameIndex;
|
||||
quint32 idIndex;
|
||||
int indexOfDefaultPropertyOrAlias : 31;
|
||||
int defaultPropertyIsAlias : 1;
|
||||
quint32 idNameIndex;
|
||||
int id;
|
||||
int indexOfDefaultPropertyOrAlias;
|
||||
bool defaultPropertyIsAlias;
|
||||
int flags;
|
||||
|
||||
QV4::CompiledData::Location location;
|
||||
QV4::CompiledData::Location locationOfIdProperty;
|
||||
|
@ -296,7 +313,7 @@ public:
|
|||
// specified object. Used for declarations inside group properties.
|
||||
Object *declarationsOverride;
|
||||
|
||||
void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
|
||||
void init(QQmlJS::MemoryPool *pool, int typeNameIndex, int idIndex, const QQmlJS::AST::SourceLocation &location = QQmlJS::AST::SourceLocation());
|
||||
|
||||
QString sanityCheckFunctionNames(const QSet<QString> &illegalNames, QQmlJS::AST::SourceLocation *errorLocation);
|
||||
|
||||
|
@ -312,7 +329,9 @@ public:
|
|||
QString bindingAsString(Document *doc, int scriptIndex) const;
|
||||
|
||||
PoolList<CompiledFunctionOrExpression> *functionsAndExpressions;
|
||||
FixedPoolArray<int> *runtimeFunctionIndices;
|
||||
FixedPoolArray<int> runtimeFunctionIndices;
|
||||
|
||||
FixedPoolArray<quint32> namedObjectsInComponent;
|
||||
|
||||
private:
|
||||
friend struct IRLoader;
|
||||
|
@ -467,7 +486,7 @@ struct Q_QML_PRIVATE_EXPORT QmlUnitGenerator
|
|||
|
||||
private:
|
||||
typedef bool (Binding::*BindingFilter)() const;
|
||||
char *writeBindings(char *bindingPtr, Object *o, BindingFilter filter) const;
|
||||
char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const;
|
||||
};
|
||||
|
||||
#ifndef V4_BOOTSTRAP
|
||||
|
|
|
@ -65,16 +65,16 @@ QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlCompiledData *
|
|||
|
||||
bool QQmlTypeCompiler::compile()
|
||||
{
|
||||
compiledData->importCache = new QQmlTypeNameCache;
|
||||
importCache = new QQmlTypeNameCache;
|
||||
|
||||
foreach (const QString &ns, typeData->namespaces())
|
||||
compiledData->importCache->add(ns);
|
||||
importCache->add(ns);
|
||||
|
||||
// Add any Composite Singletons that were used to the import cache
|
||||
foreach (const QQmlTypeData::TypeReference &singleton, typeData->compositeSingletons())
|
||||
compiledData->importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
|
||||
importCache->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
|
||||
|
||||
typeData->imports().populateCache(compiledData->importCache);
|
||||
typeData->imports().populateCache(importCache.data());
|
||||
|
||||
const QHash<int, QQmlTypeData::TypeReference> &resolvedTypes = typeData->resolvedTypeRefs();
|
||||
for (QHash<int, QQmlTypeData::TypeReference>::ConstIterator resolvedType = resolvedTypes.constBegin(), end = resolvedTypes.constEnd();
|
||||
|
@ -137,8 +137,6 @@ bool QQmlTypeCompiler::compile()
|
|||
customParsers.insert(it.key(), customParser);
|
||||
}
|
||||
|
||||
compiledData->propertyCaches.reserve(document->objects.count());
|
||||
|
||||
{
|
||||
QQmlPropertyCacheCreator propertyCacheBuilder(this);
|
||||
if (!propertyCacheBuilder.buildMetaObjects())
|
||||
|
@ -174,7 +172,8 @@ bool QQmlTypeCompiler::compile()
|
|||
|
||||
// Collect imported scripts
|
||||
const QList<QQmlTypeData::ScriptReference> &scripts = typeData->resolvedScripts();
|
||||
compiledData->scripts.reserve(scripts.count());
|
||||
QVector<QQmlScriptData *> dependentScripts;
|
||||
dependentScripts.reserve(scripts.count());
|
||||
for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) {
|
||||
const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex);
|
||||
|
||||
|
@ -187,10 +186,10 @@ bool QQmlTypeCompiler::compile()
|
|||
qualifier = qualifier.mid(lastDotIndex+1);
|
||||
}
|
||||
|
||||
compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
|
||||
importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
|
||||
QQmlScriptData *scriptData = script.script->scriptData();
|
||||
scriptData->addref();
|
||||
compiledData->scripts << scriptData;
|
||||
dependentScripts << scriptData;
|
||||
}
|
||||
|
||||
// Resolve component boundaries and aliases
|
||||
|
@ -202,6 +201,12 @@ bool QQmlTypeCompiler::compile()
|
|||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
QQmlDeferredAndCustomParserBindingScanner deferredAndCustomParserBindingScanner(this);
|
||||
if (!deferredAndCustomParserBindingScanner.scanObject())
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compile JS binding expressions and signal handlers
|
||||
if (!document->javaScriptCompilationUnit) {
|
||||
{
|
||||
|
@ -211,7 +216,7 @@ bool QQmlTypeCompiler::compile()
|
|||
sss.scan();
|
||||
}
|
||||
|
||||
QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, compiledData->importCache, &document->jsGenerator.stringTable);
|
||||
QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable);
|
||||
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
|
||||
if (!jsCodeGen.generateCodeForComponents())
|
||||
return false;
|
||||
|
@ -236,9 +241,12 @@ bool QQmlTypeCompiler::compile()
|
|||
document->javaScriptCompilationUnit->data = qmlUnit;
|
||||
|
||||
compiledData->compilationUnit = document->javaScriptCompilationUnit;
|
||||
compiledData->compilationUnit->propertyCaches = m_propertyCaches;
|
||||
compiledData->compilationUnit->importCache = importCache;
|
||||
compiledData->compilationUnit->dependentScripts = dependentScripts;
|
||||
|
||||
// Add to type registry of composites
|
||||
if (compiledData->isCompositeType())
|
||||
if (compiledData->compilationUnit->isCompositeType())
|
||||
engine->registerInternalCompositeType(compiledData);
|
||||
else {
|
||||
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(qmlUnit->indexOfRootObject);
|
||||
|
@ -272,18 +280,18 @@ bool QQmlTypeCompiler::compile()
|
|||
}
|
||||
++objectCount;
|
||||
if (typeRef->component) {
|
||||
bindingCount += typeRef->component->totalBindingsCount;
|
||||
parserStatusCount += typeRef->component->totalParserStatusCount;
|
||||
objectCount += typeRef->component->totalObjectCount;
|
||||
bindingCount += typeRef->component->compilationUnit->totalBindingsCount;
|
||||
parserStatusCount += typeRef->component->compilationUnit->totalParserStatusCount;
|
||||
objectCount += typeRef->component->compilationUnit->totalObjectCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compiledData->totalBindingsCount = bindingCount;
|
||||
compiledData->totalParserStatusCount = parserStatusCount;
|
||||
compiledData->totalObjectCount = objectCount;
|
||||
compiledData->compilationUnit->totalBindingsCount = bindingCount;
|
||||
compiledData->compilationUnit->totalParserStatusCount = parserStatusCount;
|
||||
compiledData->compilationUnit->totalObjectCount = objectCount;
|
||||
|
||||
Q_ASSERT(compiledData->propertyCaches.count() == static_cast<int>(compiledData->compilationUnit->data->nObjects));
|
||||
Q_ASSERT(compiledData->compilationUnit->propertyCaches.count() == static_cast<int>(compiledData->compilationUnit->data->nObjects));
|
||||
|
||||
return errors.isEmpty();
|
||||
}
|
||||
|
@ -337,28 +345,13 @@ int QQmlTypeCompiler::rootObjectIndex() const
|
|||
|
||||
void QQmlTypeCompiler::setPropertyCaches(const QQmlPropertyCacheVector &caches)
|
||||
{
|
||||
compiledData->propertyCaches = caches;
|
||||
m_propertyCaches = caches;
|
||||
Q_ASSERT(caches.count() >= document->indexOfRootObject);
|
||||
}
|
||||
|
||||
const QQmlPropertyCacheVector &QQmlTypeCompiler::propertyCaches() const
|
||||
{
|
||||
return compiledData->propertyCaches;
|
||||
}
|
||||
|
||||
QHash<int, int> *QQmlTypeCompiler::objectIndexToIdForRoot()
|
||||
{
|
||||
return &compiledData->objectIndexToIdForRoot;
|
||||
}
|
||||
|
||||
QHash<int, QHash<int, int> > *QQmlTypeCompiler::objectIndexToIdPerComponent()
|
||||
{
|
||||
return &compiledData->objectIndexToIdPerComponent;
|
||||
}
|
||||
|
||||
QHash<int, QBitArray> *QQmlTypeCompiler::customParserBindings()
|
||||
{
|
||||
return &compiledData->customParserBindings;
|
||||
return m_propertyCaches;
|
||||
}
|
||||
|
||||
QQmlJS::MemoryPool *QQmlTypeCompiler::memoryPool()
|
||||
|
@ -376,11 +369,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const
|
|||
return &document->jsGenerator.stringTable;
|
||||
}
|
||||
|
||||
void QQmlTypeCompiler::setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject)
|
||||
{
|
||||
compiledData->deferredBindingsPerObject = deferredBindingsPerObject;
|
||||
}
|
||||
|
||||
void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData)
|
||||
{
|
||||
compiledData->compilationUnit->bindingPropertyDataPerObject = propertyData;
|
||||
|
@ -1324,11 +1312,8 @@ QQmlComponentAndAliasResolver::QQmlComponentAndAliasResolver(QQmlTypeCompiler *t
|
|||
, qmlObjects(typeCompiler->qmlObjects())
|
||||
, indexOfRootObject(typeCompiler->rootObjectIndex())
|
||||
, _componentIndex(-1)
|
||||
, _objectIndexToIdInScope(0)
|
||||
, resolvedTypes(typeCompiler->resolvedTypes())
|
||||
, propertyCaches(typeCompiler->propertyCaches())
|
||||
, objectIndexToIdForRoot(typeCompiler->objectIndexToIdForRoot())
|
||||
, objectIndexToIdPerComponent(typeCompiler->objectIndexToIdPerComponent())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1351,7 +1336,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
|
|||
if (targetType->metaObject() == &QQmlComponent::staticMetaObject)
|
||||
continue;
|
||||
} else if (tr->component) {
|
||||
if (tr->component->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
|
||||
if (tr->component->compilationUnit->rootPropertyCache()->firstCppMetaObject() == &QQmlComponent::staticMetaObject)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1382,6 +1367,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
|
|||
QmlIR::Object *syntheticComponent = pool->New<QmlIR::Object>();
|
||||
syntheticComponent->init(pool, compiler->registerString(QString::fromUtf8(componentType->typeName())), compiler->registerString(QString()));
|
||||
syntheticComponent->location = binding->valueLocation;
|
||||
syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent;
|
||||
|
||||
if (!resolvedTypes->contains(syntheticComponent->inheritedTypeNameIndex)) {
|
||||
QQmlCompiledData::TypeReference *typeRef = new QQmlCompiledData::TypeReference;
|
||||
|
@ -1408,7 +1394,6 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
|
|||
binding->value.objectIndex = componentIndex;
|
||||
|
||||
componentRoots.append(componentIndex);
|
||||
componentBoundaries.append(syntheticBinding->value.objectIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1420,7 +1405,7 @@ bool QQmlComponentAndAliasResolver::resolve()
|
|||
// on the left hand side is of QQmlComponent type.
|
||||
const int objCountWithoutSynthesizedComponents = qmlObjects->count();
|
||||
for (int i = 0; i < objCountWithoutSynthesizedComponents; ++i) {
|
||||
const QmlIR::Object *obj = qmlObjects->at(i);
|
||||
QmlIR::Object *obj = qmlObjects->at(i);
|
||||
QQmlPropertyCache *cache = propertyCaches.at(i).data();
|
||||
if (obj->inheritedTypeNameIndex == 0 && !cache)
|
||||
continue;
|
||||
|
@ -1439,7 +1424,7 @@ bool QQmlComponentAndAliasResolver::resolve()
|
|||
continue;
|
||||
}
|
||||
|
||||
componentRoots.append(i);
|
||||
obj->flags |= QV4::CompiledData::Object::IsComponent;
|
||||
|
||||
if (obj->functionCount() > 0)
|
||||
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
|
||||
|
@ -1461,20 +1446,20 @@ bool QQmlComponentAndAliasResolver::resolve()
|
|||
if (rootBinding->next || rootBinding->type != QV4::CompiledData::Binding::Type_Object)
|
||||
COMPILE_EXCEPTION(obj, tr("Invalid component body specification"));
|
||||
|
||||
componentBoundaries.append(rootBinding->value.objectIndex);
|
||||
// We are going to collect ids/aliases and resolve them for the root object as a separate
|
||||
// last pass.
|
||||
if (i != indexOfRootObject)
|
||||
componentRoots.append(i);
|
||||
|
||||
}
|
||||
|
||||
std::sort(componentBoundaries.begin(), componentBoundaries.end());
|
||||
|
||||
for (int i = 0; i < componentRoots.count(); ++i) {
|
||||
const QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
|
||||
QmlIR::Object *component = qmlObjects->at(componentRoots.at(i));
|
||||
const QmlIR::Binding *rootBinding = component->firstBinding();
|
||||
|
||||
_componentIndex = i;
|
||||
_idToObjectIndex.clear();
|
||||
|
||||
_objectIndexToIdInScope = &(*objectIndexToIdPerComponent)[componentRoots.at(i)];
|
||||
|
||||
_objectsWithAliases.clear();
|
||||
|
||||
if (!collectIdsAndAliases(rootBinding->value.objectIndex))
|
||||
|
@ -1482,51 +1467,56 @@ bool QQmlComponentAndAliasResolver::resolve()
|
|||
|
||||
if (!resolveAliases())
|
||||
return false;
|
||||
|
||||
component->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
|
||||
}
|
||||
|
||||
// Collect ids and aliases for root
|
||||
_componentIndex = -1;
|
||||
_idToObjectIndex.clear();
|
||||
_objectIndexToIdInScope = objectIndexToIdForRoot;
|
||||
_objectsWithAliases.clear();
|
||||
|
||||
collectIdsAndAliases(indexOfRootObject);
|
||||
|
||||
resolveAliases();
|
||||
|
||||
QmlIR::Object *rootComponent = qmlObjects->at(indexOfRootObject);
|
||||
rootComponent->namedObjectsInComponent.allocate(pool, _idToObjectIndex);
|
||||
|
||||
// Implicit component insertion may have added objects and thus we also need
|
||||
// to extend the symmetric propertyCaches.
|
||||
compiler->setPropertyCaches(propertyCaches);
|
||||
compiler->setComponentRoots(componentRoots);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
|
||||
{
|
||||
const QmlIR::Object *obj = qmlObjects->at(objectIndex);
|
||||
QmlIR::Object *obj = qmlObjects->at(objectIndex);
|
||||
|
||||
if (obj->idIndex != 0) {
|
||||
if (_idToObjectIndex.contains(obj->idIndex)) {
|
||||
if (obj->idNameIndex != 0) {
|
||||
if (_idToObjectIndex.contains(obj->idNameIndex)) {
|
||||
recordError(obj->locationOfIdProperty, tr("id is not unique"));
|
||||
return false;
|
||||
}
|
||||
_idToObjectIndex.insert(obj->idIndex, objectIndex);
|
||||
_objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
|
||||
obj->id = _idToObjectIndex.count();
|
||||
_idToObjectIndex.insert(obj->idNameIndex, objectIndex);
|
||||
}
|
||||
|
||||
if (obj->aliasCount() > 0)
|
||||
_objectsWithAliases.append(objectIndex);
|
||||
|
||||
// Stop at Component boundary
|
||||
if (obj->flags & QV4::CompiledData::Object::IsComponent && objectIndex != compiler->rootObjectIndex())
|
||||
return true;
|
||||
|
||||
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
|
||||
if (binding->type != QV4::CompiledData::Binding::Type_Object
|
||||
&& binding->type != QV4::CompiledData::Binding::Type_AttachedProperty
|
||||
&& binding->type != QV4::CompiledData::Binding::Type_GroupProperty)
|
||||
continue;
|
||||
|
||||
// Stop at Component boundary
|
||||
if (std::binary_search(componentBoundaries.constBegin(), componentBoundaries.constEnd(), binding->value.objectIndex))
|
||||
continue;
|
||||
|
||||
if (!collectIdsAndAliases(binding->value.objectIndex))
|
||||
return false;
|
||||
}
|
||||
|
@ -1555,8 +1545,9 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
|
|||
}
|
||||
Q_ASSERT(!(alias->flags & QV4::CompiledData::Alias::Resolved));
|
||||
alias->flags |= QV4::CompiledData::Alias::Resolved;
|
||||
Q_ASSERT(_objectIndexToIdInScope->contains(targetObjectIndex));
|
||||
alias->targetObjectId = _objectIndexToIdInScope->value(targetObjectIndex);
|
||||
const QmlIR::Object *targetObject = qmlObjects->at(targetObjectIndex);
|
||||
Q_ASSERT(targetObject->id >= 0);
|
||||
alias->targetObjectId = targetObject->id;
|
||||
|
||||
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
|
||||
|
||||
|
@ -1668,6 +1659,126 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
|
|||
return true;
|
||||
}
|
||||
|
||||
QQmlDeferredAndCustomParserBindingScanner::QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler)
|
||||
: QQmlCompilePass(typeCompiler)
|
||||
, qmlObjects(typeCompiler->qmlObjects())
|
||||
, propertyCaches(typeCompiler->propertyCaches())
|
||||
, customParsers(typeCompiler->customParserCache())
|
||||
, _seenObjectWithId(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool QQmlDeferredAndCustomParserBindingScanner::scanObject()
|
||||
{
|
||||
return scanObject(compiler->rootObjectIndex());
|
||||
}
|
||||
|
||||
bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex)
|
||||
{
|
||||
QmlIR::Object *obj = qmlObjects->at(objectIndex);
|
||||
if (obj->idNameIndex != 0)
|
||||
_seenObjectWithId = true;
|
||||
|
||||
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
|
||||
Q_ASSERT(obj->bindingCount() == 1);
|
||||
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
|
||||
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
|
||||
return scanObject(componentBinding->value.objectIndex);
|
||||
}
|
||||
|
||||
QQmlPropertyCache *propertyCache = propertyCaches.at(objectIndex).data();
|
||||
if (!propertyCache)
|
||||
return true;
|
||||
|
||||
QString defaultPropertyName;
|
||||
QQmlPropertyData *defaultProperty = 0;
|
||||
if (obj->indexOfDefaultPropertyOrAlias != -1) {
|
||||
QQmlPropertyCache *cache = propertyCache->parent();
|
||||
defaultPropertyName = cache->defaultPropertyName();
|
||||
defaultProperty = cache->defaultProperty();
|
||||
} else {
|
||||
defaultPropertyName = propertyCache->defaultPropertyName();
|
||||
defaultProperty = propertyCache->defaultProperty();
|
||||
}
|
||||
|
||||
QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex);
|
||||
|
||||
QmlIR::PropertyResolver propertyResolver(propertyCache);
|
||||
|
||||
QStringList deferredPropertyNames;
|
||||
{
|
||||
const QMetaObject *mo = propertyCache->firstCppMetaObject();
|
||||
const int namesIndex = mo->indexOfClassInfo("DeferredPropertyNames");
|
||||
if (namesIndex != -1) {
|
||||
QMetaClassInfo classInfo = mo->classInfo(namesIndex);
|
||||
deferredPropertyNames = QString::fromUtf8(classInfo.value()).split(QLatin1Char(','));
|
||||
}
|
||||
}
|
||||
|
||||
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
|
||||
QQmlPropertyData *pd = 0;
|
||||
QString name = stringAt(binding->propertyNameIndex);
|
||||
|
||||
if (customParser) {
|
||||
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
|
||||
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
|
||||
binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
|
||||
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
|
||||
continue;
|
||||
}
|
||||
} else if (QmlIR::IRBuilder::isSignalPropertyName(name)
|
||||
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
|
||||
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
|
||||
binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (name.isEmpty()) {
|
||||
pd = defaultProperty;
|
||||
name = defaultPropertyName;
|
||||
} else {
|
||||
if (name.constData()->isUpper())
|
||||
continue;
|
||||
|
||||
bool notInRevision = false;
|
||||
pd = propertyResolver.property(name, ¬InRevision, QmlIR::PropertyResolver::CheckRevision);
|
||||
}
|
||||
|
||||
bool seenSubObjectWithId = false;
|
||||
|
||||
if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
|
||||
qSwap(_seenObjectWithId, seenSubObjectWithId);
|
||||
const bool subObjectValid = scanObject(binding->value.objectIndex);
|
||||
qSwap(_seenObjectWithId, seenSubObjectWithId);
|
||||
if (!subObjectValid)
|
||||
return false;
|
||||
_seenObjectWithId |= seenSubObjectWithId;
|
||||
}
|
||||
|
||||
if (!seenSubObjectWithId
|
||||
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
|
||||
|
||||
binding->flags |= QV4::CompiledData::Binding::IsDeferredBinding;
|
||||
obj->flags |= QV4::CompiledData::Object::HasDeferredBindings;
|
||||
}
|
||||
|
||||
if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression
|
||||
|| binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject)
|
||||
continue;
|
||||
|
||||
if (!pd) {
|
||||
if (customParser) {
|
||||
obj->flags |= QV4::CompiledData::Object::HasCustomParserBindings;
|
||||
binding->flags |= QV4::CompiledData::Binding::IsCustomParserBinding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
|
||||
: QQmlCompilePass(typeCompiler)
|
||||
, enginePrivate(typeCompiler->enginePrivate())
|
||||
|
@ -1675,9 +1786,6 @@ QQmlPropertyValidator::QQmlPropertyValidator(QQmlTypeCompiler *typeCompiler)
|
|||
, resolvedTypes(*typeCompiler->resolvedTypes())
|
||||
, customParsers(typeCompiler->customParserCache())
|
||||
, propertyCaches(typeCompiler->propertyCaches())
|
||||
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
|
||||
, customParserBindingsPerObject(typeCompiler->customParserBindings())
|
||||
, _seenObjectWithId(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1686,7 +1794,6 @@ bool QQmlPropertyValidator::validate()
|
|||
_bindingPropertyDataPerObject.resize(qmlUnit->nObjects);
|
||||
if (!validateObject(qmlUnit->indexOfRootObject, /*instantiatingBinding*/0))
|
||||
return false;
|
||||
compiler->setDeferredBindingsPerObject(_deferredBindingsPerObject);
|
||||
compiler->setBindingPropertyDataPerObject(_bindingPropertyDataPerObject);
|
||||
return true;
|
||||
}
|
||||
|
@ -1717,10 +1824,8 @@ struct BindingFinder
|
|||
bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledData::Binding *instantiatingBinding, bool populatingValueTypeGroupProperty) const
|
||||
{
|
||||
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(objectIndex);
|
||||
if (obj->idIndex != 0)
|
||||
_seenObjectWithId = true;
|
||||
|
||||
if (isComponent(objectIndex)) {
|
||||
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
|
||||
Q_ASSERT(obj->nBindings == 1);
|
||||
const QV4::CompiledData::Binding *componentBinding = obj->bindingTable();
|
||||
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
|
||||
|
@ -1764,9 +1869,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|
|||
groupProperties.insert(pos, binding);
|
||||
}
|
||||
|
||||
QBitArray customParserBindings(obj->nBindings);
|
||||
QBitArray deferredBindings;
|
||||
|
||||
QmlIR::PropertyResolver propertyResolver(propertyCache);
|
||||
|
||||
QString defaultPropertyName;
|
||||
|
@ -1790,13 +1892,11 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|
|||
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
|
||||
if (customParser->flags() & QQmlCustomParser::AcceptsAttachedProperties) {
|
||||
customBindings << binding;
|
||||
customParserBindings.setBit(i);
|
||||
continue;
|
||||
}
|
||||
} else if (QmlIR::IRBuilder::isSignalPropertyName(name)
|
||||
&& !(customParser->flags() & QQmlCustomParser::AcceptsSignalHandlers)) {
|
||||
customBindings << binding;
|
||||
customParserBindings.setBit(i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1845,24 +1945,10 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|
|||
return false;
|
||||
}
|
||||
|
||||
bool seenSubObjectWithId = false;
|
||||
|
||||
if (binding->type >= QV4::CompiledData::Binding::Type_Object && (pd || binding->isAttachedProperty())) {
|
||||
qSwap(_seenObjectWithId, seenSubObjectWithId);
|
||||
const bool subObjectValid = validateObject(binding->value.objectIndex, binding, pd && QQmlValueTypeFactory::metaObjectForMetaType(pd->propType));
|
||||
qSwap(_seenObjectWithId, seenSubObjectWithId);
|
||||
if (!subObjectValid)
|
||||
return false;
|
||||
_seenObjectWithId |= seenSubObjectWithId;
|
||||
}
|
||||
|
||||
if (!seenSubObjectWithId
|
||||
&& !deferredPropertyNames.isEmpty() && deferredPropertyNames.contains(name)) {
|
||||
|
||||
if (deferredBindings.isEmpty())
|
||||
deferredBindings.resize(obj->nBindings);
|
||||
|
||||
deferredBindings.setBit(i);
|
||||
}
|
||||
|
||||
// Signal handlers were resolved and checked earlier in the signal handler conversion pass.
|
||||
|
@ -1947,7 +2033,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|
|||
} else {
|
||||
if (customParser) {
|
||||
customBindings << binding;
|
||||
customParserBindings.setBit(i);
|
||||
continue;
|
||||
}
|
||||
if (bindingToDefaultProperty) {
|
||||
|
@ -1958,7 +2043,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|
|||
}
|
||||
}
|
||||
|
||||
if (obj->idIndex) {
|
||||
if (obj->idNameIndex) {
|
||||
bool notInRevision = false;
|
||||
collectedBindingPropertyData << propertyResolver.property(QStringLiteral("id"), ¬InRevision);
|
||||
}
|
||||
|
@ -1972,7 +2057,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|
|||
customParser->validator = 0;
|
||||
customParser->engine = 0;
|
||||
customParser->imports = (QQmlImports*)0;
|
||||
customParserBindingsPerObject->insert(objectIndex, customParserBindings);
|
||||
const QList<QQmlError> parserErrors = customParser->errors();
|
||||
if (!parserErrors.isEmpty()) {
|
||||
foreach (const QQmlError &error, parserErrors)
|
||||
|
@ -1981,9 +2065,6 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
|
|||
}
|
||||
}
|
||||
|
||||
if (!deferredBindings.isEmpty())
|
||||
_deferredBindingsPerObject.insert(objectIndex, deferredBindings);
|
||||
|
||||
_bindingPropertyDataPerObject[objectIndex] = collectedBindingPropertyData;
|
||||
|
||||
return true;
|
||||
|
@ -2328,7 +2409,7 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
|
|||
}
|
||||
}
|
||||
return true;
|
||||
} else if (isComponent(binding->value.objectIndex)) {
|
||||
} else if (qmlUnit->objectAt(binding->value.objectIndex)->flags & QV4::CompiledData::Object::IsComponent) {
|
||||
return true;
|
||||
} else if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerObject && property->isFunction()) {
|
||||
return true;
|
||||
|
@ -2365,7 +2446,6 @@ bool QQmlPropertyValidator::validateObjectBinding(QQmlPropertyData *property, co
|
|||
|
||||
QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::JSCodeGen *v4CodeGen)
|
||||
: QQmlCompilePass(typeCompiler)
|
||||
, objectIndexToIdPerComponent(*typeCompiler->objectIndexToIdPerComponent())
|
||||
, resolvedTypes(*typeCompiler->resolvedTypes())
|
||||
, customParsers(typeCompiler->customParserCache())
|
||||
, qmlObjects(*typeCompiler->qmlObjects())
|
||||
|
@ -2376,46 +2456,40 @@ QQmlJSCodeGenerator::QQmlJSCodeGenerator(QQmlTypeCompiler *typeCompiler, QmlIR::
|
|||
|
||||
bool QQmlJSCodeGenerator::generateCodeForComponents()
|
||||
{
|
||||
const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent = *compiler->objectIndexToIdPerComponent();
|
||||
for (QHash<int, QHash<int, int> >::ConstIterator component = objectIndexToIdPerComponent.constBegin(), end = objectIndexToIdPerComponent.constEnd();
|
||||
component != end; ++component) {
|
||||
if (!compileComponent(component.key(), component.value()))
|
||||
const QVector<quint32> &componentRoots = compiler->componentRoots();
|
||||
for (int i = 0; i < componentRoots.count(); ++i) {
|
||||
if (!compileComponent(componentRoots.at(i)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return compileComponent(compiler->rootObjectIndex(), *compiler->objectIndexToIdForRoot());
|
||||
return compileComponent(compiler->rootObjectIndex());
|
||||
}
|
||||
|
||||
bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, int> &objectIndexToId)
|
||||
bool QQmlJSCodeGenerator::compileComponent(int contextObject)
|
||||
{
|
||||
if (isComponent(contextObject)) {
|
||||
const QmlIR::Object *component = qmlObjects.at(contextObject);
|
||||
Q_ASSERT(component->bindingCount() == 1);
|
||||
const QV4::CompiledData::Binding *componentBinding = component->firstBinding();
|
||||
const QmlIR::Object *obj = qmlObjects.at(contextObject);
|
||||
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
|
||||
Q_ASSERT(obj->bindingCount() == 1);
|
||||
const QV4::CompiledData::Binding *componentBinding = obj->firstBinding();
|
||||
Q_ASSERT(componentBinding->type == QV4::CompiledData::Binding::Type_Object);
|
||||
contextObject = componentBinding->value.objectIndex;
|
||||
}
|
||||
|
||||
QmlIR::JSCodeGen::ObjectIdMapping idMapping;
|
||||
if (!objectIndexToId.isEmpty()) {
|
||||
idMapping.reserve(objectIndexToId.count());
|
||||
idMapping.reserve(obj->namedObjectsInComponent.count);
|
||||
for (int i = 0; i < obj->namedObjectsInComponent.count; ++i) {
|
||||
const int objectIndex = obj->namedObjectsInComponent.at(i);
|
||||
QmlIR::JSCodeGen::IdMapping m;
|
||||
const QmlIR::Object *obj = qmlObjects.at(objectIndex);
|
||||
m.name = stringAt(obj->idNameIndex);
|
||||
m.idIndex = obj->id;
|
||||
m.type = propertyCaches.at(objectIndex).data();
|
||||
|
||||
for (QHash<int, int>::ConstIterator idIt = objectIndexToId.constBegin(), end = objectIndexToId.constEnd();
|
||||
idIt != end; ++idIt) {
|
||||
QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
|
||||
if (tref && tref->isFullyDynamicType)
|
||||
m.type = 0;
|
||||
|
||||
const int objectIndex = idIt.key();
|
||||
QmlIR::JSCodeGen::IdMapping m;
|
||||
const QmlIR::Object *obj = qmlObjects.at(objectIndex);
|
||||
m.name = stringAt(obj->idIndex);
|
||||
m.idIndex = idIt.value();
|
||||
m.type = propertyCaches.at(objectIndex).data();
|
||||
|
||||
QQmlCompiledData::TypeReference *tref = resolvedTypes.value(obj->inheritedTypeNameIndex);
|
||||
if (tref && tref->isFullyDynamicType)
|
||||
m.type = 0;
|
||||
|
||||
idMapping << m;
|
||||
}
|
||||
idMapping << m;
|
||||
}
|
||||
v4CodeGen->beginContextScope(idMapping, propertyCaches.at(contextObject).data());
|
||||
|
||||
|
@ -2427,10 +2501,10 @@ bool QQmlJSCodeGenerator::compileComponent(int contextObject, const QHash<int, i
|
|||
|
||||
bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex)
|
||||
{
|
||||
if (isComponent(objectIndex))
|
||||
QmlIR::Object *object = qmlObjects.at(objectIndex);
|
||||
if (object->flags & QV4::CompiledData::Object::IsComponent)
|
||||
return true;
|
||||
|
||||
QmlIR::Object *object = qmlObjects.at(objectIndex);
|
||||
if (object->functionsAndExpressions->count > 0) {
|
||||
QQmlPropertyCache *scopeObject = propertyCaches.at(scopeObjectIndex).data();
|
||||
v4CodeGen->beginObjectScope(scopeObject);
|
||||
|
@ -2451,8 +2525,7 @@ bool QQmlJSCodeGenerator::compileJavaScriptCodeInObjectsRecursively(int objectIn
|
|||
}
|
||||
|
||||
QQmlJS::MemoryPool *pool = compiler->memoryPool();
|
||||
object->runtimeFunctionIndices = pool->New<QmlIR::FixedPoolArray<int> >();
|
||||
object->runtimeFunctionIndices->init(pool, runtimeFunctionIndices);
|
||||
object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
|
||||
}
|
||||
|
||||
for (const QmlIR::Binding *binding = object->firstBinding(); binding; binding = binding->next) {
|
||||
|
@ -2551,7 +2624,7 @@ void QQmlJavaScriptBindingExpressionSimplificationPass::reduceTranslationBinding
|
|||
if (binding->type != QV4::CompiledData::Binding::Type_Script)
|
||||
continue;
|
||||
|
||||
const int irFunctionIndex = obj->runtimeFunctionIndices->at(binding->value.compiledScriptIndex);
|
||||
const int irFunctionIndex = obj->runtimeFunctionIndices.at(binding->value.compiledScriptIndex);
|
||||
QV4::IR::Function *irFunction = jsModule->functions.at(irFunctionIndex);
|
||||
if (simplifyBinding(irFunction, binding)) {
|
||||
irFunctionsToRemove.append(irFunctionIndex);
|
||||
|
@ -2838,10 +2911,8 @@ void QQmlIRFunctionCleanser::clean()
|
|||
}
|
||||
|
||||
foreach (QmlIR::Object *obj, *compiler->qmlObjects()) {
|
||||
if (!obj->runtimeFunctionIndices)
|
||||
continue;
|
||||
for (int i = 0; i < obj->runtimeFunctionIndices->count; ++i)
|
||||
(*obj->runtimeFunctionIndices)[i] = newFunctionIndices[obj->runtimeFunctionIndices->at(i)];
|
||||
for (int i = 0; i < obj->runtimeFunctionIndices.count; ++i)
|
||||
obj->runtimeFunctionIndices[i] = newFunctionIndices[obj->runtimeFunctionIndices.at(i)];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,13 +101,11 @@ public:
|
|||
int rootObjectIndex() const;
|
||||
void setPropertyCaches(const QQmlPropertyCacheVector &caches);
|
||||
const QQmlPropertyCacheVector &propertyCaches() const;
|
||||
QHash<int, int> *objectIndexToIdForRoot();
|
||||
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent();
|
||||
QHash<int, QBitArray> *customParserBindings();
|
||||
void setComponentRoots(const QVector<quint32> &roots) { m_componentRoots = roots; }
|
||||
const QVector<quint32> &componentRoots() const { return m_componentRoots; }
|
||||
QQmlJS::MemoryPool *memoryPool();
|
||||
QStringRef newStringRef(const QString &string);
|
||||
const QV4::Compiler::StringTableGenerator *stringPool() const;
|
||||
void setDeferredBindingsPerObject(const QHash<int, QBitArray> &deferredBindingsPerObject);
|
||||
void setBindingPropertyDataPerObject(const QVector<QV4::CompiledData::BindingPropertyData> &propertyData);
|
||||
|
||||
const QHash<int, QQmlCustomParser*> &customParserCache() const { return customParsers; }
|
||||
|
@ -119,9 +117,14 @@ private:
|
|||
QQmlEnginePrivate *engine;
|
||||
QQmlCompiledData *compiledData;
|
||||
QQmlTypeData *typeData;
|
||||
QQmlRefPointer<QQmlTypeNameCache> importCache;
|
||||
QmlIR::Document *document;
|
||||
// index is string index of type name (use obj->inheritedTypeNameIndex)
|
||||
QHash<int, QQmlCustomParser*> customParsers;
|
||||
|
||||
// index in first hash is component index, vector inside contains object indices of objects with id property
|
||||
QVector<quint32> m_componentRoots;
|
||||
QQmlPropertyCacheVector m_propertyCaches;
|
||||
};
|
||||
|
||||
struct QQmlCompilePass
|
||||
|
@ -268,20 +271,31 @@ protected:
|
|||
const int indexOfRootObject;
|
||||
|
||||
// indices of the objects that are actually Component {}
|
||||
QVector<int> componentRoots;
|
||||
// indices of objects that are the beginning of a new component
|
||||
// scope. This is sorted and used for binary search.
|
||||
QVector<quint32> componentBoundaries;
|
||||
QVector<quint32> componentRoots;
|
||||
|
||||
int _componentIndex;
|
||||
QHash<int, int> _idToObjectIndex;
|
||||
QHash<int, int> *_objectIndexToIdInScope;
|
||||
QList<int> _objectsWithAliases;
|
||||
|
||||
QHash<int, QQmlCompiledData::TypeReference*> *resolvedTypes;
|
||||
QQmlPropertyCacheVector propertyCaches;
|
||||
QHash<int, int> *objectIndexToIdForRoot;
|
||||
QHash<int, QHash<int, int> > *objectIndexToIdPerComponent;
|
||||
};
|
||||
|
||||
class QQmlDeferredAndCustomParserBindingScanner : public QQmlCompilePass
|
||||
{
|
||||
public:
|
||||
QQmlDeferredAndCustomParserBindingScanner(QQmlTypeCompiler *typeCompiler);
|
||||
|
||||
bool scanObject();
|
||||
|
||||
private:
|
||||
bool scanObject(int objectIndex);
|
||||
|
||||
QList<QmlIR::Object*> *qmlObjects;
|
||||
QQmlPropertyCacheVector propertyCaches;
|
||||
const QHash<int, QQmlCustomParser*> &customParsers;
|
||||
|
||||
bool _seenObjectWithId;
|
||||
};
|
||||
|
||||
class QQmlPropertyValidator : public QQmlCompilePass
|
||||
|
@ -300,8 +314,6 @@ private:
|
|||
bool validateLiteralBinding(QQmlPropertyCache *propertyCache, QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) const;
|
||||
bool validateObjectBinding(QQmlPropertyData *property, const QString &propertyName, const QV4::CompiledData::Binding *binding) const;
|
||||
|
||||
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
|
||||
|
||||
bool canCoerce(int to, QQmlPropertyCache *fromMo) const;
|
||||
|
||||
QQmlEnginePrivate *enginePrivate;
|
||||
|
@ -309,12 +321,8 @@ private:
|
|||
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
|
||||
const QHash<int, QQmlCustomParser*> &customParsers;
|
||||
const QQmlPropertyCacheVector &propertyCaches;
|
||||
const QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
|
||||
QHash<int, QBitArray> *customParserBindingsPerObject;
|
||||
|
||||
// collected state variables, essentially write-only
|
||||
mutable QHash<int, QBitArray> _deferredBindingsPerObject;
|
||||
mutable bool _seenObjectWithId;
|
||||
mutable QVector<QV4::CompiledData::BindingPropertyData> _bindingPropertyDataPerObject;
|
||||
};
|
||||
|
||||
|
@ -327,12 +335,9 @@ public:
|
|||
bool generateCodeForComponents();
|
||||
|
||||
private:
|
||||
bool compileComponent(int componentRoot, const QHash<int, int> &objectIndexToId);
|
||||
bool compileComponent(int componentRoot);
|
||||
bool compileJavaScriptCodeInObjectsRecursively(int objectIndex, int scopeObjectIndex);
|
||||
|
||||
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
|
||||
|
||||
const QHash<int, QHash<int, int> > &objectIndexToIdPerComponent;
|
||||
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
|
||||
const QHash<int, QQmlCustomParser*> &customParsers;
|
||||
const QList<QmlIR::Object*> &qmlObjects;
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include <private/qv4lookup_p.h>
|
||||
#include <private/qv4regexpobject_p.h>
|
||||
#include <private/qqmlpropertycache_p.h>
|
||||
#include <private/qqmltypeloader_p.h>
|
||||
#endif
|
||||
#include <private/qqmlirbuilder_p.h>
|
||||
#include <QCoreApplication>
|
||||
|
@ -67,6 +68,9 @@ CompilationUnit::CompilationUnit()
|
|||
, runtimeLookups(0)
|
||||
, runtimeRegularExpressions(0)
|
||||
, runtimeClasses(0)
|
||||
, totalBindingsCount(0)
|
||||
, totalParserStatusCount(0)
|
||||
, totalObjectCount(0)
|
||||
{}
|
||||
|
||||
CompilationUnit::~CompilationUnit()
|
||||
|
@ -165,6 +169,18 @@ void CompilationUnit::unlink()
|
|||
{
|
||||
if (engine)
|
||||
engine->compilationUnits.erase(engine->compilationUnits.find(this));
|
||||
|
||||
for (int ii = 0; ii < propertyCaches.count(); ++ii)
|
||||
if (propertyCaches.at(ii).data())
|
||||
propertyCaches.at(ii)->release();
|
||||
propertyCaches.clear();
|
||||
|
||||
for (int ii = 0; ii < dependentScripts.count(); ++ii)
|
||||
dependentScripts.at(ii)->release();
|
||||
dependentScripts.clear();
|
||||
|
||||
importCache = nullptr;
|
||||
|
||||
engine = 0;
|
||||
free(runtimeStrings);
|
||||
runtimeStrings = 0;
|
||||
|
@ -189,6 +205,22 @@ void CompilationUnit::markObjects(QV4::ExecutionEngine *e)
|
|||
}
|
||||
}
|
||||
|
||||
IdentifierHash<int> CompilationUnit::namedObjectsPerComponent(int componentObjectIndex)
|
||||
{
|
||||
auto it = namedObjectsPerComponentCache.find(componentObjectIndex);
|
||||
if (it == namedObjectsPerComponentCache.end()) {
|
||||
IdentifierHash<int> namedObjectCache(engine);
|
||||
const CompiledData::Object *component = data->objectAt(componentObjectIndex);
|
||||
const quint32 *namedObjectIndexPtr = component->namedObjectsInComponentTable();
|
||||
for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) {
|
||||
const CompiledData::Object *namedObject = data->objectAt(*namedObjectIndexPtr);
|
||||
namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id);
|
||||
}
|
||||
it = namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache);
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
#endif // V4_BOOTSTRAP
|
||||
|
||||
Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
|
||||
|
|
|
@ -60,11 +60,22 @@
|
|||
#include <private/qv4executableallocator_p.h>
|
||||
#include <private/qqmlrefcount_p.h>
|
||||
#include <private/qqmlnullablevalue_p.h>
|
||||
#include <private/qv4identifier_p.h>
|
||||
#include <private/qflagpointer_p.h>
|
||||
#ifndef V4_BOOTSTRAP
|
||||
#include <private/qqmltypenamecache_p.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QQmlPropertyCache;
|
||||
class QQmlPropertyData;
|
||||
class QQmlTypeNameCache;
|
||||
class QQmlScriptData;
|
||||
|
||||
// The vector is indexed by QV4::CompiledData::Object index and the flag
|
||||
// indicates whether instantiation of the object requires a VME meta-object.
|
||||
typedef QVector<QFlagPointer<QQmlPropertyCache>> QQmlPropertyCacheVector;
|
||||
|
||||
namespace QmlIR {
|
||||
struct Document;
|
||||
|
@ -234,7 +245,9 @@ struct Q_QML_PRIVATE_EXPORT Binding
|
|||
InitializerForReadOnlyDeclaration = 0x8,
|
||||
IsResolvedEnum = 0x10,
|
||||
IsListItem = 0x20,
|
||||
IsBindingToAlias = 0x40
|
||||
IsBindingToAlias = 0x40,
|
||||
IsDeferredBinding = 0x80,
|
||||
IsCustomParserBinding = 0x100,
|
||||
};
|
||||
|
||||
quint32 flags : 16;
|
||||
|
@ -391,13 +404,22 @@ struct Alias {
|
|||
|
||||
struct Object
|
||||
{
|
||||
enum Flags {
|
||||
NoFlag = 0x0,
|
||||
IsComponent = 0x1, // object was identified to be an explicit or implicit component boundary
|
||||
HasDeferredBindings = 0x2, // any of the bindings are deferred
|
||||
HasCustomParserBindings = 0x4
|
||||
};
|
||||
|
||||
// Depending on the use, this may be the type name to instantiate before instantiating this
|
||||
// object. For grouped properties the type name will be empty and for attached properties
|
||||
// it will be the name of the attached type.
|
||||
quint32 inheritedTypeNameIndex;
|
||||
quint32 idIndex;
|
||||
qint32 indexOfDefaultPropertyOrAlias : 31; // -1 means no default property declared in this object
|
||||
quint32 idNameIndex;
|
||||
qint32 id : 16;
|
||||
qint32 flags : 15;
|
||||
quint32 defaultPropertyIsAlias : 1;
|
||||
qint32 indexOfDefaultPropertyOrAlias; // -1 means no default property declared in this object
|
||||
quint32 nFunctions;
|
||||
quint32 offsetToFunctions;
|
||||
quint32 nProperties;
|
||||
|
@ -408,6 +430,8 @@ struct Object
|
|||
quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
|
||||
quint32 nBindings;
|
||||
quint32 offsetToBindings;
|
||||
quint32 nNamedObjectsInComponent;
|
||||
quint32 offsetToNamedObjectsInComponent;
|
||||
Location location;
|
||||
Location locationOfIdProperty;
|
||||
// Function[]
|
||||
|
@ -415,7 +439,7 @@ struct Object
|
|||
// Signal[]
|
||||
// Binding[]
|
||||
|
||||
static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings)
|
||||
static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings, int nNamedObjectsInComponent)
|
||||
{
|
||||
return ( sizeof(Object)
|
||||
+ nFunctions * sizeof(quint32)
|
||||
|
@ -423,6 +447,7 @@ struct Object
|
|||
+ nAliases * sizeof(Alias)
|
||||
+ nSignals * sizeof(quint32)
|
||||
+ nBindings * sizeof(Binding)
|
||||
+ nNamedObjectsInComponent * sizeof(int)
|
||||
+ 0x7
|
||||
) & ~0x7;
|
||||
}
|
||||
|
@ -453,6 +478,11 @@ struct Object
|
|||
const uint offset = offsetTable[idx];
|
||||
return reinterpret_cast<const Signal*>(reinterpret_cast<const char*>(this) + offset);
|
||||
}
|
||||
|
||||
const quint32 *namedObjectsInComponentTable() const
|
||||
{
|
||||
return reinterpret_cast<const quint32*>(reinterpret_cast<const char *>(this) + offsetToNamedObjectsInComponent);
|
||||
}
|
||||
};
|
||||
|
||||
struct Import
|
||||
|
@ -641,11 +671,29 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
|
|||
QVector<QV4::Function *> runtimeFunctions;
|
||||
mutable QQmlNullableValue<QUrl> m_url;
|
||||
|
||||
// QML specific fields
|
||||
QQmlPropertyCacheVector propertyCaches;
|
||||
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject).data(); }
|
||||
bool isCompositeType() const { return propertyCaches.at(data->indexOfRootObject).flag(); }
|
||||
|
||||
QQmlRefPointer<QQmlTypeNameCache> importCache;
|
||||
|
||||
// index is object index. This allows fast access to the
|
||||
// property data when initializing bindings, avoiding expensive
|
||||
// lookups by string (property name).
|
||||
QVector<BindingPropertyData> bindingPropertyDataPerObject;
|
||||
|
||||
// mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects
|
||||
// this is initialized on-demand by QQmlContextData
|
||||
QHash<int, IdentifierHash<int>> namedObjectsPerComponentCache;
|
||||
IdentifierHash<int> namedObjectsPerComponent(int componentObjectIndex);
|
||||
|
||||
int totalBindingsCount; // Number of bindings used in this type
|
||||
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
|
||||
int totalObjectCount; // Number of objects explicitly instantiated
|
||||
|
||||
QVector<QQmlScriptData *> dependentScripts;
|
||||
|
||||
QV4::Function *linkToEngine(QV4::ExecutionEngine *engine);
|
||||
void unlink();
|
||||
|
||||
|
|
|
@ -71,13 +71,13 @@ public:
|
|||
virtual ~QQmlAbstractProfilerAdapter() {}
|
||||
void setService(QQmlProfilerService *new_service) { service = new_service; }
|
||||
|
||||
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages) = 0;
|
||||
virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages, bool trackLocations) = 0;
|
||||
|
||||
void startProfiling(quint64 features);
|
||||
|
||||
void stopProfiling();
|
||||
|
||||
void reportData() { emit dataRequested(); }
|
||||
void reportData(bool trackLocations) { emit dataRequested(trackLocations); }
|
||||
|
||||
void stopWaiting() { waiting = false; }
|
||||
void startWaiting() { waiting = true; }
|
||||
|
@ -94,7 +94,7 @@ signals:
|
|||
void profilingDisabled();
|
||||
void profilingDisabledWhileWaiting();
|
||||
|
||||
void dataRequested();
|
||||
void dataRequested(bool trackLocations);
|
||||
void referenceTimeKnown(const QElapsedTimer &timer);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -59,19 +59,21 @@ void QQmlProfiler::startProfiling(quint64 features)
|
|||
void QQmlProfiler::stopProfiling()
|
||||
{
|
||||
featuresEnabled = false;
|
||||
reportData();
|
||||
reportData(true);
|
||||
m_locations.clear();
|
||||
}
|
||||
|
||||
void QQmlProfiler::reportData()
|
||||
void QQmlProfiler::reportData(bool trackLocations)
|
||||
{
|
||||
LocationHash resolved;
|
||||
resolved.reserve(m_locations.size());
|
||||
for (auto it = m_locations.constBegin(), end = m_locations.constEnd(); it != end; ++it)
|
||||
resolved.insert(it.key(), it.value());
|
||||
|
||||
// This unrefs all the objects. We have to make sure we do this in the GUI thread. Also, it's
|
||||
// a good idea to release the memory before creating the packets to be sent.
|
||||
m_locations.clear();
|
||||
for (auto it = m_locations.begin(), end = m_locations.end(); it != end; ++it) {
|
||||
if (!trackLocations || !it->sent) {
|
||||
resolved.insert(it.key(), it.value());
|
||||
if (trackLocations)
|
||||
it->sent = true;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<QQmlProfilerData> data;
|
||||
data.swap(m_data);
|
||||
|
|
|
@ -146,26 +146,27 @@ public:
|
|||
// Unfortunately we have to resolve the locations right away because the QML context might not
|
||||
// be available anymore when we send the data.
|
||||
struct RefLocation : public Location {
|
||||
RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr)
|
||||
RefLocation() : Location(), locationType(MaximumRangeType), ref(nullptr), sent(false)
|
||||
{}
|
||||
|
||||
RefLocation(QQmlBinding *binding, QV4::FunctionObject *function) :
|
||||
Location(function->sourceLocation()), locationType(Binding),
|
||||
ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt)
|
||||
ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt), sent(false)
|
||||
{}
|
||||
|
||||
RefLocation(QQmlCompiledData *ref, const QUrl &url, const QV4::CompiledData::Object *obj,
|
||||
const QString &type) :
|
||||
Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url),
|
||||
locationType(Creating), ref(ref)
|
||||
locationType(Creating), ref(ref), sent(false)
|
||||
{}
|
||||
|
||||
RefLocation(QQmlBoundSignalExpression *ref) :
|
||||
Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref)
|
||||
Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref), sent(false)
|
||||
{}
|
||||
|
||||
RefLocation(QQmlDataBlob *ref) :
|
||||
Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref)
|
||||
Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref),
|
||||
sent(false)
|
||||
{}
|
||||
|
||||
bool isValid() const
|
||||
|
@ -175,6 +176,7 @@ public:
|
|||
|
||||
RangeType locationType;
|
||||
QQmlRefPointer<QQmlRefCount> ref;
|
||||
bool sent;
|
||||
};
|
||||
|
||||
typedef QHash<quintptr, Location> LocationHash;
|
||||
|
@ -217,11 +219,6 @@ public:
|
|||
location = RefLocation(expression);
|
||||
}
|
||||
|
||||
void startCreating()
|
||||
{
|
||||
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, Creating));
|
||||
}
|
||||
|
||||
void startCreating(const QV4::CompiledData::Object *obj)
|
||||
{
|
||||
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
|
||||
|
@ -233,10 +230,6 @@ public:
|
|||
const QUrl &url, const QString &type)
|
||||
{
|
||||
quintptr locationId(id(obj));
|
||||
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
|
||||
(1 << RangeLocation | 1 << RangeData),
|
||||
Creating, locationId));
|
||||
|
||||
RefLocation &location = m_locations[locationId];
|
||||
if (!location.isValid())
|
||||
location = RefLocation(ref, url, obj, type);
|
||||
|
@ -261,7 +254,7 @@ public:
|
|||
public slots:
|
||||
void startProfiling(quint64 features);
|
||||
void stopProfiling();
|
||||
void reportData();
|
||||
void reportData(bool trackLocations);
|
||||
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
|
||||
|
||||
signals:
|
||||
|
@ -363,9 +356,10 @@ private:
|
|||
class QQmlObjectCreationProfiler {
|
||||
public:
|
||||
|
||||
QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler)
|
||||
QQmlObjectCreationProfiler(QQmlProfiler *profiler, const QV4::CompiledData::Object *obj)
|
||||
: profiler(profiler)
|
||||
{
|
||||
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating());
|
||||
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, startCreating(obj));
|
||||
}
|
||||
|
||||
~QQmlObjectCreationProfiler()
|
||||
|
|
|
@ -64,12 +64,33 @@ IdentifierHashData::IdentifierHashData(int numBits)
|
|||
memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
|
||||
}
|
||||
|
||||
IdentifierHashData::IdentifierHashData(IdentifierHashData *other)
|
||||
: size(other->size)
|
||||
, numBits(other->numBits)
|
||||
, identifierTable(other->identifierTable)
|
||||
{
|
||||
refCount.store(1);
|
||||
alloc = other->alloc;
|
||||
entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
|
||||
memcpy(entries, other->entries, alloc*sizeof(IdentifierHashEntry));
|
||||
}
|
||||
|
||||
IdentifierHashBase::IdentifierHashBase(ExecutionEngine *engine)
|
||||
{
|
||||
d = new IdentifierHashData(3);
|
||||
d->identifierTable = engine->identifierTable;
|
||||
}
|
||||
|
||||
void IdentifierHashBase::detach()
|
||||
{
|
||||
if (!d || d->refCount == 1)
|
||||
return;
|
||||
IdentifierHashData *newData = new IdentifierHashData(d);
|
||||
if (d && !d->refCount.deref())
|
||||
delete d;
|
||||
d = newData;
|
||||
}
|
||||
|
||||
|
||||
IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier)
|
||||
{
|
||||
|
|
|
@ -85,6 +85,7 @@ struct IdentifierHashEntry {
|
|||
struct IdentifierHashData
|
||||
{
|
||||
IdentifierHashData(int numBits);
|
||||
explicit IdentifierHashData(IdentifierHashData *other);
|
||||
~IdentifierHashData() {
|
||||
free(entries);
|
||||
}
|
||||
|
@ -115,6 +116,8 @@ struct IdentifierHashBase
|
|||
bool contains(const QString &str) const;
|
||||
bool contains(String *str) const;
|
||||
|
||||
void detach();
|
||||
|
||||
protected:
|
||||
IdentifierHashEntry *addEntry(const Identifier *i);
|
||||
const IdentifierHashEntry *lookup(const Identifier *identifier) const;
|
||||
|
@ -141,6 +144,7 @@ struct IdentifierHash : public IdentifierHashBase
|
|||
}
|
||||
|
||||
void add(const QString &str, const T &value);
|
||||
void add(Heap::String *str, const T &value);
|
||||
|
||||
inline T value(const QString &str) const;
|
||||
inline T value(String *str) const;
|
||||
|
@ -197,6 +201,13 @@ void IdentifierHash<T>::add(const QString &str, const T &value)
|
|||
e->value = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void IdentifierHash<T>::add(Heap::String *str, const T &value)
|
||||
{
|
||||
IdentifierHashEntry *e = addEntry(toIdentifier(str));
|
||||
e->value = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T IdentifierHash<T>::value(const QString &str) const
|
||||
{
|
||||
|
@ -223,7 +234,6 @@ QString IdentifierHash<T>::findId(T value) const
|
|||
return QString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -78,7 +78,8 @@ Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(
|
|||
void Profiler::stopProfiling()
|
||||
{
|
||||
featuresEnabled = 0;
|
||||
reportData();
|
||||
reportData(true);
|
||||
m_sentLocations.clear();
|
||||
}
|
||||
|
||||
bool operator<(const FunctionCall &call1, const FunctionCall &call2)
|
||||
|
@ -88,7 +89,7 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2)
|
|||
(call1.m_end == call2.m_end && call1.m_function < call2.m_function)));
|
||||
}
|
||||
|
||||
void Profiler::reportData()
|
||||
void Profiler::reportData(bool trackLocations)
|
||||
{
|
||||
std::sort(m_data.begin(), m_data.end());
|
||||
QVector<FunctionCallProperties> properties;
|
||||
|
@ -97,9 +98,15 @@ void Profiler::reportData()
|
|||
|
||||
foreach (const FunctionCall &call, m_data) {
|
||||
properties.append(call.properties());
|
||||
FunctionLocation &location = locations[properties.constLast().id];
|
||||
if (!location.isValid())
|
||||
location = call.resolveLocation();
|
||||
Function *function = call.function();
|
||||
SentMarker &marker = m_sentLocations[reinterpret_cast<quintptr>(function)];
|
||||
if (!trackLocations || !marker.isValid()) {
|
||||
FunctionLocation &location = locations[properties.constLast().id];
|
||||
if (!location.isValid())
|
||||
location = call.resolveLocation();
|
||||
if (trackLocations)
|
||||
marker.setFunction(function);
|
||||
}
|
||||
}
|
||||
|
||||
emit dataReady(locations, properties, m_memory_data);
|
||||
|
|
|
@ -134,6 +134,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
Function *function() const
|
||||
{
|
||||
return m_function;
|
||||
}
|
||||
|
||||
FunctionLocation resolveLocation() const;
|
||||
FunctionCallProperties properties() const;
|
||||
|
||||
|
@ -165,6 +170,46 @@ class Q_QML_EXPORT Profiler : public QObject {
|
|||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Profiler)
|
||||
public:
|
||||
struct SentMarker {
|
||||
SentMarker() : m_function(nullptr) {}
|
||||
|
||||
SentMarker(const SentMarker &other) : m_function(other.m_function)
|
||||
{
|
||||
if (m_function)
|
||||
m_function->compilationUnit->addref();
|
||||
}
|
||||
|
||||
~SentMarker()
|
||||
{
|
||||
if (m_function)
|
||||
m_function->compilationUnit->release();
|
||||
}
|
||||
|
||||
SentMarker &operator=(const SentMarker &other)
|
||||
{
|
||||
if (&other != this) {
|
||||
if (m_function)
|
||||
m_function->compilationUnit->release();
|
||||
m_function = other.m_function;
|
||||
m_function->compilationUnit->addref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void setFunction(Function *function)
|
||||
{
|
||||
Q_ASSERT(m_function == nullptr);
|
||||
m_function = function;
|
||||
m_function->compilationUnit->addref();
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{ return m_function != nullptr; }
|
||||
|
||||
private:
|
||||
Function *m_function;
|
||||
};
|
||||
|
||||
Profiler(QV4::ExecutionEngine *engine);
|
||||
|
||||
size_t trackAlloc(size_t size, MemoryType type)
|
||||
|
@ -186,7 +231,7 @@ public:
|
|||
public slots:
|
||||
void stopProfiling();
|
||||
void startProfiling(quint64 features);
|
||||
void reportData();
|
||||
void reportData(bool trackLocations);
|
||||
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
|
||||
|
||||
signals:
|
||||
|
@ -199,6 +244,7 @@ private:
|
|||
QElapsedTimer m_timer;
|
||||
QVector<FunctionCall> m_data;
|
||||
QVector<MemoryAllocationProperties> m_memory_data;
|
||||
QHash<quintptr, SentMarker> m_sentLocations;
|
||||
|
||||
friend class FunctionCallProfiler;
|
||||
};
|
||||
|
@ -237,6 +283,7 @@ Q_DECLARE_TYPEINFO(QV4::Profiling::MemoryAllocationProperties, Q_MOVABLE_TYPE);
|
|||
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCallProperties, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionCall, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QV4::Profiling::FunctionLocation, Q_MOVABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QV4::Profiling::Profiler::SentMarker, Q_MOVABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)
|
||||
|
|
|
@ -68,7 +68,7 @@
|
|||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
#define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT (std::size_t)128*1024
|
||||
#define MIN_UNMANAGED_HEAPSIZE_GC_LIMIT std::size_t(128 * 1024)
|
||||
|
||||
using namespace WTF;
|
||||
|
||||
|
@ -108,29 +108,20 @@ using namespace QV4;
|
|||
|
||||
struct MemoryManager::Data
|
||||
{
|
||||
const size_t pageSize;
|
||||
|
||||
struct ChunkHeader {
|
||||
Heap::Base freeItems;
|
||||
ChunkHeader *nextNonFull;
|
||||
char *itemStart;
|
||||
char *itemEnd;
|
||||
int itemSize;
|
||||
unsigned itemSize;
|
||||
};
|
||||
|
||||
bool gcBlocked;
|
||||
bool aggressiveGC;
|
||||
bool gcStats;
|
||||
ExecutionEngine *engine;
|
||||
|
||||
enum { MaxItemSize = 512 };
|
||||
ChunkHeader *nonFullChunks[MaxItemSize/16];
|
||||
uint nChunks[MaxItemSize/16];
|
||||
uint availableItems[MaxItemSize/16];
|
||||
uint allocCount[MaxItemSize/16];
|
||||
int totalItems;
|
||||
int totalAlloc;
|
||||
uint maxShift;
|
||||
std::size_t maxChunkSize;
|
||||
QVector<PageAllocation> heapChunks;
|
||||
std::vector<PageAllocation> heapChunks;
|
||||
std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
|
||||
std::size_t unmanagedHeapSizeGCLimit;
|
||||
|
||||
|
@ -147,24 +138,39 @@ struct MemoryManager::Data
|
|||
LargeItem *largeItems;
|
||||
std::size_t totalLargeItemsAllocated;
|
||||
|
||||
enum { MaxItemSize = 512 };
|
||||
ChunkHeader *nonFullChunks[MaxItemSize/16];
|
||||
uint nChunks[MaxItemSize/16];
|
||||
uint availableItems[MaxItemSize/16];
|
||||
uint allocCount[MaxItemSize/16];
|
||||
int totalItems;
|
||||
int totalAlloc;
|
||||
uint maxShift;
|
||||
|
||||
bool gcBlocked;
|
||||
bool aggressiveGC;
|
||||
bool gcStats;
|
||||
bool unused; // suppress padding warning
|
||||
|
||||
// statistics:
|
||||
#ifdef DETAILED_MM_STATS
|
||||
QVector<unsigned> allocSizeCounters;
|
||||
#endif // DETAILED_MM_STATS
|
||||
|
||||
Data()
|
||||
: gcBlocked(false)
|
||||
, aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
|
||||
, gcStats(!qEnvironmentVariableIsEmpty("QV4_MM_STATS"))
|
||||
: pageSize(WTF::pageSize())
|
||||
, engine(0)
|
||||
, totalItems(0)
|
||||
, totalAlloc(0)
|
||||
, maxShift(maxShiftValue())
|
||||
, maxChunkSize(maxChunkSizeValue())
|
||||
, unmanagedHeapSize(0)
|
||||
, unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
|
||||
, largeItems(0)
|
||||
, totalLargeItemsAllocated(0)
|
||||
, totalItems(0)
|
||||
, totalAlloc(0)
|
||||
, maxShift(maxShiftValue())
|
||||
, gcBlocked(false)
|
||||
, aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
|
||||
, gcStats(!qEnvironmentVariableIsEmpty("QV4_MM_STATS"))
|
||||
{
|
||||
memset(nonFullChunks, 0, sizeof(nonFullChunks));
|
||||
memset(nChunks, 0, sizeof(nChunks));
|
||||
|
@ -174,7 +180,7 @@ struct MemoryManager::Data
|
|||
|
||||
~Data()
|
||||
{
|
||||
for (QVector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
|
||||
for (std::vector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
|
||||
Q_V4_PROFILE_DEALLOC(engine, 0, i->size(), Profiling::HeapPage);
|
||||
i->deallocate();
|
||||
}
|
||||
|
@ -198,7 +204,7 @@ bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, Exec
|
|||
// qDebug("chunk @ %p, in use: %s, mark bit: %s",
|
||||
// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false"));
|
||||
|
||||
Q_ASSERT((qintptr) item % 16 == 0);
|
||||
Q_ASSERT(qintptr(item) % 16 == 0);
|
||||
|
||||
if (m->isMarked()) {
|
||||
Q_ASSERT(m->inUse());
|
||||
|
@ -324,14 +330,15 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
|
|||
if (shift > m_d->maxShift)
|
||||
shift = m_d->maxShift;
|
||||
std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
|
||||
allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
|
||||
allocSize = roundUpToMultipleOf(m_d->pageSize, allocSize);
|
||||
PageAllocation allocation = PageAllocation::allocate(
|
||||
Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage),
|
||||
OSAllocator::JSGCHeapPages);
|
||||
m_d->heapChunks.append(allocation);
|
||||
m_d->heapChunks.push_back(allocation);
|
||||
|
||||
header = reinterpret_cast<Data::ChunkHeader *>(allocation.base());
|
||||
header->itemSize = int(size);
|
||||
Q_ASSERT(size <= UINT_MAX);
|
||||
header->itemSize = unsigned(size);
|
||||
header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader));
|
||||
header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize;
|
||||
|
||||
|
@ -347,7 +354,8 @@ Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize
|
|||
}
|
||||
last->setNextFree(0);
|
||||
m = header->freeItems.nextFree();
|
||||
const size_t increase = (header->itemEnd - header->itemStart) / header->itemSize;
|
||||
Q_ASSERT(header->itemEnd >= header->itemStart);
|
||||
const size_t increase = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
|
||||
m_d->availableItems[pos] += uint(increase);
|
||||
m_d->totalItems += int(increase);
|
||||
#ifdef V4_USE_VALGRIND
|
||||
|
@ -465,22 +473,23 @@ void MemoryManager::sweep(bool lastSweep)
|
|||
}
|
||||
}
|
||||
|
||||
bool *chunkIsEmpty = (bool *)alloca(m_d->heapChunks.size() * sizeof(bool));
|
||||
bool *chunkIsEmpty = static_cast<bool *>(alloca(m_d->heapChunks.size() * sizeof(bool)));
|
||||
uint itemsInUse[MemoryManager::Data::MaxItemSize/16];
|
||||
memset(itemsInUse, 0, sizeof(itemsInUse));
|
||||
memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks));
|
||||
|
||||
for (int i = 0; i < m_d->heapChunks.size(); ++i) {
|
||||
for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
|
||||
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base());
|
||||
chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine, &m_d->unmanagedHeapSize);
|
||||
}
|
||||
|
||||
QVector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
|
||||
for (int i = 0; i < m_d->heapChunks.size(); ++i) {
|
||||
std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
|
||||
for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
|
||||
Q_ASSERT(chunkIter != m_d->heapChunks.end());
|
||||
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base());
|
||||
const size_t pos = header->itemSize >> 4;
|
||||
const size_t decrease = (header->itemEnd - header->itemStart) / header->itemSize;
|
||||
Q_ASSERT(header->itemEnd >= header->itemStart);
|
||||
const size_t decrease = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
|
||||
|
||||
// Release that chunk if it could have been spared since the last GC run without any difference.
|
||||
if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
|
||||
|
@ -561,7 +570,7 @@ void MemoryManager::runGC()
|
|||
t.restart();
|
||||
const size_t usedBefore = getUsedMem();
|
||||
const size_t largeItemsBefore = getLargeItemsMem();
|
||||
int chunksBefore = m_d->heapChunks.size();
|
||||
size_t chunksBefore = m_d->heapChunks.size();
|
||||
sweep();
|
||||
const size_t usedAfter = getUsedMem();
|
||||
const size_t largeItemsAfter = getLargeItemsMem();
|
||||
|
@ -589,11 +598,11 @@ void MemoryManager::runGC()
|
|||
size_t MemoryManager::getUsedMem() const
|
||||
{
|
||||
size_t usedMem = 0;
|
||||
for (QVector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
|
||||
for (std::vector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
|
||||
Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base());
|
||||
for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
|
||||
Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
|
||||
Q_ASSERT((qintptr) item % 16 == 0);
|
||||
Q_ASSERT(qintptr(item) % 16 == 0);
|
||||
if (m->inUse())
|
||||
usedMem += header->itemSize;
|
||||
}
|
||||
|
@ -604,7 +613,7 @@ size_t MemoryManager::getUsedMem() const
|
|||
size_t MemoryManager::getAllocatedMem() const
|
||||
{
|
||||
size_t total = 0;
|
||||
for (int i = 0; i < m_d->heapChunks.size(); ++i)
|
||||
for (size_t i = 0; i < m_d->heapChunks.size(); ++i)
|
||||
total += m_d->heapChunks.at(i).size();
|
||||
return total;
|
||||
}
|
||||
|
|
|
@ -55,8 +55,7 @@
|
|||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
|
||||
: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false),
|
||||
totalBindingsCount(0), totalParserStatusCount(0)
|
||||
: engine(engine), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
}
|
||||
|
@ -85,16 +84,6 @@ QQmlCompiledData::~QQmlCompiledData()
|
|||
}
|
||||
qDeleteAll(resolvedTypes);
|
||||
resolvedTypes.clear();
|
||||
|
||||
for (int ii = 0; ii < scripts.count(); ++ii)
|
||||
scripts.at(ii)->release();
|
||||
|
||||
if (importCache)
|
||||
importCache->release();
|
||||
|
||||
for (int ii = 0; ii < propertyCaches.count(); ++ii)
|
||||
if (propertyCaches.at(ii).data())
|
||||
propertyCaches.at(ii)->release();
|
||||
}
|
||||
|
||||
void QQmlCompiledData::clear()
|
||||
|
@ -109,7 +98,7 @@ QQmlPropertyCache *QQmlCompiledData::TypeReference::propertyCache() const
|
|||
if (type)
|
||||
return typePropertyCache;
|
||||
else
|
||||
return component->rootPropertyCache();
|
||||
return component->compilationUnit->rootPropertyCache();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -124,7 +113,7 @@ QQmlPropertyCache *QQmlCompiledData::TypeReference::createPropertyCache(QQmlEngi
|
|||
typePropertyCache->addref();
|
||||
return typePropertyCache;
|
||||
} else {
|
||||
return component->rootPropertyCache();
|
||||
return component->compilationUnit->rootPropertyCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +135,7 @@ void QQmlCompiledData::TypeReference::doDynamicTypeCheck()
|
|||
else if (type)
|
||||
mo = type->metaObject();
|
||||
else if (component)
|
||||
mo = component->rootPropertyCache()->firstCppMetaObject();
|
||||
mo = component->compilationUnit->rootPropertyCache()->firstCppMetaObject();
|
||||
isFullyDynamicType = qtTypeInherits<QQmlPropertyMap>(mo);
|
||||
}
|
||||
|
||||
|
|
|
@ -80,10 +80,6 @@ class QQmlComponent;
|
|||
class QQmlContext;
|
||||
class QQmlContextData;
|
||||
|
||||
// The vector is indexed by QV4::CompiledData::Object index and the flag
|
||||
// indicates whether instantiation of the object requires a VME meta-object.
|
||||
typedef QVector<QFlagPointer<QQmlPropertyCache>> QQmlPropertyCacheVector;
|
||||
|
||||
// ### Merge with QV4::CompiledData::CompilationUnit
|
||||
class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup
|
||||
{
|
||||
|
@ -93,8 +89,6 @@ public:
|
|||
|
||||
QQmlEngine *engine;
|
||||
|
||||
QQmlTypeNameCache *importCache;
|
||||
|
||||
int metaTypeId;
|
||||
int listMetaTypeId;
|
||||
bool isRegisteredWithEngine;
|
||||
|
@ -126,23 +120,7 @@ public:
|
|||
// map from name index
|
||||
QHash<int, TypeReference*> resolvedTypes;
|
||||
|
||||
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(compilationUnit->data->indexOfRootObject).data(); }
|
||||
QQmlPropertyCacheVector propertyCaches;
|
||||
QList<QQmlScriptData *> scripts;
|
||||
|
||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
|
||||
// index in first hash is component index, hash inside maps from object index in that scope to integer id
|
||||
QHash<int, QHash<int, int> > objectIndexToIdPerComponent;
|
||||
QHash<int, int> objectIndexToIdForRoot;
|
||||
// hash key is object index, value is indicies of bindings covered by custom parser
|
||||
QHash<int, QBitArray> customParserBindings;
|
||||
QHash<int, QBitArray> deferredBindingsPerObject; // index is object index
|
||||
int totalBindingsCount; // Number of bindings used in this type
|
||||
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
|
||||
int totalObjectCount; // Number of objects explicitly instantiated
|
||||
|
||||
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
|
||||
bool isCompositeType() const { return propertyCaches.at(compilationUnit->data->indexOfRootObject).flag(); }
|
||||
|
||||
bool isInitialized() const { return hasEngine(); }
|
||||
void initialize(QQmlEngine *);
|
||||
|
|
|
@ -310,7 +310,7 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
|
|||
}
|
||||
}
|
||||
|
||||
QV4::IdentifierHash<int> &properties = data->propertyNames();
|
||||
QV4::IdentifierHash<int> &properties = data->detachedPropertyNames();
|
||||
int idx = properties.value(name);
|
||||
if (idx == -1) {
|
||||
properties.add(name, data->idValueCount + d->propertyValues.count());
|
||||
|
@ -346,7 +346,7 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value)
|
|||
return;
|
||||
}
|
||||
|
||||
QV4::IdentifierHash<int> &properties = data->propertyNames();
|
||||
QV4::IdentifierHash<int> &properties = data->detachedPropertyNames();
|
||||
int idx = properties.value(name);
|
||||
|
||||
if (idx == -1) {
|
||||
|
@ -523,7 +523,7 @@ QQmlContextData::QQmlContextData()
|
|||
QQmlContextData::QQmlContextData(QQmlContext *ctxt)
|
||||
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
|
||||
isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
|
||||
publicContext(ctxt), activeVMEData(0),
|
||||
publicContext(ctxt), activeVMEData(0), componentObjectIndex(-1),
|
||||
contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
|
||||
expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
|
||||
componentAttached(0)
|
||||
|
@ -760,15 +760,6 @@ void QQmlContextData::setIdProperty(int idx, QObject *obj)
|
|||
idValues[idx].context = this;
|
||||
}
|
||||
|
||||
void QQmlContextData::setIdPropertyData(const QHash<int, int> &data)
|
||||
{
|
||||
Q_ASSERT(objectIndexToId.isEmpty());
|
||||
objectIndexToId = data;
|
||||
Q_ASSERT(propertyNameCache.isEmpty());
|
||||
idValueCount = data.count();
|
||||
idValues = new ContextGuard[idValueCount];
|
||||
}
|
||||
|
||||
QString QQmlContextData::findObjectId(const QObject *obj) const
|
||||
{
|
||||
const QV4::IdentifierHash<int> &properties = propertyNames();
|
||||
|
@ -804,21 +795,33 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate()
|
|||
return QQmlContextPrivate::get(asQQmlContext());
|
||||
}
|
||||
|
||||
QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const
|
||||
void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex)
|
||||
{
|
||||
typeCompilationUnit = unit;
|
||||
componentObjectIndex = subComponentIndex == -1 ? typeCompilationUnit->data->indexOfRootObject : subComponentIndex;
|
||||
Q_ASSERT(!idValues);
|
||||
idValueCount = typeCompilationUnit->data->objectAt(componentObjectIndex)->nNamedObjectsInComponent;
|
||||
idValues = new ContextGuard[idValueCount];
|
||||
}
|
||||
|
||||
const QV4::IdentifierHash<int> &QQmlContextData::propertyNames() const
|
||||
{
|
||||
if (propertyNameCache.isEmpty()) {
|
||||
propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle()));
|
||||
for (QHash<int, int>::ConstIterator it = objectIndexToId.cbegin(), end = objectIndexToId.cend();
|
||||
it != end; ++it) {
|
||||
const QV4::CompiledData::Object *obj = typeCompilationUnit->data->objectAt(it.key());
|
||||
const QString name = typeCompilationUnit->data->stringAt(obj->idIndex);
|
||||
propertyNameCache.add(name, it.value());
|
||||
}
|
||||
objectIndexToId.clear();
|
||||
if (typeCompilationUnit)
|
||||
propertyNameCache = typeCompilationUnit->namedObjectsPerComponent(componentObjectIndex);
|
||||
else
|
||||
propertyNameCache = QV4::IdentifierHash<int>(QV8Engine::getV4(engine));
|
||||
}
|
||||
return propertyNameCache;
|
||||
}
|
||||
|
||||
QV4::IdentifierHash<int> &QQmlContextData::detachedPropertyNames()
|
||||
{
|
||||
propertyNames();
|
||||
propertyNameCache.detach();
|
||||
return propertyNameCache;
|
||||
}
|
||||
|
||||
QUrl QQmlContextData::url() const
|
||||
{
|
||||
if (typeCompilationUnit)
|
||||
|
|
|
@ -151,9 +151,15 @@ public:
|
|||
// Compilation unit for contexts that belong to a compiled type.
|
||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> typeCompilationUnit;
|
||||
|
||||
mutable QHash<int, int> objectIndexToId;
|
||||
// object index in CompiledData::Unit to component that created this context
|
||||
int componentObjectIndex;
|
||||
|
||||
void initFromTypeCompilationUnit(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &unit, int subComponentIndex);
|
||||
|
||||
// flag indicates whether the context owns the cache (after mutation) or not.
|
||||
mutable QV4::IdentifierHash<int> propertyNameCache;
|
||||
QV4::IdentifierHash<int> &propertyNames() const;
|
||||
const QV4::IdentifierHash<int> &propertyNames() const;
|
||||
QV4::IdentifierHash<int> &detachedPropertyNames();
|
||||
|
||||
// Context object
|
||||
QObject *contextObject;
|
||||
|
@ -201,7 +207,6 @@ public:
|
|||
ContextGuard *idValues;
|
||||
int idValueCount;
|
||||
void setIdProperty(int, QObject *);
|
||||
void setIdPropertyData(const QHash<int, int> &);
|
||||
|
||||
// Linked contexts. this owns linkedContext.
|
||||
QQmlContextData *linkedContext;
|
||||
|
|
|
@ -82,7 +82,7 @@ public:
|
|||
Flags flags() const { return m_flags; }
|
||||
|
||||
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
|
||||
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) = 0;
|
||||
virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) = 0;
|
||||
|
||||
QList<QQmlError> errors() const { return exceptions; }
|
||||
|
||||
|
|
|
@ -2227,7 +2227,7 @@ QQmlMetaObject QQmlEnginePrivate::rawMetaObjectForType(int t) const
|
|||
Locker locker(this);
|
||||
QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
|
||||
if (iter != m_compositeTypes.cend()) {
|
||||
return QQmlMetaObject((*iter)->rootPropertyCache());
|
||||
return QQmlMetaObject((*iter)->compilationUnit->rootPropertyCache());
|
||||
} else {
|
||||
QQmlType *type = QQmlMetaType::qmlType(t);
|
||||
return QQmlMetaObject(type?type->baseMetaObject():0);
|
||||
|
@ -2239,7 +2239,7 @@ QQmlMetaObject QQmlEnginePrivate::metaObjectForType(int t) const
|
|||
Locker locker(this);
|
||||
QHash<int, QQmlCompiledData *>::ConstIterator iter = m_compositeTypes.constFind(t);
|
||||
if (iter != m_compositeTypes.cend()) {
|
||||
return QQmlMetaObject((*iter)->rootPropertyCache());
|
||||
return QQmlMetaObject((*iter)->compilationUnit->rootPropertyCache());
|
||||
} else {
|
||||
QQmlType *type = QQmlMetaType::qmlType(t);
|
||||
return QQmlMetaObject(type?type->metaObject():0);
|
||||
|
@ -2251,7 +2251,7 @@ QQmlPropertyCache *QQmlEnginePrivate::propertyCacheForType(int t)
|
|||
Locker locker(this);
|
||||
QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
|
||||
if (iter != m_compositeTypes.cend()) {
|
||||
return (*iter)->rootPropertyCache();
|
||||
return (*iter)->compilationUnit->rootPropertyCache();
|
||||
} else {
|
||||
QQmlType *type = QQmlMetaType::qmlType(t);
|
||||
locker.unlock();
|
||||
|
@ -2264,7 +2264,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
|
|||
Locker locker(this);
|
||||
QHash<int, QQmlCompiledData*>::ConstIterator iter = m_compositeTypes.constFind(t);
|
||||
if (iter != m_compositeTypes.cend()) {
|
||||
return (*iter)->rootPropertyCache();
|
||||
return (*iter)->compilationUnit->rootPropertyCache();
|
||||
} else {
|
||||
QQmlType *type = QQmlMetaType::qmlType(t);
|
||||
locker.unlock();
|
||||
|
@ -2274,7 +2274,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t)
|
|||
|
||||
void QQmlEnginePrivate::registerInternalCompositeType(QQmlCompiledData *data)
|
||||
{
|
||||
QByteArray name = data->rootPropertyCache()->className();
|
||||
QByteArray name = data->compilationUnit->rootPropertyCache()->className();
|
||||
|
||||
QByteArray ptr = name + '*';
|
||||
QByteArray lst = "QQmlListProperty<" + name + '>';
|
||||
|
|
|
@ -494,7 +494,7 @@ QQmlType *QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const
|
|||
if (!td || !td->isComplete())
|
||||
return 0;
|
||||
QQmlCompiledData *cd = td->compiledData();
|
||||
const QMetaObject *mo = cd->rootPropertyCache()->firstCppMetaObject();
|
||||
const QMetaObject *mo = cd->compilationUnit->rootPropertyCache()->firstCppMetaObject();
|
||||
return QQmlMetaType::qmlType(mo);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
|
|||
: phase(Startup)
|
||||
, compiledData(compiledData)
|
||||
, resolvedTypes(compiledData->resolvedTypes)
|
||||
, propertyCaches(compiledData->propertyCaches)
|
||||
, propertyCaches(compiledData->compilationUnit->propertyCaches)
|
||||
, activeVMEDataForRootContext(activeVMEDataForRootContext)
|
||||
{
|
||||
init(parentContext);
|
||||
|
@ -81,23 +81,23 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompile
|
|||
sharedState = new QQmlObjectCreatorSharedState;
|
||||
topLevelCreator = true;
|
||||
sharedState->componentAttached = 0;
|
||||
sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount);
|
||||
sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount);
|
||||
sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount);
|
||||
sharedState->allCreatedBindings.allocate(compiledData->compilationUnit->totalBindingsCount);
|
||||
sharedState->allParserStatusCallbacks.allocate(compiledData->compilationUnit->totalParserStatusCount);
|
||||
sharedState->allCreatedObjects.allocate(compiledData->compilationUnit->totalObjectCount);
|
||||
sharedState->allJavaScriptObjects = 0;
|
||||
sharedState->creationContext = creationContext;
|
||||
sharedState->rootContext = 0;
|
||||
|
||||
QQmlProfiler *profiler = QQmlEnginePrivate::get(engine)->profiler;
|
||||
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler,
|
||||
sharedState->profiler.init(profiler, compiledData->totalParserStatusCount));
|
||||
sharedState->profiler.init(profiler, compiledData->compilationUnit->totalParserStatusCount));
|
||||
}
|
||||
|
||||
QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState)
|
||||
: phase(Startup)
|
||||
, compiledData(compiledData)
|
||||
, resolvedTypes(compiledData->resolvedTypes)
|
||||
, propertyCaches(compiledData->propertyCaches)
|
||||
, propertyCaches(compiledData->compilationUnit->propertyCaches)
|
||||
, activeVMEDataForRootContext(0)
|
||||
{
|
||||
init(parentContext);
|
||||
|
@ -158,19 +158,17 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
|
|||
int objectToCreate;
|
||||
|
||||
if (subComponentIndex == -1) {
|
||||
objectIndexToId = compiledData->objectIndexToIdForRoot;
|
||||
objectToCreate = qmlUnit->indexOfRootObject;
|
||||
} else {
|
||||
objectIndexToId = compiledData->objectIndexToIdPerComponent[subComponentIndex];
|
||||
const QV4::CompiledData::Object *compObj = qmlUnit->objectAt(subComponentIndex);
|
||||
objectToCreate = compObj->bindingTable()->value.objectIndex;
|
||||
}
|
||||
|
||||
context = new QQmlContextData;
|
||||
context->isInternal = true;
|
||||
context->imports = compiledData->importCache;
|
||||
context->imports = compiledData->compilationUnit->importCache;
|
||||
context->imports->addref();
|
||||
context->typeCompilationUnit = compiledData->compilationUnit;
|
||||
context->initFromTypeCompilationUnit(compiledData->compilationUnit, subComponentIndex);
|
||||
context->setParent(parentContext);
|
||||
|
||||
if (!sharedState->rootContext) {
|
||||
|
@ -183,16 +181,14 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
|
|||
|
||||
Q_ASSERT(sharedState->allJavaScriptObjects || topLevelCreator);
|
||||
if (topLevelCreator)
|
||||
sharedState->allJavaScriptObjects = scope.alloc(compiledData->totalObjectCount);
|
||||
sharedState->allJavaScriptObjects = scope.alloc(compiledData->compilationUnit->totalObjectCount);
|
||||
|
||||
context->setIdPropertyData(objectIndexToId);
|
||||
|
||||
if (subComponentIndex == -1 && compiledData->scripts.count()) {
|
||||
QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->scripts.count()));
|
||||
if (subComponentIndex == -1 && compiledData->compilationUnit->dependentScripts.count()) {
|
||||
QV4::ScopedObject scripts(scope, v4->newArrayObject(compiledData->compilationUnit->dependentScripts.count()));
|
||||
context->importedScripts.set(v4, scripts);
|
||||
QV4::ScopedValue v(scope);
|
||||
for (int i = 0; i < compiledData->scripts.count(); ++i) {
|
||||
QQmlScriptData *s = compiledData->scripts.at(i);
|
||||
for (int i = 0; i < compiledData->compilationUnit->dependentScripts.count(); ++i) {
|
||||
QQmlScriptData *s = compiledData->compilationUnit->dependentScripts.at(i);
|
||||
scripts->putIndexed(i, (v = s->scriptValueForContext(context)));
|
||||
}
|
||||
} else if (sharedState->creationContext) {
|
||||
|
@ -240,7 +236,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
|
|||
|
||||
Q_ASSERT(topLevelCreator);
|
||||
Q_ASSERT(!sharedState->allJavaScriptObjects);
|
||||
sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->totalObjectCount);
|
||||
sharedState->allJavaScriptObjects = valueScope.alloc(compiledData->compilationUnit->totalObjectCount);
|
||||
|
||||
QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc(1));
|
||||
|
||||
|
@ -259,11 +255,7 @@ bool QQmlObjectCreator::populateDeferredProperties(QObject *instance)
|
|||
qSwap(_bindingTarget, bindingTarget);
|
||||
qSwap(_vmeMetaObject, vmeMetaObject);
|
||||
|
||||
QBitArray bindingSkipList = compiledData->deferredBindingsPerObject.value(_compiledObjectIndex);
|
||||
for (int i = 0; i < bindingSkipList.count(); ++i)
|
||||
bindingSkipList.setBit(i, !bindingSkipList.testBit(i));
|
||||
|
||||
setupBindings(bindingSkipList);
|
||||
setupBindings(/*applyDeferredBindings=*/true);
|
||||
|
||||
qSwap(_vmeMetaObject, vmeMetaObject);
|
||||
qSwap(_bindingTarget, bindingTarget);
|
||||
|
@ -630,14 +622,14 @@ static QQmlType *qmlTypeForObject(QObject *object)
|
|||
return type;
|
||||
}
|
||||
|
||||
void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
|
||||
void QQmlObjectCreator::setupBindings(bool applyDeferredBindings)
|
||||
{
|
||||
QQmlListProperty<void> savedList;
|
||||
qSwap(_currentList, savedList);
|
||||
|
||||
const QV4::CompiledData::BindingPropertyData &propertyData = compiledData->compilationUnit->bindingPropertyDataPerObject.at(_compiledObjectIndex);
|
||||
|
||||
if (_compiledObject->idIndex) {
|
||||
if (_compiledObject->idNameIndex) {
|
||||
const QQmlPropertyData *idProperty = propertyData.last();
|
||||
Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id"));
|
||||
if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType == QMetaType::QString) {
|
||||
|
@ -645,7 +637,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
|
|||
idBinding.propertyNameIndex = 0; // Not used
|
||||
idBinding.flags = 0;
|
||||
idBinding.type = QV4::CompiledData::Binding::Type_String;
|
||||
idBinding.stringIndex = _compiledObject->idIndex;
|
||||
idBinding.stringIndex = _compiledObject->idNameIndex;
|
||||
idBinding.location = _compiledObject->location; // ###
|
||||
setPropertyValue(idProperty, &idBinding);
|
||||
}
|
||||
|
@ -681,9 +673,17 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
|
|||
|
||||
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
|
||||
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
|
||||
if (static_cast<int>(i) < bindingsToSkip.size() && bindingsToSkip.testBit(i))
|
||||
if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding)
|
||||
continue;
|
||||
|
||||
if (binding->flags & QV4::CompiledData::Binding::IsDeferredBinding) {
|
||||
if (!applyDeferredBindings)
|
||||
continue;
|
||||
} else {
|
||||
if (applyDeferredBindings)
|
||||
continue;
|
||||
}
|
||||
|
||||
const QQmlPropertyData *property = propertyData.at(i);
|
||||
|
||||
if (property && property->isQList()) {
|
||||
|
@ -1005,11 +1005,10 @@ void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location,
|
|||
errors << error;
|
||||
}
|
||||
|
||||
void QQmlObjectCreator::registerObjectWithContextById(int objectIndex, QObject *instance) const
|
||||
void QQmlObjectCreator::registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const
|
||||
{
|
||||
QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(objectIndex);
|
||||
if (idEntry != objectIndexToId.constEnd())
|
||||
context->setIdProperty(idEntry.value(), instance);
|
||||
if (object->id >= 0)
|
||||
context->setIdProperty(object->id, instance);
|
||||
}
|
||||
|
||||
QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
|
||||
|
@ -1022,7 +1021,9 @@ QV4::Heap::QmlContext *QQmlObjectCreator::currentQmlContext()
|
|||
|
||||
QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isContextObject)
|
||||
{
|
||||
QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler);
|
||||
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
|
||||
QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj);
|
||||
|
||||
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
|
||||
|
||||
bool isComponent = false;
|
||||
|
@ -1032,8 +1033,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
|
|||
QQmlParserStatus *parserStatus = 0;
|
||||
bool installPropertyCache = true;
|
||||
|
||||
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
|
||||
if (compiledData->isComponent(index)) {
|
||||
if (obj->flags & QV4::CompiledData::Object::IsComponent) {
|
||||
isComponent = true;
|
||||
QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
|
||||
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
|
||||
|
@ -1125,28 +1125,26 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
|
|||
if (isContextObject)
|
||||
context->contextObject = instance;
|
||||
|
||||
QBitArray bindingsToSkip;
|
||||
if (customParser) {
|
||||
QHash<int, QBitArray>::ConstIterator customParserBindings = compiledData->customParserBindings.constFind(index);
|
||||
if (customParserBindings != compiledData->customParserBindings.constEnd()) {
|
||||
customParser->engine = QQmlEnginePrivate::get(engine);
|
||||
customParser->imports = compiledData->importCache;
|
||||
if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
|
||||
customParser->engine = QQmlEnginePrivate::get(engine);
|
||||
customParser->imports = compiledData->compilationUnit->importCache;
|
||||
|
||||
QList<const QV4::CompiledData::Binding *> bindings;
|
||||
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
|
||||
for (int i = 0; i < customParserBindings->count(); ++i)
|
||||
if (customParserBindings->testBit(i))
|
||||
bindings << obj->bindingTable() + i;
|
||||
customParser->applyBindings(instance, compiledData, bindings);
|
||||
|
||||
customParser->engine = 0;
|
||||
customParser->imports = (QQmlTypeNameCache*)0;
|
||||
bindingsToSkip = *customParserBindings;
|
||||
QList<const QV4::CompiledData::Binding *> bindings;
|
||||
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
|
||||
const QV4::CompiledData::Binding *binding = obj->bindingTable();
|
||||
for (quint32 i = 0; i < obj->nBindings; ++i, ++binding) {
|
||||
if (binding->flags & QV4::CompiledData::Binding::IsCustomParserBinding) {
|
||||
bindings << binding;
|
||||
}
|
||||
}
|
||||
customParser->applyBindings(instance, compiledData->compilationUnit.data(), bindings);
|
||||
|
||||
customParser->engine = 0;
|
||||
customParser->imports = (QQmlTypeNameCache*)0;
|
||||
}
|
||||
|
||||
if (isComponent) {
|
||||
registerObjectWithContextById(index, instance);
|
||||
registerObjectWithContextById(obj, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
@ -1171,7 +1169,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
|
|||
|
||||
qSwap(_qmlContext, qmlContext);
|
||||
|
||||
bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0, bindingsToSkip);
|
||||
bool result = populateInstance(index, instance, /*binding target*/instance, /*value type property*/0);
|
||||
|
||||
qSwap(_qmlContext, qmlContext);
|
||||
qSwap(_scopeObject, scopeObject);
|
||||
|
@ -1266,7 +1264,7 @@ void QQmlObjectCreator::clear()
|
|||
phase = Done;
|
||||
}
|
||||
|
||||
bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty, const QBitArray &bindingsToSkip)
|
||||
bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty)
|
||||
{
|
||||
QQmlData *declarativeData = QQmlData::get(instance, /*create*/true);
|
||||
|
||||
|
@ -1298,33 +1296,23 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
|
|||
vmeMetaObject = QQmlVMEMetaObject::get(_qobject);
|
||||
}
|
||||
|
||||
registerObjectWithContextById(_compiledObjectIndex, _qobject);
|
||||
registerObjectWithContextById(_compiledObject, _qobject);
|
||||
|
||||
qSwap(_propertyCache, cache);
|
||||
qSwap(_vmeMetaObject, vmeMetaObject);
|
||||
|
||||
QBitArray bindingSkipList = bindingsToSkip;
|
||||
{
|
||||
QHash<int, QBitArray>::ConstIterator deferredBindings = compiledData->deferredBindingsPerObject.constFind(_compiledObjectIndex);
|
||||
if (deferredBindings != compiledData->deferredBindingsPerObject.constEnd()) {
|
||||
if (bindingSkipList.isEmpty())
|
||||
bindingSkipList.resize(deferredBindings->count());
|
||||
|
||||
for (int i = 0; i < deferredBindings->count(); ++i)
|
||||
if (deferredBindings->testBit(i))
|
||||
bindingSkipList.setBit(i);
|
||||
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
|
||||
deferData->deferredIdx = _compiledObjectIndex;
|
||||
deferData->compiledData = compiledData;
|
||||
deferData->compiledData->addref();
|
||||
deferData->context = context;
|
||||
_ddata->deferredData = deferData;
|
||||
}
|
||||
if (_compiledObject->flags & QV4::CompiledData::Object::HasDeferredBindings) {
|
||||
QQmlData::DeferredData *deferData = new QQmlData::DeferredData;
|
||||
deferData->deferredIdx = _compiledObjectIndex;
|
||||
deferData->compiledData = compiledData;
|
||||
deferData->compiledData->addref();
|
||||
deferData->context = context;
|
||||
_ddata->deferredData = deferData;
|
||||
}
|
||||
|
||||
if (_compiledObject->nFunctions > 0)
|
||||
setupFunctions();
|
||||
setupBindings(bindingSkipList);
|
||||
setupBindings();
|
||||
|
||||
qSwap(_vmeMetaObject, vmeMetaObject);
|
||||
qSwap(_bindingTarget, bindingTarget);
|
||||
|
|
|
@ -111,10 +111,9 @@ private:
|
|||
QObject *createInstance(int index, QObject *parent = 0, bool isContextObject = false);
|
||||
|
||||
bool populateInstance(int index, QObject *instance,
|
||||
QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty,
|
||||
const QBitArray &bindingsToSkip = QBitArray());
|
||||
QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
|
||||
|
||||
void setupBindings(const QBitArray &bindingsToSkip);
|
||||
void setupBindings(bool applyDeferredBindings = false);
|
||||
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
|
||||
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
|
||||
void setupFunctions();
|
||||
|
@ -122,7 +121,7 @@ private:
|
|||
QString stringAt(int idx) const { return qmlUnit->stringAt(idx); }
|
||||
void recordError(const QV4::CompiledData::Location &location, const QString &description);
|
||||
|
||||
void registerObjectWithContextById(int objectIndex, QObject *instance) const;
|
||||
void registerObjectWithContextById(const QV4::CompiledData::Object *object, QObject *instance) const;
|
||||
|
||||
QV4::Heap::QmlContext *currentQmlContext();
|
||||
|
||||
|
@ -143,7 +142,6 @@ private:
|
|||
QQmlContextData *context;
|
||||
const QHash<int, QQmlCompiledData::TypeReference*> &resolvedTypes;
|
||||
const QQmlPropertyCacheVector &propertyCaches;
|
||||
QHash<int, int> objectIndexToId;
|
||||
QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
|
||||
bool topLevelCreator;
|
||||
void *activeVMEDataForRootContext;
|
||||
|
|
|
@ -452,7 +452,12 @@ QQmlPropertyCache *QQmlPropertyCache::parent() const
|
|||
|
||||
void QQmlPropertyCache::setParent(QQmlPropertyCache *newParent)
|
||||
{
|
||||
if (_parent == newParent)
|
||||
return;
|
||||
if (_parent)
|
||||
_parent->release();
|
||||
_parent = newParent;
|
||||
_parent->addref();
|
||||
}
|
||||
|
||||
// Returns the first C++ type's QMetaObject - that is, the first QMetaObject not created by
|
||||
|
|
|
@ -67,7 +67,7 @@ public:
|
|||
bool ignoreUnknownSignals;
|
||||
bool componentcomplete;
|
||||
|
||||
QQmlRefPointer<QQmlCompiledData> cdata;
|
||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
|
||||
QList<const QV4::CompiledData::Binding *> bindings;
|
||||
};
|
||||
|
||||
|
@ -258,11 +258,11 @@ void QQmlConnectionsParser::verifyBindings(const QV4::CompiledData::Unit *qmlUni
|
|||
}
|
||||
}
|
||||
|
||||
void QQmlConnectionsParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
void QQmlConnectionsParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
{
|
||||
QQmlConnectionsPrivate *p =
|
||||
static_cast<QQmlConnectionsPrivate *>(QObjectPrivate::get(object));
|
||||
p->cdata = cdata;
|
||||
p->compilationUnit = compilationUnit;
|
||||
p->bindings = bindings;
|
||||
}
|
||||
|
||||
|
@ -278,7 +278,7 @@ void QQmlConnections::connectSignals()
|
|||
QQmlData *ddata = QQmlData::get(this);
|
||||
QQmlContextData *ctxtdata = ddata ? ddata->outerContext : 0;
|
||||
|
||||
const QV4::CompiledData::Unit *qmlUnit = d->cdata->compilationUnit->data;
|
||||
const QV4::CompiledData::Unit *qmlUnit = d->compilationUnit->data;
|
||||
foreach (const QV4::CompiledData::Binding *binding, d->bindings) {
|
||||
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_Script);
|
||||
QString propName = qmlUnit->stringAt(binding->propertyNameIndex);
|
||||
|
@ -291,7 +291,7 @@ void QQmlConnections::connectSignals()
|
|||
|
||||
QQmlBoundSignalExpression *expression = ctxtdata ?
|
||||
new QQmlBoundSignalExpression(target, signalIndex,
|
||||
ctxtdata, this, d->cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
|
||||
ctxtdata, this, d->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]) : 0;
|
||||
signal->takeExpression(expression);
|
||||
d->boundsignals += signal;
|
||||
} else {
|
||||
|
|
|
@ -99,7 +99,7 @@ class QQmlConnectionsParser : public QQmlCustomParser
|
|||
{
|
||||
public:
|
||||
virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
|
||||
virtual void applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
|
||||
virtual void applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2401,7 +2401,7 @@ bool QQmlListModelParser::verifyProperty(const QV4::CompiledData::Unit *qmlUnit,
|
|||
listElementTypeName = objName; // cache right name for next time
|
||||
}
|
||||
|
||||
if (!qmlUnit->stringAt(target->idIndex).isEmpty()) {
|
||||
if (!qmlUnit->stringAt(target->idNameIndex).isEmpty()) {
|
||||
error(target->locationOfIdProperty, QQmlListModel::tr("ListElement: cannot use reserved \"id\" property"));
|
||||
return false;
|
||||
}
|
||||
|
@ -2508,13 +2508,13 @@ void QQmlListModelParser::verifyBindings(const QV4::CompiledData::Unit *qmlUnit,
|
|||
}
|
||||
}
|
||||
|
||||
void QQmlListModelParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
void QQmlListModelParser::applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
{
|
||||
QQmlListModel *rv = static_cast<QQmlListModel *>(obj);
|
||||
|
||||
rv->m_engine = QV8Engine::getV4(qmlEngine(rv));
|
||||
|
||||
const QV4::CompiledData::Unit *qmlUnit = cdata->compilationUnit->data;
|
||||
const QV4::CompiledData::Unit *qmlUnit = compilationUnit->data;
|
||||
|
||||
bool setRoles = false;
|
||||
|
||||
|
|
|
@ -188,7 +188,7 @@ public:
|
|||
QQmlListModelParser() : QQmlCustomParser(QQmlCustomParser::AcceptsSignalHandlers) {}
|
||||
|
||||
void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
|
||||
void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
|
||||
void applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
bool verifyProperty(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);
|
||||
|
|
|
@ -70,7 +70,7 @@ void QQmlProfilerClient::sendRecordingStatus(bool record, int engineId, quint32
|
|||
Q_D(const QQmlProfilerClient);
|
||||
|
||||
QPacket stream(d->connection->currentDataStreamVersion());
|
||||
stream << record << engineId << d->features << flushInterval;
|
||||
stream << record << engineId << d->features << flushInterval << true;
|
||||
sendMessage(stream.data());
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ inline QQmlProfilerDefinitions::ProfileFeature featureFromRangeType(
|
|||
|
||||
void QQmlProfilerClient::messageReceived(const QByteArray &data)
|
||||
{
|
||||
Q_D(const QQmlProfilerClient);
|
||||
Q_D(QQmlProfilerClient);
|
||||
|
||||
QPacket stream(d->connection->currentDataStreamVersion(), data);
|
||||
|
||||
|
@ -333,12 +333,25 @@ void QQmlProfilerClient::messageReceived(const QByteArray &data)
|
|||
!(d->features & one << featureFromRangeType(rangeType)))
|
||||
return;
|
||||
|
||||
qint64 typeId = 0;
|
||||
if (messageType == QQmlProfilerDefinitions::RangeStart) {
|
||||
rangeStart(rangeType, time);
|
||||
if (!stream.atEnd()) {
|
||||
stream >> typeId;
|
||||
auto i = d->types.constFind(typeId);
|
||||
if (i != d->types.constEnd()) {
|
||||
rangeLocation(rangeType, time, i->location);
|
||||
rangeData(rangeType, time, i->name);
|
||||
}
|
||||
}
|
||||
} else if (messageType == QQmlProfilerDefinitions::RangeData) {
|
||||
QString data;
|
||||
stream >> data;
|
||||
rangeData(rangeType, time, data);
|
||||
if (!stream.atEnd()) {
|
||||
stream >> typeId;
|
||||
d->types[typeId].name = data;
|
||||
}
|
||||
} else if (messageType == QQmlProfilerDefinitions::RangeLocation) {
|
||||
QQmlEventLocation location;
|
||||
stream >> location.filename >> location.line;
|
||||
|
@ -347,6 +360,10 @@ void QQmlProfilerClient::messageReceived(const QByteArray &data)
|
|||
stream >> location.column;
|
||||
|
||||
rangeLocation(rangeType, time, location);
|
||||
if (!stream.atEnd()) {
|
||||
stream >> typeId;
|
||||
d->types[typeId].location = location;
|
||||
}
|
||||
} else if (messageType == QQmlProfilerDefinitions::RangeEnd) {
|
||||
rangeEnd(rangeType, time);
|
||||
} else {
|
||||
|
|
|
@ -56,12 +56,20 @@
|
|||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct QQmlProfilerRangeType
|
||||
{
|
||||
QQmlEventLocation location;
|
||||
QString name;
|
||||
};
|
||||
|
||||
class QQmlProfilerClientPrivate : public QQmlDebugClientPrivate
|
||||
{
|
||||
Q_DECLARE_PUBLIC(QQmlProfilerClient)
|
||||
public:
|
||||
QQmlProfilerClientPrivate(QQmlDebugConnection *connection);
|
||||
quint64 features;
|
||||
|
||||
QHash<qint64, QQmlProfilerRangeType> types;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -415,4 +415,26 @@ Item {
|
|||
\endqml
|
||||
*/
|
||||
|
||||
/*!
|
||||
\qmlproperty int QtQuick::WheelEvent::inverted
|
||||
|
||||
Returns whether the delta values delivered with the event are inverted.
|
||||
|
||||
Normally, a vertical wheel will produce a WheelEvent with positive delta
|
||||
values if the top of the wheel is rotating away from the hand operating it.
|
||||
Similarly, a horizontal wheel movement will produce a QWheelEvent with
|
||||
positive delta values if the top of the wheel is moved to the left.
|
||||
|
||||
However, on some platforms this is configurable, so that the same
|
||||
operations described above will produce negative delta values (but with the
|
||||
same magnitude). For instance, in a QML component (such as a tumbler or a
|
||||
slider) where it is appropriate to synchronize the movement or rotation of
|
||||
an item with the direction of the wheel, regardless of the system settings,
|
||||
the wheel event handler can use the inverted property to decide whether to
|
||||
negate the angleDelta or pixelDelta values.
|
||||
|
||||
\note Many platforms provide no such information. On such platforms
|
||||
\l inverted always returns false.
|
||||
*/
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -73,10 +73,22 @@ class QQuickKeyEvent : public QObject
|
|||
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
|
||||
|
||||
public:
|
||||
QQuickKeyEvent(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
|
||||
: event(type, key, modifiers, text, autorep, count) { event.setAccepted(false); }
|
||||
QQuickKeyEvent(const QKeyEvent &ke)
|
||||
: event(ke) { event.setAccepted(false); }
|
||||
QQuickKeyEvent()
|
||||
: event(QEvent::None, 0, 0)
|
||||
{}
|
||||
|
||||
void reset(QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
|
||||
const QString &text = QString(), bool autorep = false, ushort count = 1)
|
||||
{
|
||||
event = QKeyEvent(type, key, modifiers, text, autorep, count);
|
||||
event.setAccepted(false);
|
||||
}
|
||||
|
||||
void reset(const QKeyEvent &ke)
|
||||
{
|
||||
event = ke;
|
||||
event.setAccepted(false);
|
||||
}
|
||||
|
||||
int key() const { return event.key(); }
|
||||
QString text() const { return event.text(); }
|
||||
|
@ -109,10 +121,21 @@ class Q_QUICK_PRIVATE_EXPORT QQuickMouseEvent : public QObject
|
|||
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
|
||||
|
||||
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)
|
||||
, _source(Qt::MouseEventNotSynthesized), _wasHeld(wasHeld), _isClick(isClick), _accepted(true) {}
|
||||
QQuickMouseEvent() {}
|
||||
|
||||
void reset(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;
|
||||
_source = Qt::MouseEventNotSynthesized;
|
||||
_wasHeld = wasHeld;
|
||||
_isClick = isClick;
|
||||
_accepted = true;
|
||||
}
|
||||
|
||||
qreal x() const { return _x; }
|
||||
qreal y() const { return _y; }
|
||||
|
@ -139,9 +162,9 @@ private:
|
|||
Qt::MouseButtons _buttons;
|
||||
Qt::KeyboardModifiers _modifiers;
|
||||
Qt::MouseEventSource _source;
|
||||
bool _wasHeld;
|
||||
bool _isClick;
|
||||
bool _accepted;
|
||||
bool _wasHeld : 1;
|
||||
bool _isClick : 1;
|
||||
bool _accepted : 1;
|
||||
};
|
||||
|
||||
class QQuickWheelEvent : public QObject
|
||||
|
@ -153,13 +176,24 @@ class QQuickWheelEvent : public QObject
|
|||
Q_PROPERTY(QPoint pixelDelta READ pixelDelta)
|
||||
Q_PROPERTY(int buttons READ buttons)
|
||||
Q_PROPERTY(int modifiers READ modifiers)
|
||||
Q_PROPERTY(bool inverted READ inverted)
|
||||
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted)
|
||||
|
||||
public:
|
||||
QQuickWheelEvent(qreal x, qreal y, const QPoint& angleDelta, const QPoint& pixelDelta,
|
||||
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
|
||||
: _x(x), _y(y), _angleDelta(angleDelta), _pixelDelta(pixelDelta), _buttons(buttons),
|
||||
_modifiers(modifiers), _accepted(true) {}
|
||||
QQuickWheelEvent() {}
|
||||
|
||||
void reset(qreal x, qreal y, const QPoint &angleDelta, const QPoint &pixelDelta,
|
||||
Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, bool inverted)
|
||||
{
|
||||
_x = x;
|
||||
_y = y;
|
||||
_angleDelta = angleDelta;
|
||||
_pixelDelta = pixelDelta;
|
||||
_buttons = buttons;
|
||||
_modifiers = modifiers;
|
||||
_accepted = true;
|
||||
_inverted = inverted;
|
||||
}
|
||||
|
||||
qreal x() const { return _x; }
|
||||
qreal y() const { return _y; }
|
||||
|
@ -167,7 +201,7 @@ public:
|
|||
QPoint pixelDelta() const { return _pixelDelta; }
|
||||
int buttons() const { return _buttons; }
|
||||
int modifiers() const { return _modifiers; }
|
||||
|
||||
bool inverted() const { return _inverted; }
|
||||
bool isAccepted() { return _accepted; }
|
||||
void setAccepted(bool accepted) { _accepted = accepted; }
|
||||
|
||||
|
@ -178,6 +212,7 @@ private:
|
|||
QPoint _pixelDelta;
|
||||
Qt::MouseButtons _buttons;
|
||||
Qt::KeyboardModifiers _modifiers;
|
||||
bool _inverted;
|
||||
bool _accepted;
|
||||
};
|
||||
|
||||
|
|
|
@ -1355,7 +1355,8 @@ void QQuickKeysAttached::keyPressed(QKeyEvent *event, bool post)
|
|||
d->inPress = false;
|
||||
}
|
||||
|
||||
QQuickKeyEvent ke(*event);
|
||||
QQuickKeyEvent &ke = d->theKeyEvent;
|
||||
ke.reset(*event);
|
||||
QByteArray keySignal = keyToSignal(event->key());
|
||||
if (!keySignal.isEmpty()) {
|
||||
keySignal += "(QQuickKeyEvent*)";
|
||||
|
@ -1398,7 +1399,8 @@ void QQuickKeysAttached::keyReleased(QKeyEvent *event, bool post)
|
|||
d->inRelease = false;
|
||||
}
|
||||
|
||||
QQuickKeyEvent ke(*event);
|
||||
QQuickKeyEvent &ke = d->theKeyEvent;
|
||||
ke.reset(*event);
|
||||
emit released(&ke);
|
||||
event->setAccepted(ke.isAccepted());
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "qquickanchors_p.h"
|
||||
#include "qquickanchors_p_p.h"
|
||||
#include "qquickitemchangelistener_p.h"
|
||||
#include "qquickevents_p_p.h"
|
||||
|
||||
#include "qquickwindow_p.h"
|
||||
|
||||
|
@ -777,6 +778,7 @@ public:
|
|||
QQuickItem *imeItem;
|
||||
QList<QQuickItem *> targets;
|
||||
QQuickItem *item;
|
||||
QQuickKeyEvent theKeyEvent;
|
||||
};
|
||||
|
||||
class QQuickKeysAttached : public QObject, public QQuickItemKeyFilter
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
#include "qquickmousearea_p.h"
|
||||
#include "qquickmousearea_p_p.h"
|
||||
#include "qquickwindow.h"
|
||||
#include "qquickevents_p_p.h"
|
||||
#include "qquickdrag_p.h"
|
||||
|
||||
#include <private/qqmldata_p.h>
|
||||
|
@ -761,7 +760,8 @@ void QQuickMouseArea::mouseMoveEvent(QMouseEvent *event)
|
|||
}
|
||||
#endif
|
||||
|
||||
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
|
||||
QQuickMouseEvent &me = d->quickMouseEvent;
|
||||
me.reset(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);
|
||||
|
@ -802,7 +802,8 @@ void QQuickMouseArea::mouseDoubleClickEvent(QMouseEvent *event)
|
|||
Q_D(QQuickMouseArea);
|
||||
if (d->enabled) {
|
||||
d->saveEvent(event);
|
||||
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
|
||||
QQuickMouseEvent &me = d->quickMouseEvent;
|
||||
me.reset(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);
|
||||
|
@ -822,7 +823,8 @@ void QQuickMouseArea::hoverEnterEvent(QHoverEvent *event)
|
|||
d->lastPos = event->posF();
|
||||
d->lastModifiers = event->modifiers();
|
||||
setHovered(true);
|
||||
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
|
||||
QQuickMouseEvent &me = d->quickMouseEvent;
|
||||
me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
|
||||
emit mouseXChanged(&me);
|
||||
me.setPosition(d->lastPos);
|
||||
emit mouseYChanged(&me);
|
||||
|
@ -835,10 +837,11 @@ void QQuickMouseArea::hoverMoveEvent(QHoverEvent *event)
|
|||
Q_D(QQuickMouseArea);
|
||||
if (!d->enabled && !d->pressed) {
|
||||
QQuickItem::hoverMoveEvent(event);
|
||||
} else {
|
||||
} else if (d->lastPos != event->posF()) {
|
||||
d->lastPos = event->posF();
|
||||
d->lastModifiers = event->modifiers();
|
||||
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
|
||||
QQuickMouseEvent &me = d->quickMouseEvent;
|
||||
me.reset(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, d->lastModifiers, false, false);
|
||||
emit mouseXChanged(&me);
|
||||
me.setPosition(d->lastPos);
|
||||
emit mouseYChanged(&me);
|
||||
|
@ -865,8 +868,9 @@ void QQuickMouseArea::wheelEvent(QWheelEvent *event)
|
|||
return;
|
||||
}
|
||||
|
||||
QQuickWheelEvent we(event->posF().x(), event->posF().y(), event->angleDelta(),
|
||||
event->pixelDelta(), event->buttons(), event->modifiers());
|
||||
QQuickWheelEvent &we = d->quickWheelEvent;
|
||||
we.reset(event->posF().x(), event->posF().y(), event->angleDelta(), event->pixelDelta(),
|
||||
event->buttons(), event->modifiers(), event->inverted());
|
||||
we.setAccepted(d->isWheelConnected());
|
||||
emit wheel(&we);
|
||||
if (!we.isAccepted())
|
||||
|
@ -997,7 +1001,8 @@ void QQuickMouseArea::timerEvent(QTimerEvent *event)
|
|||
#endif
|
||||
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);
|
||||
QQuickMouseEvent &me = d->quickMouseEvent;
|
||||
me.reset(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);
|
||||
|
@ -1078,8 +1083,7 @@ void QQuickMouseArea::setHoverEnabled(bool h)
|
|||
\qmlproperty bool QtQuick::MouseArea::containsMouse
|
||||
This property holds whether the mouse is currently inside the mouse area.
|
||||
|
||||
\warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
|
||||
In addition, if hoverEnabled is false, containsMouse will only be valid
|
||||
\warning If hoverEnabled is false, containsMouse will only be valid
|
||||
when the mouse is pressed while the mouse cursor is inside the MouseArea.
|
||||
*/
|
||||
bool QQuickMouseArea::hovered() const
|
||||
|
@ -1175,7 +1179,8 @@ bool QQuickMouseArea::setPressed(Qt::MouseButton button, bool p, Qt::MouseEventS
|
|||
Qt::MouseButtons oldPressed = d->pressed;
|
||||
|
||||
if (wasPressed != p) {
|
||||
QQuickMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
|
||||
QQuickMouseEvent &me = d->quickMouseEvent;
|
||||
me.reset(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
|
||||
me.setSource(source);
|
||||
if (p) {
|
||||
d->pressed |= button;
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
//
|
||||
|
||||
#include "qquickitem_p.h"
|
||||
#include "qquickevents_p_p.h"
|
||||
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtCore/qbasictimer.h>
|
||||
|
@ -107,6 +108,8 @@ public:
|
|||
#ifndef QT_NO_CURSOR
|
||||
QCursor *cursor;
|
||||
#endif
|
||||
QQuickMouseEvent quickMouseEvent;
|
||||
QQuickWheelEvent quickWheelEvent;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
@ -456,7 +456,7 @@ void QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache()
|
|||
{
|
||||
QQuickOpenGLShaderEffectMaterialCache *cache = QQuickOpenGLShaderEffectMaterialCache::get(false);
|
||||
if (cache) {
|
||||
qDeleteAll(cache->cache.values());
|
||||
qDeleteAll(cache->cache);
|
||||
delete cache;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@ void QQuickRenderControl::polishItems()
|
|||
return;
|
||||
|
||||
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
|
||||
cd->flushDelayedTouchEvent();
|
||||
cd->flushFrameSynchronousEvents();
|
||||
if (!d->window)
|
||||
return;
|
||||
cd->polishItems();
|
||||
|
|
|
@ -2028,7 +2028,7 @@ void QQuickWindowPrivate::deliverTouchEvent(QTouchEvent *event)
|
|||
}
|
||||
}
|
||||
|
||||
void QQuickWindowPrivate::flushDelayedTouchEvent()
|
||||
void QQuickWindowPrivate::flushFrameSynchronousEvents()
|
||||
{
|
||||
if (delayedTouch) {
|
||||
deliverDelayedTouchEvent();
|
||||
|
@ -2039,6 +2039,17 @@ void QQuickWindowPrivate::flushDelayedTouchEvent()
|
|||
if (ut && ut->hasStartAnimationPending())
|
||||
ut->startAnimations();
|
||||
}
|
||||
|
||||
// Once per frame, send a synthetic hover, in case items have changed position.
|
||||
// For instance, during animation (including the case of a ListView
|
||||
// whose delegates contain MouseAreas), a MouseArea needs to know
|
||||
// whether it has moved into a position where it is now under the cursor.
|
||||
if (!mouseGrabberItem && !lastMousePosition.isNull()) {
|
||||
bool accepted = false;
|
||||
bool delivered = deliverHoverEvent(contentItem, lastMousePosition, lastMousePosition, QGuiApplication::keyboardModifiers(), accepted);
|
||||
if (!delivered)
|
||||
clearHover(); // take care of any exits
|
||||
}
|
||||
}
|
||||
|
||||
void QQuickWindowPrivate::reallyDeliverTouchEvent(QTouchEvent *event)
|
||||
|
|
|
@ -160,7 +160,7 @@ public:
|
|||
void reallyDeliverTouchEvent(QTouchEvent *);
|
||||
bool deliverTouchCancelEvent(QTouchEvent *);
|
||||
void deliverDelayedTouchEvent();
|
||||
void flushDelayedTouchEvent();
|
||||
void flushFrameSynchronousEvents();
|
||||
bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted);
|
||||
bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered);
|
||||
static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false);
|
||||
|
|
|
@ -126,7 +126,7 @@ void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window)
|
|||
data.updatePending = false;
|
||||
|
||||
if (!data.grabOnly) {
|
||||
cd->flushDelayedTouchEvent();
|
||||
cd->flushFrameSynchronousEvents();
|
||||
// Event delivery/processing triggered the window to be deleted or stop rendering.
|
||||
if (!m_windows.contains(window))
|
||||
return;
|
||||
|
|
|
@ -846,7 +846,7 @@ Renderer::~Renderer()
|
|||
for (int i=0; i<m_batchPool.size(); ++i) qsg_wipeBatch(m_batchPool.at(i), this);
|
||||
}
|
||||
|
||||
foreach (Node *n, m_nodes.values())
|
||||
for (Node *n : qAsConst(m_nodes))
|
||||
m_nodeAllocator.release(n);
|
||||
|
||||
// Remaining elements...
|
||||
|
|
|
@ -382,7 +382,7 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
|
|||
return;
|
||||
|
||||
if (!data.grabOnly) {
|
||||
cd->flushDelayedTouchEvent();
|
||||
cd->flushFrameSynchronousEvents();
|
||||
// Event delivery/processing triggered the window to be deleted or stop rendering.
|
||||
if (!m_windows.contains(window))
|
||||
return;
|
||||
|
|
|
@ -1142,7 +1142,7 @@ void QSGThreadedRenderLoop::polishAndSync(Window *w, bool inExpose)
|
|||
}
|
||||
|
||||
// Flush pending touch events.
|
||||
QQuickWindowPrivate::get(window)->flushDelayedTouchEvent();
|
||||
QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
|
||||
// The delivery of the event might have caused the window to stop rendering
|
||||
w = windowFor(m_windows, window);
|
||||
if (!w || !w->thread || !w->thread->window) {
|
||||
|
|
|
@ -445,7 +445,7 @@ void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
|
|||
}
|
||||
}
|
||||
|
||||
d->flushDelayedTouchEvent();
|
||||
d->flushFrameSynchronousEvents();
|
||||
// Event delivery or processing has caused the window to stop rendering.
|
||||
if (!windowData(window))
|
||||
return;
|
||||
|
|
|
@ -922,15 +922,13 @@ QQuickPixmapStore::~QQuickPixmapStore()
|
|||
#ifndef QT_NO_DEBUG
|
||||
int leakedPixmaps = 0;
|
||||
#endif
|
||||
QList<QQuickPixmapData*> cachedData = m_cache.values();
|
||||
|
||||
// Prevent unreferencePixmap() from assuming it needs to kick
|
||||
// off the cache expiry timer, as we're shrinking the cache
|
||||
// manually below after releasing all the pixmaps.
|
||||
m_timerId = -2;
|
||||
|
||||
// unreference all (leaked) pixmaps
|
||||
foreach (QQuickPixmapData* pixmap, cachedData) {
|
||||
for (auto *pixmap : qAsConst(m_cache)) {
|
||||
int currRefCount = pixmap->refCount;
|
||||
if (currRefCount) {
|
||||
#ifndef QT_NO_DEBUG
|
||||
|
|
|
@ -110,8 +110,9 @@ void QQuickProfiler::stopProfilingImpl()
|
|||
m_data.clear();
|
||||
}
|
||||
|
||||
void QQuickProfiler::reportDataImpl()
|
||||
void QQuickProfiler::reportDataImpl(bool trackLocations)
|
||||
{
|
||||
Q_UNUSED(trackLocations);
|
||||
QMutexLocker lock(&m_dataMutex);
|
||||
emit dataReady(m_data);
|
||||
m_data.clear();
|
||||
|
|
|
@ -353,7 +353,7 @@ signals:
|
|||
protected slots:
|
||||
void startProfilingImpl(quint64 features);
|
||||
void stopProfilingImpl();
|
||||
void reportDataImpl();
|
||||
void reportDataImpl(bool trackLocations);
|
||||
void setTimer(const QElapsedTimer &t);
|
||||
};
|
||||
|
||||
|
|
|
@ -202,7 +202,7 @@ public:
|
|||
|
||||
QPointer<QObject> object;
|
||||
QList<const QV4::CompiledData::Binding *> bindings;
|
||||
QQmlRefPointer<QQmlCompiledData> cdata;
|
||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
|
||||
|
||||
bool decoded : 1;
|
||||
bool restore : 1;
|
||||
|
@ -258,7 +258,7 @@ void QQuickPropertyChangesPrivate::decode()
|
|||
return;
|
||||
|
||||
foreach (const QV4::CompiledData::Binding *binding, bindings)
|
||||
decodeBinding(QString(), cdata->compilationUnit->data, binding);
|
||||
decodeBinding(QString(), compilationUnit->data, binding);
|
||||
|
||||
bindings.clear();
|
||||
|
||||
|
@ -288,7 +288,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix,
|
|||
QQuickReplaceSignalHandler *handler = new QQuickReplaceSignalHandler;
|
||||
handler->property = prop;
|
||||
handler->expression.take(new QQmlBoundSignalExpression(object, QQmlPropertyPrivate::get(prop)->signalIndex(),
|
||||
QQmlContextData::get(qmlContext(q)), object, cdata->compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]));
|
||||
QQmlContextData::get(qmlContext(q)), object, compilationUnit->runtimeFunctions[binding->value.compiledScriptIndex]));
|
||||
signalReplacements << handler;
|
||||
return;
|
||||
}
|
||||
|
@ -338,12 +338,12 @@ void QQuickPropertyChangesParser::verifyBindings(const QV4::CompiledData::Unit *
|
|||
verifyList(qmlUnit, props.at(ii));
|
||||
}
|
||||
|
||||
void QQuickPropertyChangesParser::applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
void QQuickPropertyChangesParser::applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
{
|
||||
QQuickPropertyChangesPrivate *p =
|
||||
static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj));
|
||||
p->bindings = bindings;
|
||||
p->cdata = cdata;
|
||||
p->compilationUnit = compilationUnit;
|
||||
p->decoded = false;
|
||||
}
|
||||
|
||||
|
@ -456,7 +456,7 @@ QQuickPropertyChanges::ActionList QQuickPropertyChanges::actions()
|
|||
QQmlBinding *newBinding = 0;
|
||||
if (e.id != QQmlBinding::Invalid) {
|
||||
QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
|
||||
QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, object(), d->cdata->compilationUnit->runtimeFunctions[e.id]));
|
||||
QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, object(), d->compilationUnit->runtimeFunctions[e.id]));
|
||||
newBinding = new QQmlBinding(function, object(), context);
|
||||
}
|
||||
// QQmlBinding *newBinding = e.id != QQmlBinding::Invalid ? QQmlBinding::createBinding(e.id, object(), qmlContext(this)) : 0;
|
||||
|
|
|
@ -104,7 +104,7 @@ public:
|
|||
void verifyList(const QV4::CompiledData::Unit *qmlUnit, const QV4::CompiledData::Binding *binding);
|
||||
|
||||
virtual void verifyBindings(const QV4::CompiledData::Unit *qmlUnit, const QList<const QV4::CompiledData::Binding *> &props);
|
||||
virtual void applyBindings(QObject *obj, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings);
|
||||
virtual void applyBindings(QObject *obj, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -392,7 +392,7 @@ QQuickSmoothedAnimationPrivate::~QQuickSmoothedAnimationPrivate()
|
|||
|
||||
void QQuickSmoothedAnimationPrivate::updateRunningAnimations()
|
||||
{
|
||||
foreach(QSmoothedAnimation* ease, activeAnimations.values()){
|
||||
for (QSmoothedAnimation *ease : qAsConst(activeAnimations)) {
|
||||
ease->maximumEasingTime = anim->maximumEasingTime;
|
||||
ease->reversingMode = anim->reversingMode;
|
||||
ease->velocity = anim->velocity;
|
||||
|
@ -444,7 +444,8 @@ QAbstractAnimationJob* QQuickSmoothedAnimation::transition(QQuickStateActions &a
|
|||
anims.insert(ease);
|
||||
}
|
||||
|
||||
foreach (QSmoothedAnimation *ease, d->activeAnimations.values()){
|
||||
const auto copy = d->activeAnimations;
|
||||
for (QSmoothedAnimation *ease : copy) {
|
||||
if (!anims.contains(ease)) {
|
||||
ease->clearTemplate();
|
||||
d->activeAnimations.remove(ease->target);
|
||||
|
|
|
@ -585,7 +585,8 @@ QAbstractAnimationJob* QQuickSpringAnimation::transition(QQuickStateActions &act
|
|||
animation->restart();
|
||||
anims.insert(animation);
|
||||
}
|
||||
foreach (QSpringAnimation *anim, d->activeAnimations.values()){
|
||||
const auto copy = d->activeAnimations;
|
||||
for (QSpringAnimation *anim : copy) {
|
||||
if (!anims.contains(anim)) {
|
||||
anim->clearTemplate();
|
||||
d->activeAnimations.remove(anim->target);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import QtQml 2.0
|
||||
Component {
|
||||
QtObject {
|
||||
id: blah
|
||||
}
|
||||
}
|
|
@ -110,11 +110,11 @@ QVariant myCustomVariantTypeConverter(const QString &data)
|
|||
}
|
||||
|
||||
|
||||
void CustomBindingParser::applyBindings(QObject *object, QQmlCompiledData *cdata, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
void CustomBindingParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
{
|
||||
CustomBinding *customBinding = qobject_cast<CustomBinding*>(object);
|
||||
Q_ASSERT(customBinding);
|
||||
customBinding->cdata = cdata;
|
||||
customBinding->compilationUnit = compilationUnit;
|
||||
customBinding->bindings = bindings;
|
||||
}
|
||||
|
||||
|
@ -123,14 +123,14 @@ void CustomBinding::componentComplete()
|
|||
Q_ASSERT(m_target);
|
||||
|
||||
foreach (const QV4::CompiledData::Binding *binding, bindings) {
|
||||
QString name = cdata->compilationUnit->data->stringAt(binding->propertyNameIndex);
|
||||
QString name = compilationUnit->data->stringAt(binding->propertyNameIndex);
|
||||
|
||||
int bindingId = binding->value.compiledScriptIndex;
|
||||
|
||||
QQmlContextData *context = QQmlContextData::get(qmlContext(this));
|
||||
|
||||
QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this)));
|
||||
QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, cdata->compilationUnit->runtimeFunctions[bindingId]));
|
||||
QV4::ScopedValue function(scope, QV4::FunctionObject::createQmlFunction(context, m_target, compilationUnit->runtimeFunctions[bindingId]));
|
||||
QQmlBinding *qmlBinding = new QQmlBinding(function, m_target, context);
|
||||
|
||||
QQmlProperty property(m_target, name, qmlContext(this));
|
||||
|
@ -169,7 +169,7 @@ void EnumSupportingCustomParser::verifyBindings(const QV4::CompiledData::Unit *q
|
|||
}
|
||||
}
|
||||
|
||||
void SimpleObjectCustomParser::applyBindings(QObject *object, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
void SimpleObjectCustomParser::applyBindings(QObject *object, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &bindings)
|
||||
{
|
||||
SimpleObjectWithCustomParser *o = qobject_cast<SimpleObjectWithCustomParser*>(object);
|
||||
Q_ASSERT(o);
|
||||
|
|
|
@ -733,14 +733,14 @@ class MyCustomParserTypeParser : public QQmlCustomParser
|
|||
{
|
||||
public:
|
||||
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
|
||||
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {}
|
||||
virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
|
||||
};
|
||||
|
||||
class EnumSupportingCustomParser : public QQmlCustomParser
|
||||
{
|
||||
public:
|
||||
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &);
|
||||
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &) {}
|
||||
virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &) {}
|
||||
};
|
||||
|
||||
class MyParserStatus : public QObject, public QQmlParserStatus
|
||||
|
@ -1170,7 +1170,7 @@ public:
|
|||
void setTarget(QObject *newTarget) { m_target = newTarget; }
|
||||
|
||||
QPointer<QObject> m_target;
|
||||
QQmlRefPointer<QQmlCompiledData> cdata;
|
||||
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
|
||||
QList<const QV4::CompiledData::Binding*> bindings;
|
||||
QByteArray m_bindingData;
|
||||
};
|
||||
|
@ -1178,7 +1178,7 @@ public:
|
|||
class CustomBindingParser : public QQmlCustomParser
|
||||
{
|
||||
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
|
||||
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &);
|
||||
virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &);
|
||||
};
|
||||
|
||||
class SimpleObjectWithCustomParser : public QObject
|
||||
|
@ -1224,7 +1224,7 @@ private:
|
|||
class SimpleObjectCustomParser : public QQmlCustomParser
|
||||
{
|
||||
virtual void verifyBindings(const QV4::CompiledData::Unit *, const QList<const QV4::CompiledData::Binding *> &) {}
|
||||
virtual void applyBindings(QObject *, QQmlCompiledData *, const QList<const QV4::CompiledData::Binding *> &);
|
||||
virtual void applyBindings(QObject *, QV4::CompiledData::CompilationUnit *, const QList<const QV4::CompiledData::Binding *> &);
|
||||
};
|
||||
|
||||
class RootObjectInCreationTester : public QObject
|
||||
|
|
|
@ -108,6 +108,7 @@ private slots:
|
|||
void bindTypeToJSValue();
|
||||
void customParserTypes();
|
||||
void rootAsQmlComponent();
|
||||
void rootItemIsComponent();
|
||||
void inlineQmlComponents();
|
||||
void idProperty();
|
||||
void autoNotifyConnection();
|
||||
|
@ -1195,6 +1196,19 @@ void tst_qqmllanguage::rootAsQmlComponent()
|
|||
QCOMPARE(object->getChildren()->count(), 2);
|
||||
}
|
||||
|
||||
void tst_qqmllanguage::rootItemIsComponent()
|
||||
{
|
||||
QQmlComponent component(&engine, testFileUrl("rootItemIsComponent.qml"));
|
||||
VERIFY_ERRORS(0);
|
||||
QScopedPointer<QObject> root(component.create());
|
||||
QVERIFY(qobject_cast<QQmlComponent*>(root.data()));
|
||||
QScopedPointer<QObject> other(qobject_cast<QQmlComponent*>(root.data())->create());
|
||||
QVERIFY(!other.isNull());
|
||||
QQmlContext *context = qmlContext(other.data());
|
||||
QVERIFY(context);
|
||||
QCOMPARE(context->nameForObject(other.data()), QStringLiteral("blah"));
|
||||
}
|
||||
|
||||
// Tests that components can be specified inline
|
||||
void tst_qqmllanguage::inlineQmlComponents()
|
||||
{
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 9741ac4655808ac46c127e3d1d8ba3d27ada618e
|
||||
Subproject commit 0b5af3dcec772bb06b4d685a20b2859cda59d189
|
Loading…
Reference in New Issue