Merge remote-tracking branch 'origin/dev' into wip/scenegraphng

Conflicts:
	src/quick/items/qquickopenglshadereffectnode.cpp
	src/quick/items/qquickshadereffect.cpp
	src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
	src/quick/scenegraph/qsgdefaultglyphnode_p.h

Change-Id: I3d6874b4e4231a89d2836c04fe8e7f2ef2d698c4
This commit is contained in:
Laszlo Agocs 2016-05-24 11:08:09 +02:00
commit 9ff09fb283
221 changed files with 3769 additions and 2040 deletions

View File

@ -141,7 +141,7 @@ MinuteTimer *TimeModel::timer=0;
class QExampleQmlPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri)

View File

@ -1,10 +1,15 @@
TARGET = chapter6-plugins
QT += qml quick
# Avoid going to debug/release subdirectory
# so that our application will see the
# import path for the Charts module.
# Ensure that the application will see the import path for the Charts module:
# * On Windows, do not build into a debug/release subdirectory.
# * On OS X, add the plugin files into the bundle.
win32: DESTDIR = ./
osx {
charts.files = $$OUT_PWD/Charts
charts.path = Contents/PlugIns
QMAKE_BUNDLE_DATA += charts
}
SOURCES += main.cpp
RESOURCES += app.qrc

View File

@ -46,7 +46,7 @@
class ChartsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri);

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
@ -37,17 +37,21 @@
** $QT_END_LICENSE$
**
****************************************************************************/
//![0]
#include <QtQuick/QQuickView>
#include <QGuiApplication>
#include <QQmlEngine>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
//![0]
QQuickView view;
#ifdef Q_OS_OSX
view.engine()->addImportPath(app.applicationDirPath() + "/../PlugIns");
#endif
//![0]
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:///app.qml"));
view.show();
return app.exec();
}
//![0]

View File

@ -55,7 +55,7 @@
class TextBalloonPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri)
{

View File

@ -87,7 +87,7 @@ public:
class ImageProviderExtensionPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri)
{
@ -103,7 +103,4 @@ public:
};
#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface"
#include "imageprovider.moc"

View File

@ -102,7 +102,7 @@ private:
class ImageProviderExtensionPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
void registerTypes(const char *uri)
{
@ -117,7 +117,4 @@ public:
};
#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface"
#include "imageresponseprovider.moc"

View File

@ -74,12 +74,15 @@
/* COMPILER(MSVC) - Microsoft Visual C++ */
/* COMPILER(MSVC7_OR_LOWER) - Microsoft Visual C++ 2003 or lower*/
/* COMPILER(MSVC9_OR_LOWER) - Microsoft Visual C++ 2008 or lower*/
/* COMPILER(MSVC12_OR_LOWER) - Microsoft Visual C++ 2013 or lower*/
#if defined(_MSC_VER)
#define WTF_COMPILER_MSVC 1
#if _MSC_VER < 1400
#define WTF_COMPILER_MSVC7_OR_LOWER 1
#elif _MSC_VER < 1600
#define WTF_COMPILER_MSVC9_OR_LOWER 1
#elif _MSC_VER < 1800
#define WTF_COMPILER_MSVC12_OR_LOWER 1
#endif
/* Specific compiler features */

View File

@ -173,11 +173,15 @@ inline float log2f(float num)
inline long long abs(long long num) { return _abs64(num); }
#endif
#if COMPILER(MSVC12_OR_LOWER)
inline double nextafter(double x, double y) { return _nextafter(x, y); }
inline float nextafterf(float x, float y) { return x > y ? x - FLT_EPSILON : x + FLT_EPSILON; }
inline double copysign(double x, double y) { return _copysign(x, y); }
#endif // COMPILER(MSVC12_OR_LOWER)
// Work around a bug in Win, where atan2(+-infinity, +-infinity) yields NaN instead of specific values.
inline double wtf_atan2(double x, double y)
{
@ -211,6 +215,8 @@ inline double wtf_pow(double x, double y) { return y == 0 ? 1 : pow(x, y); }
#define fmod(x, y) wtf_fmod(x, y)
#define pow(x, y) wtf_pow(x, y)
#if COMPILER(MSVC12_OR_LOWER)
// MSVC's math functions do not bring lrint.
inline long int lrint(double flt)
{
@ -233,6 +239,7 @@ inline long int lrint(double flt)
return static_cast<long int>(intgr);
}
#endif // COMPILER(MSVC12_OR_LOWER)
#endif // COMPILER(MSVC)
inline double deg2rad(double d) { return d * piDouble / 180.0; }

View File

@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE
class QmlFolderListModelPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QmlFolderListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }

View File

@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE
class QtQuickLayoutsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QtQuickLayoutsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent)
{

View File

@ -754,7 +754,7 @@ static QObject *module_api_factory(QQmlEngine *engine, QJSEngine *scriptEngine)
class QQmlLocalStoragePlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QQmlLocalStoragePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent)

View File

@ -75,7 +75,7 @@ QT_BEGIN_NAMESPACE
class QtQmlModelsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QtQmlModelsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
void registerTypes(const char *uri) Q_DECL_OVERRIDE

View File

@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
class QtQuick2ParticlesPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QtQuick2ParticlesPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
void registerTypes(const char *uri) Q_DECL_OVERRIDE

View File

@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
class QtQuick2Plugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QtQuick2Plugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
void registerTypes(const char *uri) Q_DECL_OVERRIDE

View File

@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
class QmlSettingsPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QmlSettingsPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }

View File

@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
class QtQmlStateMachinePlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtQml.StateMachine/1.0")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QtQmlStateMachinePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }

View File

@ -147,7 +147,7 @@ QT_BEGIN_NAMESPACE
class QTestQmlModule : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QTestQmlModule(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }

View File

@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE
class QtQuick2WindowPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QtQuick2WindowPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
void registerTypes(const char *uri) Q_DECL_OVERRIDE

View File

@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE
class QmlXmlListModelPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
public:
QmlXmlListModelPlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }

View File

@ -291,8 +291,6 @@ QQuickOpenGLShaderEffectNode *QQuickCustomParticle::prepareNextFrame(QQuickOpenG
builder.appendSourceFile(QStringLiteral(":/particles/shaders/customparticle.vert"));
s.sourceCode[Key::VertexShader] = builder.source() + s.sourceCode[Key::VertexShader];
s.className = metaObject()->className();
material->setProgramSource(s);
material->attributes = m_common.attributes;
foreach (QQuickOpenGLShaderEffectNode* node, m_nodes)

View File

@ -322,6 +322,8 @@ public:
return m_startTime;
}
void reclaculateGroupId() const;
protected:
qreal m_particlesPerSecond;
int m_particleDuration;
@ -359,9 +361,6 @@ protected:
bool isEmitConnected();
private: // methods
void reclaculateGroupId() const;
private: // data
QString m_group;
mutable bool m_groupIdNeedRecalculation;

View File

@ -597,6 +597,13 @@ void QQuickParticleSystem::initGroups()
groupIds.clear();
nextFreeGroupId = 0;
for (auto e : qAsConst(m_emitters)) {
e->reclaculateGroupId();
}
foreach (QQuickParticlePainter *p, m_painters) {
p->recalculateGroupIds();
}
QQuickParticleGroupData *pd = new QQuickParticleGroupData(QString(), this); // Default group
Q_ASSERT(pd->index == 0);
Q_UNUSED(pd);

View File

@ -683,11 +683,13 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope
QQmlContext *context = qmlContext(object);
if (object && context) {
QString parentProperty = propertyName;
if (propertyName.indexOf(QLatin1Char('.')) != -1)
parentProperty = propertyName.left(propertyName.indexOf(QLatin1Char('.')));
QStringRef parentPropertyRef(&propertyName);
const int idx = parentPropertyRef.indexOf(QLatin1Char('.'));
if (idx != -1)
parentPropertyRef = parentPropertyRef.left(idx);
if (object->property(parentProperty.toLatin1()).isValid()) {
const QByteArray parentProperty = parentPropertyRef.toLatin1();
if (object->property(parentProperty).isValid()) {
QQmlProperty property(object, propertyName);
QQmlPropertyPrivate::removeBinding(property);
if (property.isResettable()) {
@ -700,7 +702,7 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope
// overwrite with default value
if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) {
if (QObject *emptyObject = objType->create()) {
if (emptyObject->property(parentProperty.toLatin1()).isValid()) {
if (emptyObject->property(parentProperty).isValid()) {
QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read();
if (defaultValue.isValid()) {
setBinding(objectId, propertyName, defaultValue, true);
@ -764,9 +766,14 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth
QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(object);
Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this
int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex);
QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(object)->handle());
QV4::Scope scope(v4);
int lineNumber = 0;
QV4::ScopedFunctionObject oldMethod(scope, vmeMetaObject->vmeMethod(prop->coreIndex));
if (oldMethod && oldMethod->d()->function) {
lineNumber = oldMethod->d()->function->compiledFunction->location.line;
}
QV4::ScopedValue v(scope, QQmlJavaScriptExpression::evalFunction(contextData, object, jsfunction, contextData->urlString(), lineNumber));
vmeMetaObject->setVmeMethod(prop->coreIndex, v);
return true;

View File

@ -704,7 +704,7 @@ bool NativeDebugger::reallyHitTheBreakPoint(const QV4::Function *function, int l
const BreakPoint &bp = m_service->m_breakHandler->m_breakPoints.at(i);
if (bp.lineNumber == lineNumber) {
const QString fileName = function->sourceFile();
const QString base = fileName.mid(fileName.lastIndexOf('/') + 1);
const QStringRef base = fileName.midRef(fileName.lastIndexOf('/') + 1);
if (bp.fileName.endsWith(base)) {
if (bp.condition.isEmpty() || checkCondition(bp.condition)) {
BreakPoint &mbp = m_service->m_breakHandler->m_breakPoints[i];

View File

@ -49,6 +49,7 @@
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonvalue.h>
#include <QtCore/qpointer.h>
#include <QtCore/qvector.h>
//#define TRACE_PROTOCOL(s) qDebug() << s
#define TRACE_PROTOCOL(s)
@ -182,24 +183,21 @@ QQmlNativeDebugConnector::QQmlNativeDebugConnector()
: m_blockingMode(false)
{
const QString args = commandLineArguments();
const QStringList lstjsDebugArguments = args.split(QLatin1Char(','));
const auto lstjsDebugArguments = args.splitRef(QLatin1Char(','));
QStringList services;
QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend();
QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin();
for (; argsIt != argsItEnd; ++argsIt) {
const QString strArgument = *argsIt;
for (const QStringRef &strArgument : lstjsDebugArguments) {
if (strArgument == QLatin1String("block")) {
m_blockingMode = true;
} else if (strArgument == QLatin1String("native")) {
// Ignore. This is used to signal that this connector
// should be loaded and that has already happened.
} else if (strArgument.startsWith(QLatin1String("services:"))) {
services.append(strArgument.mid(9));
services.append(strArgument.mid(9).toString());
} else if (!services.isEmpty()) {
services.append(strArgument);
services.append(strArgument.toString());
} else {
qWarning("QML Debugger: Invalid argument \"%s\" detected. Ignoring the same.",
qUtf8Printable(strArgument));
strArgument.toUtf8().constData());
}
}
setServices(services);

View File

@ -58,71 +58,81 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin
connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData()));
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
engine->profiler, SLOT(setTimer(QElapsedTimer)));
connect(engine->profiler, SIGNAL(dataReady(QVector<QQmlProfilerData>)),
this, SLOT(receiveData(QVector<QQmlProfilerData>)));
connect(engine->profiler,
SIGNAL(dataReady(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash)),
this,
SLOT(receiveData(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash)));
}
// convert to QByteArrays that can be sent to the debug client
// use of QDataStream can skew results
// (see tst_qqmldebugtrace::trace() benchmark)
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteArray> &messages)
static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d,
const QQmlProfiler::LocationHash &locations,
QList<QByteArray> &messages)
{
QQmlDebugPacket ds;
Q_ASSERT_X(((d->messageType | d->detailType) & (1 << 31)) == 0, Q_FUNC_INFO,
"You can use at most 31 message types and 31 detail types.");
for (uint decodedMessageType = 0; (d->messageType >> decodedMessageType) != 0;
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)
if ((d.messageType & (1 << decodedMessageType)) == 0)
continue;
for (uint decodedDetailType = 0; (d->detailType >> decodedDetailType) != 0;
++decodedDetailType) {
if ((d->detailType & (1 << decodedDetailType)) == 0)
continue;
//### using QDataStream is relatively expensive
ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType);
//### using QDataStream is relatively expensive
ds << d->time << decodedMessageType << decodedDetailType;
QQmlProfiler::Location l = locations.value(d.locationId);
switch (decodedMessageType) {
case QQmlProfilerDefinitions::RangeStart:
case QQmlProfilerDefinitions::RangeEnd:
break;
case QQmlProfilerDefinitions::RangeData:
ds << (d->detailString.isEmpty() ? d->detailUrl.toString() : d->detailString);
break;
case QQmlProfilerDefinitions::RangeLocation:
ds << (d->detailUrl.isEmpty() ? d->detailString : d->detailUrl.toString()) << d->x
<< d->y;
break;
default:
Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type.");
break;
}
messages.append(ds.squeezedData());
ds.clear();
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;
}
messages.append(ds.squeezedData());
ds.clear();
}
}
qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
while (next != data.length()) {
if (data[next].time > until || messages.length() > s_numMessagesPerBatch)
return data[next].time;
qQmlProfilerDataToByteArrays(&(data[next++]), messages);
const QQmlProfilerData &nextData = data.at(next);
if (nextData.time > until || messages.length() > s_numMessagesPerBatch)
return nextData.time;
qQmlProfilerDataToByteArrays(nextData, locations, messages);
++next;
}
next = 0;
data.clear();
locations.clear();
return -1;
}
void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data)
void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data,
const QQmlProfiler::LocationHash &new_locations)
{
if (data.isEmpty())
data = new_data;
else
data.append(new_data);
if (locations.isEmpty())
locations = new_locations;
else
locations.unite(new_locations);
service->dataReady(this);
}

View File

@ -63,10 +63,12 @@ public:
qint64 sendMessages(qint64 until, QList<QByteArray> &messages) Q_DECL_OVERRIDE;
public slots:
void receiveData(const QVector<QQmlProfilerData> &new_data);
void receiveData(const QVector<QQmlProfilerData> &new_data,
const QQmlProfiler::LocationHash &locations);
private:
QVector<QQmlProfilerData> data;
QQmlProfiler::LocationHash locations;
int next;
};

View File

@ -61,29 +61,35 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut
connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData()));
connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)),
engine->profiler, SLOT(setTimer(QElapsedTimer)));
connect(engine->profiler, SIGNAL(dataReady(QVector<QV4::Profiling::FunctionCallProperties>,
connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash,
QVector<QV4::Profiling::FunctionCallProperties>,
QVector<QV4::Profiling::MemoryAllocationProperties>)),
this, SLOT(receiveData(QVector<QV4::Profiling::FunctionCallProperties>,
this, SLOT(receiveData(QV4::Profiling::FunctionLocationHash,
QVector<QV4::Profiling::FunctionCallProperties>,
QVector<QV4::Profiling::MemoryAllocationProperties>)));
}
qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages,
QQmlDebugPacket &d)
{
while (m_memoryData.length() > m_memoryPos && m_memoryData[m_memoryPos].timestamp <= until) {
QV4::Profiling::MemoryAllocationProperties &props = m_memoryData[m_memoryPos];
// Make it const, so that we cannot accidentally detach it.
const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData = m_memoryData;
while (memoryData.length() > m_memoryPos && memoryData[m_memoryPos].timestamp <= until) {
const QV4::Profiling::MemoryAllocationProperties &props = memoryData[m_memoryPos];
d << props.timestamp << MemoryAllocation << props.type << props.size;
++m_memoryPos;
messages.append(d.squeezedData());
d.clear();
}
return m_memoryData.length() == m_memoryPos ? -1 : m_memoryData[m_memoryPos].timestamp;
return memoryData.length() == m_memoryPos ? -1 : memoryData[m_memoryPos].timestamp;
}
qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &messages,
qint64 callNext, QQmlDebugPacket &d)
{
if (callNext == -1) {
m_functionLocations.clear();
m_functionCallData.clear();
m_functionCallPos = 0;
}
@ -102,10 +108,15 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes
qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages)
{
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() &&
(m_functionCallPos == m_functionCallData.length() ||
m_stack.top() <= m_functionCallData[m_functionCallPos].start)) {
(m_functionCallPos == functionCallData.length() ||
m_stack.top() <= functionCallData[m_functionCallPos].start)) {
if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch)
return finalizeMessages(until, messages, m_stack.top(), d);
@ -114,39 +125,46 @@ qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &message
messages.append(d.squeezedData());
d.clear();
}
while (m_functionCallPos != m_functionCallData.length() &&
(m_stack.empty() || m_functionCallData[m_functionCallPos].start < m_stack.top())) {
while (m_functionCallPos != functionCallData.length() &&
(m_stack.empty() || functionCallData[m_functionCallPos].start < m_stack.top())) {
const QV4::Profiling::FunctionCallProperties &props =
m_functionCallData[m_functionCallPos];
functionCallData[m_functionCallPos];
if (props.start > until || messages.length() > s_numMessagesPerBatch)
return finalizeMessages(until, messages, props.start, d);
appendMemoryEvents(props.start, messages, d);
auto location = functionLocations.constFind(props.id);
Q_ASSERT(location != functionLocations.constEnd());
d << props.start << RangeStart << Javascript;
messages.push_back(d.squeezedData());
d.clear();
d << props.start << RangeLocation << Javascript << props.file << props.line
<< props.column;
d << props.start << RangeLocation << Javascript << location->file << location->line
<< location->column;
messages.push_back(d.squeezedData());
d.clear();
d << props.start << RangeData << Javascript << props.name;
d << props.start << RangeData << Javascript << location->name;
messages.push_back(d.squeezedData());
d.clear();
m_stack.push(props.end);
++m_functionCallPos;
}
if (m_stack.empty() && m_functionCallPos == m_functionCallData.length())
if (m_stack.empty() && m_functionCallPos == functionCallData.length())
return finalizeMessages(until, messages, -1, d);
}
}
void QV4ProfilerAdapter::receiveData(
const QV4::Profiling::FunctionLocationHash &locations,
const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData,
const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData)
{
// In rare cases it could be that another flush or stop event is processed while data from
// the previous one is still pending. In that case we just append the data.
if (m_functionLocations.isEmpty())
m_functionLocations = locations;
else
m_functionLocations.unite(locations);
if (m_functionCallData.isEmpty())
m_functionCallData = functionCallData;

View File

@ -74,7 +74,8 @@ signals:
void v4ProfilingEnabledWhileWaiting(quint64 v4Features);
public slots:
void receiveData(const QVector<QV4::Profiling::FunctionCallProperties> &,
void receiveData(const QV4::Profiling::FunctionLocationHash &,
const QVector<QV4::Profiling::FunctionCallProperties> &,
const QVector<QV4::Profiling::MemoryAllocationProperties> &);
private slots:
@ -82,6 +83,7 @@ private slots:
void forwardEnabledWhileWaiting(quint64 features);
private:
QV4::Profiling::FunctionLocationHash m_functionLocations;
QVector<QV4::Profiling::FunctionCallProperties> m_functionCallData;
QVector<QV4::Profiling::MemoryAllocationProperties> m_memoryData;
int m_functionCallPos;

View File

@ -53,6 +53,7 @@
#include <QtCore/QDir>
#include <QtCore/QPluginLoader>
#include <QtCore/QStringList>
#include <QtCore/QVector>
#include <QtCore/qwaitcondition.h>
QT_BEGIN_NAMESPACE
@ -345,40 +346,40 @@ void QQmlDebugServerImpl::parseArguments()
QString fileName;
QStringList services;
const QStringList lstjsDebugArguments = args.split(QLatin1Char(','));
QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend();
QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin();
for (; argsIt != argsItEnd; ++argsIt) {
const QString strArgument = *argsIt;
const auto lstjsDebugArguments = args.splitRef(QLatin1Char(','));
for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) {
const QStringRef &strArgument = *argsIt;
if (strArgument.startsWith(QLatin1String("port:"))) {
portFrom = strArgument.midRef(5).toInt(&ok);
portFrom = strArgument.mid(5).toInt(&ok);
portTo = portFrom;
QStringList::const_iterator argsNext = argsIt + 1;
const auto argsNext = argsIt + 1;
if (argsNext == argsItEnd)
break;
const QString nextArgument = *argsNext;
if (ok) {
const QString nextArgument = argsNext->toString();
// Don't use QStringLiteral here. QRegExp has a global cache and will save an implicitly
// shared copy of the passed string. That copy isn't properly detached when the library
// is unloaded if the original string lives in the library's .rodata
if (ok && nextArgument.contains(QRegExp(QLatin1String("^\\s*\\d+\\s*$")))) {
portTo = nextArgument.toInt(&ok);
++argsIt;
// Don't use QStringLiteral here. QRegExp has a global cache and will save an implicitly
// shared copy of the passed string. That copy isn't properly detached when the library
// is unloaded if the original string lives in the library's .rodata
if (nextArgument.contains(QRegExp(QLatin1String("^\\s*\\d+\\s*$")))) {
portTo = nextArgument.toInt(&ok);
++argsIt;
}
}
} else if (strArgument.startsWith(QLatin1String("host:"))) {
hostAddress = strArgument.mid(5);
hostAddress = strArgument.mid(5).toString();
} else if (strArgument == QLatin1String("block")) {
block = true;
} else if (strArgument.startsWith(QLatin1String("file:"))) {
fileName = strArgument.mid(5);
fileName = strArgument.mid(5).toString();
ok = !fileName.isEmpty();
} else if (strArgument.startsWith(QLatin1String("services:"))) {
services.append(strArgument.mid(9));
services.append(strArgument.mid(9).toString());
} else if (!services.isEmpty()) {
services.append(strArgument);
services.append(strArgument.toString());
} else {
const QString message = tr("QML Debugger: Invalid argument \"%1\" detected."
" Ignoring the same.").arg(strArgument);
" Ignoring the same.").arg(strArgument.toString());
qWarning("%s", qPrintable(message));
}
}
@ -423,7 +424,7 @@ void QQmlDebugServerImpl::parseArguments()
//: Please preserve the line breaks and formatting
<< tr("Sends qDebug() and similar messages over the QML debug\n"
"\t\t connection. QtCreator uses this for showing debug\n"
"\t\t messages in the JavaScript console.") << '\n'
"\t\t messages in the debugger console.") << '\n'
<< tr("Other services offered by qmltooling plugins that implement "
"QQmlDebugServiceFactory and which can be found in the standard plugin "
"paths will also be available and can be specified. If no \"services\" "

View File

@ -72,7 +72,7 @@ protected:
{
QMutexLocker lock(&m_configMutex);
m_waitingForConfiguration = false;
foreach (QJSEngine *engine, m_waitingEngines)
for (QJSEngine *engine : qAsConst(m_waitingEngines))
emit Base::attachedToEngine(engine);
m_waitingEngines.clear();
}

View File

@ -80,8 +80,10 @@ void Object::init(QQmlJS::MemoryPool *pool, int typeNameIndex, int id, const QQm
location.column = loc.startColumn;
idIndex = id;
indexOfDefaultProperty = -1;
indexOfDefaultPropertyOrAlias = -1;
defaultPropertyIsAlias = false;
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> >();
@ -145,15 +147,42 @@ QString Object::appendProperty(Property *prop, const QString &propertyName, bool
const int index = target->properties->append(prop);
if (isDefaultProperty) {
if (target->indexOfDefaultProperty != -1) {
if (target->indexOfDefaultPropertyOrAlias != -1) {
*errorLocation = defaultToken;
return tr("Duplicate default property");
}
target->indexOfDefaultProperty = index;
target->indexOfDefaultPropertyOrAlias = index;
}
return QString(); // no error
}
QString Object::appendAlias(Alias *alias, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation)
{
Object *target = declarationsOverride;
if (!target)
target = this;
for (Alias *p = target->aliases->first; p; p = p->next)
if (p->nameIndex == alias->nameIndex)
return tr("Duplicate alias name");
if (aliasName.constData()->isUpper())
return tr("Alias names cannot begin with an upper case letter");
const int index = target->aliases->append(alias);
if (isDefaultProperty) {
if (target->indexOfDefaultPropertyOrAlias != -1) {
*errorLocation = defaultToken;
return tr("Duplicate default property");
}
target->indexOfDefaultPropertyOrAlias = index;
target->defaultPropertyIsAlias = true;
}
return QString(); // no error
}
void Object::appendFunction(QmlIR::Function *f)
{
Object *target = declarationsOverride;
@ -190,7 +219,7 @@ Binding *Object::findBinding(quint32 nameIndex) const
void Object::insertSorted(Binding *b)
{
Binding *insertionPoint = bindings->findSortedInsertionPoint<QV4::CompiledData::Location, QV4::CompiledData::Binding, &QV4::CompiledData::Binding::valueLocation>(b);
Binding *insertionPoint = bindings->findSortedInsertionPoint<quint32, Binding, &Binding::offset>(b);
bindings->insertAfter(insertionPoint, b);
}
@ -249,8 +278,8 @@ void Document::collectTypeReferences()
void Document::removeScriptPragmas(QString &script)
{
const QString pragma(QLatin1String("pragma"));
const QString library(QLatin1String("library"));
const QLatin1String pragma("pragma");
const QLatin1String library("library");
QQmlJS::Lexer l(0);
l.setCode(script, 0);
@ -268,7 +297,7 @@ void Document::removeScriptPragmas(QString &script)
if (token != QQmlJSGrammar::T_PRAGMA ||
l.tokenStartLine() != startLine ||
script.mid(l.tokenOffset(), l.tokenLength()) != pragma)
script.midRef(l.tokenOffset(), l.tokenLength()) != pragma)
return;
token = l.lex();
@ -277,7 +306,7 @@ void Document::removeScriptPragmas(QString &script)
l.tokenStartLine() != startLine)
return;
QString pragmaValue = script.mid(l.tokenOffset(), l.tokenLength());
const QStringRef pragmaValue = script.midRef(l.tokenOffset(), l.tokenLength());
int endOffset = l.tokenLength() + l.tokenOffset();
token = l.lex();
@ -806,130 +835,86 @@ bool IRBuilder::visit(QQmlJS::AST::UiPublicMember *node)
}
} else {
const QStringRef &memberType = node->memberType;
const QStringRef &name = node->name;
bool typeFound = false;
QV4::CompiledData::Property::Type type;
if (memberType == QLatin1String("alias")) {
type = QV4::CompiledData::Property::Alias;
typeFound = true;
}
return appendAlias(node);
} else {
const QStringRef &name = node->name;
for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
const TypeNameToType *t = propTypeNameToTypes + ii;
if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
type = t->type;
typeFound = true;
bool typeFound = false;
QV4::CompiledData::Property::Type type;
for (int ii = 0; !typeFound && ii < propTypeNameToTypesCount; ++ii) {
const TypeNameToType *t = propTypeNameToTypes + ii;
if (memberType == QLatin1String(t->name, static_cast<int>(t->nameLength))) {
type = t->type;
typeFound = true;
}
}
}
if (!typeFound && memberType.at(0).isUpper()) {
const QStringRef &typeModifier = node->typeModifier;
if (!typeFound && memberType.at(0).isUpper()) {
const QStringRef &typeModifier = node->typeModifier;
if (typeModifier.isEmpty()) {
type = QV4::CompiledData::Property::Custom;
} else if (typeModifier == QLatin1String("list")) {
type = QV4::CompiledData::Property::CustomList;
} else {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
if (typeModifier.isEmpty()) {
type = QV4::CompiledData::Property::Custom;
} else if (typeModifier == QLatin1String("list")) {
type = QV4::CompiledData::Property::CustomList;
} else {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Invalid property type modifier"));
return false;
}
typeFound = true;
} else if (!node->typeModifier.isNull()) {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
return false;
}
typeFound = true;
} else if (!node->typeModifier.isNull()) {
recordError(node->typeModifierToken, QCoreApplication::translate("QQmlParser","Unexpected property type modifier"));
return false;
}
if (!typeFound) {
recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type"));
return false;
}
Property *property = New<Property>();
property->flags = 0;
if (node->isReadonlyMember)
property->flags |= QV4::CompiledData::Property::IsReadOnly;
property->type = type;
if (type >= QV4::CompiledData::Property::Custom)
property->customTypeNameIndex = registerString(memberType.toString());
else
property->customTypeNameIndex = emptyStringIndex;
const QString propName = name.toString();
property->nameIndex = registerString(propName);
QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
property->location.line = loc.startLine;
property->location.column = loc.startColumn;
property->aliasPropertyValueIndex = emptyStringIndex;
if (type == QV4::CompiledData::Property::Alias) {
if (!node->statement && !node->binding)
COMPILE_EXCEPTION(loc, tr("No property alias location"));
QQmlJS::AST::SourceLocation rhsLoc;
if (node->binding)
rhsLoc = node->binding->firstSourceLocation();
else if (node->statement)
rhsLoc = node->statement->firstSourceLocation();
else
rhsLoc = node->semicolonToken;
property->aliasLocation.line = rhsLoc.startLine;
property->aliasLocation.column = rhsLoc.startColumn;
QStringList alias;
if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) {
alias = astNodeToStringList(stmt->expression);
if (alias.isEmpty()) {
if (isStatementNodeScript(node->statement)) {
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
} else {
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location"));
}
}
} else {
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
if (!typeFound) {
recordError(node->typeToken, QCoreApplication::translate("QQmlParser","Expected property type"));
return false;
}
if (alias.count() < 1 || alias.count() > 3)
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
Property *property = New<Property>();
property->flags = 0;
if (node->isReadonlyMember)
property->flags |= QV4::CompiledData::Property::IsReadOnly;
property->type = type;
if (type >= QV4::CompiledData::Property::Custom)
property->customTypeNameIndex = registerString(memberType.toString());
else
property->customTypeNameIndex = emptyStringIndex;
property->aliasIdValueIndex = registerString(alias.first());
const QString propName = name.toString();
property->nameIndex = registerString(propName);
QString propertyValue = alias.value(1);
if (alias.count() == 3) {
propertyValue += QLatin1Char('.');
propertyValue += alias.at(2);
}
property->aliasPropertyValueIndex = registerString(propertyValue);
QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
property->location.line = loc.startLine;
property->location.column = loc.startColumn;
QQmlJS::AST::SourceLocation errorLocation;
QString error;
if (illegalNames.contains(propName))
error = tr("Illegal property name");
else
error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
if (!error.isEmpty()) {
if (errorLocation.startLine == 0)
errorLocation = node->identifierToken;
recordError(errorLocation, error);
return false;
}
qSwap(_propertyDeclaration, property);
if (node->binding) {
// process QML-like initializers (e.g. property Object o: Object {})
QQmlJS::AST::Node::accept(node->binding, this);
} else if (node->statement) {
appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
}
qSwap(_propertyDeclaration, property);
}
QQmlJS::AST::SourceLocation errorLocation;
QString error;
if (illegalNames.contains(propName))
error = tr("Illegal property name");
else
error = _object->appendProperty(property, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
if (!error.isEmpty()) {
if (errorLocation.startLine == 0)
errorLocation = node->identifierToken;
recordError(errorLocation, error);
return false;
}
qSwap(_propertyDeclaration, property);
if (node->binding) {
// process QML-like initializers (e.g. property Object o: Object {})
QQmlJS::AST::Node::accept(node->binding, this);
} else if (node->statement && type != QV4::CompiledData::Property::Alias) {
appendBinding(node->identifierToken, node->identifierToken, _propertyDeclaration->nameIndex, node->statement);
}
qSwap(_propertyDeclaration, property);
}
return false;
@ -1084,6 +1069,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
{
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
binding->flags = 0;
@ -1103,6 +1089,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
Binding *binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = nameLocation.offset;
binding->location.line = nameLocation.startLine;
binding->location.column = nameLocation.startColumn;
@ -1132,6 +1119,79 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo
}
}
bool IRBuilder::appendAlias(QQmlJS::AST::UiPublicMember *node)
{
Alias *alias = New<Alias>();
alias->flags = 0;
if (node->isReadonlyMember)
alias->flags |= QV4::CompiledData::Alias::IsReadOnly;
const QString propName = node->name.toString();
alias->nameIndex = registerString(propName);
QQmlJS::AST::SourceLocation loc = node->firstSourceLocation();
alias->location.line = loc.startLine;
alias->location.column = loc.startColumn;
alias->propertyNameIndex = emptyStringIndex;
if (!node->statement && !node->binding)
COMPILE_EXCEPTION(loc, tr("No property alias location"));
QQmlJS::AST::SourceLocation rhsLoc;
if (node->binding)
rhsLoc = node->binding->firstSourceLocation();
else if (node->statement)
rhsLoc = node->statement->firstSourceLocation();
else
rhsLoc = node->semicolonToken;
alias->referenceLocation.line = rhsLoc.startLine;
alias->referenceLocation.column = rhsLoc.startColumn;
QStringList aliasReference;
if (QQmlJS::AST::ExpressionStatement *stmt = QQmlJS::AST::cast<QQmlJS::AST::ExpressionStatement*>(node->statement)) {
aliasReference = astNodeToStringList(stmt->expression);
if (aliasReference.isEmpty()) {
if (isStatementNodeScript(node->statement)) {
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
} else {
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias location"));
}
}
} else {
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
}
if (aliasReference.count() < 1 || aliasReference.count() > 3)
COMPILE_EXCEPTION(rhsLoc, tr("Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property>"));
alias->idIndex = registerString(aliasReference.first());
QString propertyValue = aliasReference.value(1);
if (aliasReference.count() == 3)
propertyValue += QLatin1Char('.') + aliasReference.at(2);
alias->propertyNameIndex = registerString(propertyValue);
QQmlJS::AST::SourceLocation errorLocation;
QString error;
if (illegalNames.contains(propName))
error = tr("Illegal property name");
else
error = _object->appendAlias(alias, propName, node->isDefaultMember, node->defaultToken, &errorLocation);
if (!error.isEmpty()) {
if (errorLocation.startLine == 0)
errorLocation = node->identifierToken;
recordError(errorLocation, error);
return false;
}
return false;
}
Object *IRBuilder::bindingsTarget() const
{
if (_propertyDeclaration && _object->declarationsOverride)
@ -1201,8 +1261,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
if (import->qualifierIndex != emptyStringIndex
&& stringAt(import->qualifierIndex) == currentName) {
qualifiedIdElement = qualifiedIdElement->next;
currentName += QLatin1Char('.');
currentName += qualifiedIdElement->name;
currentName += QLatin1Char('.') + qualifiedIdElement->name;
if (!qualifiedIdElement->name.unicode()->isUpper())
COMPILE_EXCEPTION(qualifiedIdElement->firstSourceLocation(), tr("Expected type name"));
@ -1228,6 +1287,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O
if (!binding) {
binding = New<Binding>();
binding->propertyNameIndex = propertyNameIndex;
binding->offset = qualifiedIdElement->identifierToken.offset;
binding->location.line = qualifiedIdElement->identifierToken.startLine;
binding->location.column = qualifiedIdElement->identifierToken.startColumn;
binding->valueLocation.line = qualifiedIdElement->next->identifierToken.startLine;
@ -1313,7 +1373,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
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->signalCount(), o->bindingCount());
objectsSize += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount());
int signalTableSize = 0;
for (const Signal *s = o->firstSignal(); s; s = s->next)
@ -1358,7 +1418,8 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
QV4::CompiledData::Object *objectToWrite = reinterpret_cast<QV4::CompiledData::Object*>(objectPtr);
objectToWrite->inheritedTypeNameIndex = o->inheritedTypeNameIndex;
objectToWrite->indexOfDefaultProperty = o->indexOfDefaultProperty;
objectToWrite->indexOfDefaultPropertyOrAlias = o->indexOfDefaultPropertyOrAlias;
objectToWrite->defaultPropertyIsAlias = o->defaultPropertyIsAlias;
objectToWrite->idIndex = o->idIndex;
objectToWrite->location = o->location;
objectToWrite->locationOfIdProperty = o->locationOfIdProperty;
@ -1373,6 +1434,10 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
objectToWrite->offsetToProperties = nextOffset;
nextOffset += objectToWrite->nProperties * sizeof(QV4::CompiledData::Property);
objectToWrite->nAliases = o->aliasCount();
objectToWrite->offsetToAliases = nextOffset;
nextOffset += objectToWrite->nAliases * sizeof(QV4::CompiledData::Alias);
objectToWrite->nSignals = o->signalCount();
objectToWrite->offsetToSignals = nextOffset;
nextOffset += objectToWrite->nSignals * sizeof(quint32);
@ -1392,6 +1457,13 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
propertiesPtr += sizeof(QV4::CompiledData::Property);
}
char *aliasesPtr = objectPtr + objectToWrite->offsetToAliases;
for (const Alias *a = o->firstAlias(); a; a = a->next) {
QV4::CompiledData::Alias *aliasToWrite = reinterpret_cast<QV4::CompiledData::Alias*>(aliasesPtr);
*aliasToWrite = *a;
aliasesPtr += sizeof(QV4::CompiledData::Alias);
}
char *bindingPtr = objectPtr + objectToWrite->offsetToBindings;
bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isValueBindingNoAlias);
bindingPtr = writeBindings(bindingPtr, o, &QV4::CompiledData::Binding::isSignalHandler);
@ -1420,7 +1492,7 @@ QV4::CompiledData::Unit *QmlUnitGenerator::generate(Document &output)
signalPtr += size;
}
objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->signalCount(), o->bindingCount());
objectPtr += QV4::CompiledData::Object::calculateSizeExcludingSignals(o->functionCount(), o->propertyCount(), o->aliasCount(), o->signalCount(), o->bindingCount());
objectPtr += signalTableSize;
}

View File

@ -113,7 +113,7 @@ struct PoolList
T *insertPos = 0;
for (T *it = first; it; it = it->next) {
if (!(it->*sortMember < item->*sortMember))
if (!(it->*sortMember <= item->*sortMember))
break;
insertPos = it;
}
@ -227,10 +227,19 @@ struct Property : public QV4::CompiledData::Property
struct Binding : public QV4::CompiledData::Binding
{
// The offset in the source file where the binding appeared. This is used for sorting to ensure
// that assignments to list properties are done in the correct order. We use the offset here instead
// of Binding::location as the latter has limited precision.
quint32 offset;
// Binding's compiledScriptIndex is index in object's functionsAndExpressions
Binding *next;
};
struct Alias : public QV4::CompiledData::Alias
{
Alias *next;
};
struct Function
{
QQmlJS::AST::FunctionDeclaration *functionDeclaration;
@ -266,13 +275,16 @@ struct Q_QML_PRIVATE_EXPORT Object
public:
quint32 inheritedTypeNameIndex;
quint32 idIndex;
int indexOfDefaultProperty;
int indexOfDefaultPropertyOrAlias : 31;
int defaultPropertyIsAlias : 1;
QV4::CompiledData::Location location;
QV4::CompiledData::Location locationOfIdProperty;
const Property *firstProperty() const { return properties->first; }
int propertyCount() const { return properties->count; }
Alias *firstAlias() const { return aliases->first; }
int aliasCount() const { return aliases->count; }
const Signal *firstSignal() const { return qmlSignals->first; }
int signalCount() const { return qmlSignals->count; }
Binding *firstBinding() const { return bindings->first; }
@ -290,6 +302,7 @@ public:
QString appendSignal(Signal *signal);
QString appendProperty(Property *prop, const QString &propertyName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
QString appendAlias(Alias *prop, const QString &aliasName, bool isDefaultProperty, const QQmlJS::AST::SourceLocation &defaultToken, QQmlJS::AST::SourceLocation *errorLocation);
void appendFunction(QmlIR::Function *f);
QString appendBinding(Binding *b, bool isListBinding);
@ -305,6 +318,7 @@ private:
friend struct IRLoader;
PoolList<Property> *properties;
PoolList<Alias> *aliases;
PoolList<Signal> *qmlSignals;
PoolList<Binding> *bindings;
PoolList<Function> *functions;
@ -410,6 +424,8 @@ public:
void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, QQmlJS::AST::Statement *value);
void appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem = false, bool isOnAssignment = false);
bool appendAlias(QQmlJS::AST::UiPublicMember *node);
Object *bindingsTarget() const;
bool setId(const QQmlJS::AST::SourceLocation &idLocation, QQmlJS::AST::Statement *value);

View File

@ -179,16 +179,16 @@ bool QQmlTypeCompiler::compile()
for (int scriptIndex = 0; scriptIndex < scripts.count(); ++scriptIndex) {
const QQmlTypeData::ScriptReference &script = scripts.at(scriptIndex);
QString qualifier = script.qualifier;
QStringRef qualifier(&script.qualifier);
QString enclosingNamespace;
const int lastDotIndex = qualifier.lastIndexOf(QLatin1Char('.'));
if (lastDotIndex != -1) {
enclosingNamespace = qualifier.left(lastDotIndex);
enclosingNamespace = qualifier.left(lastDotIndex).toString();
qualifier = qualifier.mid(lastDotIndex+1);
}
compiledData->importCache->add(qualifier, scriptIndex, enclosingNamespace);
compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlScriptData *scriptData = script.script->scriptData();
scriptData->addref();
compiledData->scripts << scriptData;
@ -480,7 +480,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
}
}
bool needVMEMetaObject = obj->propertyCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
bool needVMEMetaObject = obj->propertyCount() != 0 || obj->aliasCount() != 0 || obj->signalCount() != 0 || obj->functionCount() != 0;
if (!needVMEMetaObject) {
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type == QV4::CompiledData::Binding::Type_Object && (binding->flags & QV4::CompiledData::Binding::IsOnAssignment)) {
@ -507,7 +507,7 @@ bool QQmlPropertyCacheCreator::buildMetaObjectRecursively(int objectIndex, int r
Q_ASSERT(typeRef);
if (typeRef->isFullyDynamicType) {
if (obj->propertyCount() > 0) {
if (obj->propertyCount() > 0 || obj->aliasCount() > 0) {
recordError(obj->location, tr("Fully dynamic types cannot declare new properties."));
return false;
}
@ -586,9 +586,9 @@ bool QQmlPropertyCacheCreator::ensureMetaObject(int objectIndex)
bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Object *obj, QQmlPropertyCache *baseTypeCache)
{
QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount(),
obj->functionCount() + obj->propertyCount() + obj->signalCount(),
obj->signalCount() + obj->propertyCount());
QQmlPropertyCache *cache = baseTypeCache->copyAndReserve(obj->propertyCount() + obj->aliasCount(),
obj->functionCount() + obj->propertyCount() + obj->aliasCount() + obj->signalCount(),
obj->signalCount() + obj->propertyCount() + obj->aliasCount());
propertyCaches[objectIndex] = cache;
struct TypeData {
@ -624,7 +624,7 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
QString path = compiler->url().path();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
if (lastSlash > -1) {
QString nameBase = path.mid(lastSlash + 1, path.length()-lastSlash-5);
const QStringRef nameBase = path.midRef(lastSlash + 1, path.length() - lastSlash - 5);
if (!nameBase.isEmpty() && nameBase.at(0).isUpper())
newClassName = nameBase.toUtf8() + "_QMLTYPE_" +
QByteArray::number(classIndexCounter.fetchAndAddRelaxed(1));
@ -638,30 +638,30 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
cache->_dynamicClassName = newClassName;
int aliasCount = 0;
int varPropCount = 0;
QmlIR::PropertyResolver resolver(baseTypeCache);
for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
if (p->type == QV4::CompiledData::Property::Alias)
aliasCount++;
else if (p->type == QV4::CompiledData::Property::Var)
if (p->type == QV4::CompiledData::Property::Var)
varPropCount++;
// No point doing this for both the alias and non alias cases
bool notInRevision = false;
QQmlPropertyData *d = resolver.property(stringAt(p->nameIndex), &notInRevision);
if (d && d->isFinal())
COMPILE_EXCEPTION(p, tr("Cannot override FINAL property"));
}
for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) {
bool notInRevision = false;
QQmlPropertyData *d = resolver.property(stringAt(a->nameIndex), &notInRevision);
if (d && d->isFinal())
COMPILE_EXCEPTION(a, tr("Cannot override FINAL property"));
}
typedef QQmlVMEMetaData VMD;
QByteArray &dynamicData = vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData)
+ obj->propertyCount() * sizeof(VMD::PropertyData)
+ obj->functionCount() * sizeof(VMD::MethodData)
+ aliasCount * sizeof(VMD::AliasData), 0);
vmeMetaObjects[objectIndex] = QByteArray(sizeof(QQmlVMEMetaData) + obj->aliasCount() * sizeof(VMD::AliasData), 0);
int effectivePropertyIndex = cache->propertyIndexCacheStart;
int effectiveMethodIndex = cache->methodIndexCacheStart;
@ -689,25 +689,25 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
}
}
// First set up notify signals for properties - first normal, then var, then alias
enum { NSS_Normal = 0, NSS_Alias = 1 };
for (int ii = NSS_Normal; ii <= NSS_Alias; ++ii) { // 0 == normal, 1 == var, 2 == alias
// Set up notify signals for properties - first normal, then alias
for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
QQmlPropertyData::IsVMESignal;
if (ii == NSS_Alias && aliasCount == 0) continue;
QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
seenSignals.insert(changedSigName);
for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next) {
if ((ii == NSS_Normal && p->type == QV4::CompiledData::Property::Alias) ||
(ii == NSS_Alias && p->type != QV4::CompiledData::Property::Alias))
continue;
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
QQmlPropertyData::IsVMESignal;
for (const QmlIR::Alias *a = obj->firstAlias(); a; a = a->next) {
quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
QQmlPropertyData::IsVMESignal;
QString changedSigName = stringAt(p->nameIndex) + QLatin1String("Changed");
seenSignals.insert(changedSigName);
QString changedSigName = stringAt(a->nameIndex) + QLatin1String("Changed");
seenSignals.insert(changedSigName);
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
cache->appendSignal(changedSigName, flags, effectiveMethodIndex++);
}
// Dynamic signals
@ -752,8 +752,6 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
}
}
((QQmlVMEMetaData *)dynamicData.data())->signalCount++;
quint32 flags = QQmlPropertyData::IsSignal | QQmlPropertyData::IsFunction |
QQmlPropertyData::IsVMESignal;
if (paramCount)
@ -795,25 +793,18 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
}
// Dynamic properties (except var and aliases)
// Dynamic properties
int effectiveSignalIndex = cache->signalHandlerIndexCacheStart;
int propertyIdx = 0;
for (const QmlIR::Property *p = obj->firstProperty(); p; p = p->next, ++propertyIdx) {
if (p->type == QV4::CompiledData::Property::Alias)
continue;
int propertyType = 0;
int vmePropertyType = 0;
quint32 propertyFlags = 0;
if (p->type == QV4::CompiledData::Property::Var) {
propertyType = QMetaType::QVariant;
vmePropertyType = QQmlVMEMetaData::VarPropertyType;
propertyFlags = QQmlPropertyData::IsVarProperty;
} else if (p->type < builtinTypeCount) {
propertyType = builtinTypes[p->type].metaType;
vmePropertyType = propertyType;
if (p->type == QV4::CompiledData::Property::Variant)
propertyFlags |= QQmlPropertyData::IsQVariant;
@ -836,20 +827,16 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
if (p->type == QV4::CompiledData::Property::Custom) {
propertyType = data->metaTypeId;
vmePropertyType = QMetaType::QObjectStar;
} else {
propertyType = data->listMetaTypeId;
vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
}
tdata->release();
} else {
if (p->type == QV4::CompiledData::Property::Custom) {
propertyType = qmltype->typeId();
vmePropertyType = QMetaType::QObjectStar;
} else {
propertyType = qmltype->qListTypeId();
vmePropertyType = qMetaTypeId<QQmlListProperty<QObject> >();
}
}
@ -864,38 +851,12 @@ bool QQmlPropertyCacheCreator::createMetaObject(int objectIndex, const QmlIR::Ob
QString propertyName = stringAt(p->nameIndex);
if (propertyIdx == obj->indexOfDefaultProperty) cache->_defaultPropertyName = propertyName;
if (!obj->defaultPropertyIsAlias && propertyIdx == obj->indexOfDefaultPropertyOrAlias)
cache->_defaultPropertyName = propertyName;
cache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
propertyType, effectiveSignalIndex);
effectiveSignalIndex++;
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
(vmd->propertyData() + vmd->propertyCount)->propertyType = vmePropertyType;
vmd->propertyCount++;
}
// Alias property count. Actual data is setup in buildDynamicMetaAliases
((QQmlVMEMetaData *)dynamicData.data())->aliasCount = aliasCount;
// Dynamic slot data - comes after the property data
for (const QmlIR::Function *s = obj->firstFunction(); s; s = s->next) {
QQmlJS::AST::FunctionDeclaration *astFunction = s->functionDeclaration;
int formalsCount = 0;
QQmlJS::AST::FormalParameterList *param = astFunction->formals;
while (param) {
formalsCount++;
param = param->next;
}
VMD::MethodData methodData = { /* runtimeFunctionIndex*/ 0, // ###
formalsCount,
/* s->location.start.line */0 }; // ###
VMD *vmd = (QQmlVMEMetaData *)dynamicData.data();
VMD::MethodData &md = *(vmd->methodData() + vmd->methodCount);
vmd->methodCount++;
md = methodData;
}
return true;
@ -1163,10 +1124,10 @@ struct StaticQtMetaObject : public QObject
{ return &staticQtMetaObject; }
};
bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject)
bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject)
{
if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) {
COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName));
COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName.toString()));
}
binding->type = QV4::CompiledData::Binding::Type_Number;
binding->value.d = (double)enumValue;
@ -1197,7 +1158,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj,
QHashedStringRef typeName(string.constData(), dot);
const bool isQtObject = (typeName == QLatin1String("Qt"));
QString enumValue = string.mid(dot+1);
const QStringRef enumValue = string.midRef(dot + 1);
if (isIntProp) {
// Allow enum assignment to ints.
@ -1318,7 +1279,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases()
const QmlIR::Object *obj = qmlObjects.at(i);
QmlIR::PropertyResolver resolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (!binding->isValueBinding())
@ -1350,7 +1311,7 @@ void QQmlScriptStringScanner::scan()
const QmlIR::Object *obj = qmlObjects.at(i);
QmlIR::PropertyResolver resolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Script)
@ -1390,7 +1351,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI
{
QmlIR::PropertyResolver propertyResolver(propertyCache);
QQmlPropertyData *defaultProperty = obj->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty();
for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object)
@ -1497,7 +1458,7 @@ bool QQmlComponentAndAliasResolver::resolve()
if (obj->functionCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new functions."));
if (obj->propertyCount() > 0)
if (obj->propertyCount() > 0 || obj->aliasCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new properties."));
if (obj->signalCount() > 0)
COMPILE_EXCEPTION(obj, tr("Component objects cannot declare new signals."));
@ -1568,12 +1529,8 @@ bool QQmlComponentAndAliasResolver::collectIdsAndAliases(int objectIndex)
_objectIndexToIdInScope->insert(objectIndex, _objectIndexToIdInScope->count());
}
for (const QmlIR::Property *property = obj->firstProperty(); property; property = property->next) {
if (property->type == QV4::CompiledData::Property::Alias) {
_objectsWithAliases.append(objectIndex);
break;
}
}
if (obj->aliasCount() > 0)
_objectsWithAliases.append(objectIndex);
for (const QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) {
if (binding->type != QV4::CompiledData::Binding::Type_Object
@ -1604,21 +1561,20 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
int effectivePropertyIndex = propertyCache->propertyIndexCacheStart + propertyCache->propertyIndexCache.count();
int effectiveAliasIndex = 0;
const QmlIR::Property *p = obj->firstProperty();
for (int propertyIndex = 0; propertyIndex < obj->propertyCount(); ++propertyIndex, p = p->next) {
if (p->type != QV4::CompiledData::Property::Alias)
continue;
const int idIndex = p->aliasIdValueIndex;
int aliasIndex = 0;
for (QmlIR::Alias *alias = obj->firstAlias(); alias; alias = alias->next, ++aliasIndex) {
const int idIndex = alias->idIndex;
const int targetObjectIndex = _idToObjectIndex.value(idIndex, -1);
if (targetObjectIndex == -1) {
recordError(p->aliasLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
recordError(alias->referenceLocation, tr("Invalid alias reference. Unable to find id \"%1\"").arg(stringAt(idIndex)));
return false;
}
const int targetId = _objectIndexToIdInScope->value(targetObjectIndex, -1);
Q_ASSERT(targetId != -1);
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 QString aliasPropertyValue = stringAt(p->aliasPropertyValueIndex);
const QString aliasPropertyValue = stringAt(alias->propertyNameIndex);
QStringRef property;
QStringRef subProperty;
@ -1631,9 +1587,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
property = QStringRef(&aliasPropertyValue, 0, aliasPropertyValue.length());
int propIdx = -1;
int propType = 0;
int notifySignal = -1;
int flags = 0;
int type = 0;
bool writable = false;
bool resettable = false;
@ -1650,7 +1604,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
else
type = typeRef->component->metaTypeId;
flags |= QML_ALIAS_FLAG_PTR;
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
propertyFlags |= QQmlPropertyData::IsQObjectDerived;
} else {
QQmlPropertyCache *targetCache = propertyCaches.at(targetObjectIndex);
@ -1659,7 +1613,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
QQmlPropertyData *targetProperty = resolver.property(property.toString());
if (!targetProperty || targetProperty->coreIndex > 0x0000FFFF) {
recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(property.toString()));
recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(property.toString()));
return false;
}
@ -1673,16 +1627,14 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
if (!subProperty.isEmpty()) {
const QMetaObject *valueTypeMetaObject = QQmlValueTypeFactory::metaObjectForMetaType(type);
if (!valueTypeMetaObject) {
recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
return false;
}
propType = type;
int valueTypeIndex =
valueTypeMetaObject->indexOfProperty(subProperty.toString().toUtf8().constData());
if (valueTypeIndex == -1) {
recordError(p->aliasLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
recordError(alias->referenceLocation, tr("Invalid alias target location: %1").arg(subProperty.toString()));
return false;
}
Q_ASSERT(valueTypeIndex <= 0x0000FFFF);
@ -1704,12 +1656,13 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
propertyFlags |= QQmlPropertyData::IsQVariant;
if (targetProperty->isQObject())
flags |= QML_ALIAS_FLAG_PTR;
alias->flags |= QV4::CompiledData::Alias::AliasPointsToPointerObject;
}
}
}
QQmlVMEMetaData::AliasData aliasData = { targetId, propIdx, propType, flags, notifySignal };
alias->encodedMetaPropertyIndex = propIdx;
QQmlVMEMetaData::AliasData aliasData = { notifySignal };
typedef QQmlVMEMetaData VMD;
QByteArray &dynamicData = (*vmeMetaObjectData)[objectIndex];
@ -1719,7 +1672,7 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
Q_ASSERT(dynamicData.isDetached());
if (!(p->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
if (!(alias->flags & QV4::CompiledData::Property::IsReadOnly) && writable)
propertyFlags |= QQmlPropertyData::IsWritable;
else
propertyFlags &= ~QQmlPropertyData::IsWritable;
@ -1729,8 +1682,11 @@ bool QQmlComponentAndAliasResolver::resolveAliases()
else
propertyFlags &= ~QQmlPropertyData::IsResettable;
QString propertyName = stringAt(p->nameIndex);
if (propertyIndex == obj->indexOfDefaultProperty) propertyCache->_defaultPropertyName = propertyName;
QString propertyName = stringAt(alias->nameIndex);
if (obj->defaultPropertyIsAlias && aliasIndex == obj->indexOfDefaultPropertyOrAlias)
propertyCache->_defaultPropertyName = propertyName;
propertyCache->appendProperty(propertyName, propertyFlags, effectivePropertyIndex++,
type, effectiveSignalIndex++);
@ -1842,7 +1798,7 @@ bool QQmlPropertyValidator::validateObject(int objectIndex, const QV4::CompiledD
QString defaultPropertyName;
QQmlPropertyData *defaultProperty = 0;
if (obj->indexOfDefaultProperty != -1) {
if (obj->indexOfDefaultPropertyOrAlias != -1) {
QQmlPropertyCache *cache = propertyCache->parent();
defaultPropertyName = cache->defaultPropertyName();
defaultProperty = cache->defaultProperty();
@ -2562,7 +2518,7 @@ void QQmlDefaultPropertyMerger::mergeDefaultProperties(int objectIndex)
QmlIR::Object *object = qmlObjects.at(objectIndex);
QString defaultProperty = object->indexOfDefaultProperty != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
QString defaultProperty = object->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultPropertyName() : propertyCache->defaultPropertyName();
QmlIR::Binding *bindingsToReinsert = 0;
QmlIR::Binding *tail = 0;

View File

@ -196,7 +196,11 @@ public:
bool resolveEnumBindings();
private:
bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject);
bool assignEnumToBinding(QmlIR::Binding *binding, const QStringRef &enumName, int enumValue, bool isQtObject);
bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject)
{
return assignEnumToBinding(binding, QStringRef(&enumName), enumValue, isQtObject);
}
bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache,
const QQmlPropertyData *prop,
QmlIR::Binding *binding);

View File

@ -72,6 +72,9 @@ CompilationUnit::CompilationUnit()
CompilationUnit::~CompilationUnit()
{
unlink();
if (data && !(data->flags & QV4::CompiledData::Unit::StaticData))
free(data);
data = 0;
}
QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine)
@ -163,9 +166,6 @@ void CompilationUnit::unlink()
if (engine)
engine->compilationUnits.erase(engine->compilationUnits.find(this));
engine = 0;
if (data && !(data->flags & QV4::CompiledData::Unit::StaticData))
free(data);
data = 0;
free(runtimeStrings);
runtimeStrings = 0;
delete [] runtimeLookups;
@ -221,8 +221,8 @@ QString Binding::valueAsString(const Unit *unit) const
// This code must match that in the qsTr() implementation
const QString &path = unit->stringAt(unit->sourceFileIndex);
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) :
QString();
QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5)
: QStringRef();
QByteArray contextUtf8 = context.toUtf8();
QByteArray comment = unit->stringAt(value.translationData.commentIndex).toUtf8();
QByteArray text = unit->stringAt(stringIndex).toUtf8();

View File

@ -351,22 +351,42 @@ struct Property
enum Type { Var = 0, Variant, Int, Bool, Real, String, Url, Color,
Font, Time, Date, DateTime, Rect, Point, Size,
Vector2D, Vector3D, Vector4D, Matrix4x4, Quaternion,
Alias, Custom, CustomList };
Custom, CustomList };
enum Flags {
IsReadOnly = 0x1
};
quint32 nameIndex;
quint32 type;
union {
quint32 customTypeNameIndex; // If type >= Custom
quint32 aliasIdValueIndex; // If type == Alias
};
quint32 aliasPropertyValueIndex;
quint32 flags; // readonly
quint32 type : 31;
quint32 flags : 1; // readonly
quint32 customTypeNameIndex; // If type >= Custom
Location location;
Location aliasLocation; // If type == Alias
};
struct Alias {
enum Flags {
IsReadOnly = 0x1,
Resolved = 0x2,
AliasPointsToPointerObject = 0x4
};
quint32 nameIndex : 29;
quint32 flags : 3;
union {
quint32 idIndex; // string index
quint32 targetObjectId; // object id index (in QQmlContextData::idValues)
};
union {
quint32 propertyNameIndex; // string index
qint32 encodedMetaPropertyIndex;
};
Location location;
Location referenceLocation;
bool isObjectAlias() const {
Q_ASSERT(flags & Resolved);
return encodedMetaPropertyIndex == -1;
}
};
struct Object
@ -376,11 +396,14 @@ struct Object
// it will be the name of the attached type.
quint32 inheritedTypeNameIndex;
quint32 idIndex;
qint32 indexOfDefaultProperty; // -1 means no default property declared in this object
qint32 indexOfDefaultPropertyOrAlias : 31; // -1 means no default property declared in this object
quint32 defaultPropertyIsAlias : 1;
quint32 nFunctions;
quint32 offsetToFunctions;
quint32 nProperties;
quint32 offsetToProperties;
quint32 nAliases;
quint32 offsetToAliases;
quint32 nSignals;
quint32 offsetToSignals; // which in turn will be a table with offsets to variable-sized Signal objects
quint32 nBindings;
@ -392,11 +415,12 @@ struct Object
// Signal[]
// Binding[]
static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nSignals, int nBindings)
static int calculateSizeExcludingSignals(int nFunctions, int nProperties, int nAliases, int nSignals, int nBindings)
{
return ( sizeof(Object)
+ nFunctions * sizeof(quint32)
+ nProperties * sizeof(Property)
+ nAliases * sizeof(Alias)
+ nSignals * sizeof(quint32)
+ nBindings * sizeof(Binding)
+ 0x7
@ -413,6 +437,11 @@ struct Object
return reinterpret_cast<const Property*>(reinterpret_cast<const char *>(this) + offsetToProperties);
}
const Alias *aliasTable() const
{
return reinterpret_cast<const Alias*>(reinterpret_cast<const char *>(this) + offsetToAliases);
}
const Binding *bindingTable() const
{
return reinterpret_cast<const Binding*>(reinterpret_cast<const char *>(this) + offsetToBindings);

View File

@ -135,7 +135,7 @@ public:
// Validate the new range
if (_end != InvalidPosition) {
Q_ASSERT(!_ranges.isEmpty());
foreach (const Range &range, _ranges) {
for (const Range &range : qAsConst(_ranges)) {
Q_ASSERT(range.start >= 0);
Q_ASSERT(range.end >= 0);
Q_ASSERT(range.start <= range.end);

View File

@ -45,7 +45,9 @@ QT_BEGIN_NAMESPACE
QQmlProfiler::QQmlProfiler() : featuresEnabled(0)
{
static int metatype = qRegisterMetaType<QVector<QQmlProfilerData> >();
static int metatype2 = qRegisterMetaType<QQmlProfiler::LocationHash> ();
Q_UNUSED(metatype);
Q_UNUSED(metatype2);
m_timer.start();
}
@ -62,8 +64,18 @@ void QQmlProfiler::stopProfiling()
void QQmlProfiler::reportData()
{
emit dataReady(m_data);
m_data.clear();
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();
QVector<QQmlProfilerData> data;
data.swap(m_data);
emit dataReady(data, resolved);
}
QT_END_NAMESPACE

View File

@ -54,6 +54,8 @@
#include <private/qv4function_p.h>
#include <private/qqmlboundsignal_p.h>
#include <private/qfinitestack_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlcompiler_p.h>
#include "qqmlprofilerdefinitions_p.h"
#include "qqmlabstractprofileradapter_p.h"
@ -77,40 +79,18 @@ QT_BEGIN_NAMESPACE
// independently when converting to QByteArrays. Thus you can only pack
// messages if their data doesn't overlap. It's up to you to figure that
// out.
struct Q_AUTOTEST_EXPORT QQmlProfilerData
struct Q_AUTOTEST_EXPORT QQmlProfilerData : public QQmlProfilerDefinitions
{
QQmlProfilerData() {}
QQmlProfilerData(qint64 time, int messageType, int detailType, const QUrl &url,
int x = 0, int y = 0) :
time(time), messageType(messageType), detailType(detailType), detailUrl(url),
x(x), y(y) {}
QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str,
int x = 0, int y = 0) :
time(time), messageType(messageType), detailType(detailType),detailString(str),
x(x), y(y) {}
QQmlProfilerData(qint64 time, int messageType, int detailType, const QString &str,
const QUrl &url, int x = 0, int y = 0) :
time(time), messageType(messageType), detailType(detailType), detailString(str),
detailUrl(url), x(x), y(y) {}
QQmlProfilerData(qint64 time, int messageType, int detailType) :
time(time), messageType(messageType), detailType(detailType) {}
QQmlProfilerData(qint64 time = -1, int messageType = -1,
RangeType detailType = MaximumRangeType, quintptr locationId = 0) :
time(time), locationId(locationId), messageType(messageType), detailType(detailType)
{}
qint64 time;
quintptr locationId;
int messageType; //bit field of QQmlProfilerService::Message
int detailType;
// RangeData prefers detailString; RangeLocation prefers detailUrl.
QString detailString; //used by RangeData and possibly by RangeLocation
QUrl detailUrl; //used by RangeLocation and possibly by RangeData
int x; //used by RangeLocation
int y; //used by RangeLocation
RangeType detailType;
};
Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
@ -118,58 +98,166 @@ Q_DECLARE_TYPEINFO(QQmlProfilerData, Q_MOVABLE_TYPE);
class QQmlProfiler : public QObject, public QQmlProfilerDefinitions {
Q_OBJECT
public:
void startBinding(const QQmlSourceLocation &location)
class BindingRefCount : public QQmlRefCount {
public:
BindingRefCount(QQmlBinding *binding):
m_binding(binding)
{
m_binding->ref.ref();
}
BindingRefCount(const BindingRefCount &other) :
QQmlRefCount(other), m_binding(other.m_binding)
{
m_binding->ref.ref();
}
BindingRefCount &operator=(const BindingRefCount &other)
{
if (this != &other) {
QQmlRefCount::operator=(other);
other.m_binding->ref.ref();
if (!m_binding->ref.deref())
delete m_binding;
m_binding = other.m_binding;
}
return *this;
}
~BindingRefCount()
{
if (!m_binding->ref.deref())
delete m_binding;
}
private:
QQmlBinding *m_binding;
};
struct Location {
Location(const QQmlSourceLocation &location = QQmlSourceLocation(),
const QUrl &url = QUrl()) :
location(location), url(url) {}
QQmlSourceLocation location;
QUrl url;
};
// 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(QQmlBinding *binding, QV4::FunctionObject *function) :
Location(function->sourceLocation()), locationType(Binding),
ref(new BindingRefCount(binding), QQmlRefPointer<QQmlRefCount>::Adopt)
{}
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)
{}
RefLocation(QQmlBoundSignalExpression *ref) :
Location(ref->sourceLocation()), locationType(HandlingSignal), ref(ref)
{}
RefLocation(QQmlDataBlob *ref) :
Location(QQmlSourceLocation(), ref->url()), locationType(Compiling), ref(ref)
{}
bool isValid() const
{
return locationType != MaximumRangeType;
}
RangeType locationType;
QQmlRefPointer<QQmlRefCount> ref;
};
typedef QHash<quintptr, Location> LocationHash;
void startBinding(QQmlBinding *binding, QV4::FunctionObject *function)
{
quintptr locationId(id(binding));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), 1 << Binding,
location.sourceFile, qmlSourceCoordinate(location.line), qmlSourceCoordinate(location.column)));
(1 << RangeStart | 1 << RangeLocation), Binding,
locationId));
RefLocation &location = m_locations[locationId];
if (!location.isValid())
location = RefLocation(binding, function);
}
// Have toByteArrays() construct another RangeData event from the same QString later.
// This is somewhat pointless but important for backwards compatibility.
void startCompiling(const QUrl &url)
void startCompiling(QQmlDataBlob *blob)
{
quintptr locationId(id(blob));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation | 1 << RangeData),
1 << Compiling, url, 1, 1));
Compiling, locationId));
RefLocation &location = m_locations[locationId];
if (!location.isValid())
location = RefLocation(blob);
}
void startHandlingSignal(const QQmlSourceLocation &location)
void startHandlingSignal(QQmlBoundSignalExpression *expression)
{
quintptr locationId(id(expression));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation), 1 << HandlingSignal,
location.sourceFile, location.line, location.column));
(1 << RangeStart | 1 << RangeLocation), HandlingSignal,
locationId));
RefLocation &location = m_locations[locationId];
if (!location.isValid())
location = RefLocation(expression);
}
void startCreating()
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, 1 << Creating));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeStart, Creating));
}
void startCreating(const QString &typeName, const QUrl &fileName, int line, int column)
void startCreating(const QV4::CompiledData::Object *obj)
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeStart | 1 << RangeLocation | 1 << RangeData),
1 << Creating, typeName, fileName, line, column));
Creating, id(obj)));
}
void updateCreating(const QString &typeName, const QUrl &fileName, int line, int column)
void updateCreating(const QV4::CompiledData::Object *obj, QQmlCompiledData *ref,
const QUrl &url, const QString &type)
{
quintptr locationId(id(obj));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(),
(1 << RangeLocation | 1 << RangeData),
1 << Creating, typeName, fileName, line, column));
Creating, locationId));
RefLocation &location = m_locations[locationId];
if (!location.isValid())
location = RefLocation(ref, url, obj, type);
}
template<RangeType Range>
void endRange()
{
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, 1 << Range));
m_data.append(QQmlProfilerData(m_timer.nsecsElapsed(), 1 << RangeEnd, Range));
}
QQmlProfiler();
quint64 featuresEnabled;
template<typename Object>
static quintptr id(const Object *pointer)
{
return reinterpret_cast<quintptr>(pointer);
}
public slots:
void startProfiling(quint64 features);
void stopProfiling();
@ -177,10 +265,11 @@ public slots:
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
void dataReady(const QVector<QQmlProfilerData> &);
void dataReady(const QVector<QQmlProfilerData> &, const QQmlProfiler::LocationHash &);
protected:
QElapsedTimer m_timer;
QHash<quintptr, RefLocation> m_locations;
QVector<QQmlProfilerData> m_data;
};
@ -194,11 +283,12 @@ struct QQmlProfilerHelper : public QQmlProfilerDefinitions {
};
struct QQmlBindingProfiler : public QQmlProfilerHelper {
QQmlBindingProfiler(QQmlProfiler *profiler, const QV4::FunctionObject *function) :
QQmlBindingProfiler(QQmlProfiler *profiler, QQmlBinding *binding,
QV4::FunctionObject *function) :
QQmlProfilerHelper(profiler)
{
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileBinding, profiler,
startBinding(function->sourceLocation()));
startBinding(binding, function));
}
~QQmlBindingProfiler()
@ -213,7 +303,7 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper {
QQmlProfilerHelper(profiler)
{
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileHandlingSignal, profiler,
startHandlingSignal(expression->sourceLocation()));
startHandlingSignal(expression));
}
~QQmlHandlingSignalProfiler()
@ -224,10 +314,10 @@ struct QQmlHandlingSignalProfiler : public QQmlProfilerHelper {
};
struct QQmlCompilingProfiler : public QQmlProfilerHelper {
QQmlCompilingProfiler(QQmlProfiler *profiler, const QUrl &url) :
QQmlCompilingProfiler(QQmlProfiler *profiler, QQmlDataBlob *blob) :
QQmlProfilerHelper(profiler)
{
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(url));
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCompiling, profiler, startCompiling(blob));
}
~QQmlCompilingProfiler()
@ -239,14 +329,6 @@ struct QQmlCompilingProfiler : public QQmlProfilerHelper {
struct QQmlVmeProfiler : public QQmlProfilerDefinitions {
public:
struct Data {
Data() : m_line(0), m_column(0) {}
QUrl m_url;
int m_line;
int m_column;
QString m_typeName;
};
QQmlVmeProfiler() : profiler(0) {}
void init(QQmlProfiler *p, int maxDepth)
@ -255,30 +337,30 @@ public:
ranges.allocate(maxDepth);
}
Data pop()
const QV4::CompiledData::Object *pop()
{
if (ranges.count() > 0)
return ranges.pop();
else
return Data();
return nullptr;
}
void push(const Data &data)
void push(const QV4::CompiledData::Object *object)
{
if (ranges.capacity() > ranges.count())
ranges.push(data);
ranges.push(object);
}
QQmlProfiler *profiler;
private:
QFiniteStack<Data> ranges;
QFiniteStack<const QV4::CompiledData::Object *> ranges;
};
#define Q_QML_OC_PROFILE(member, Code)\
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, member.profiler, Code)
class QQmlObjectCreationProfiler : public QQmlVmeProfiler::Data {
class QQmlObjectCreationProfiler {
public:
QQmlObjectCreationProfiler(QQmlProfiler *profiler) : profiler(profiler)
@ -291,13 +373,10 @@ public:
Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange<QQmlProfilerDefinitions::Creating>());
}
void update(const QString &typeName, const QUrl &url, int line, int column)
void update(QQmlCompiledData *ref, const QV4::CompiledData::Object *obj,
const QString &typeName, const QUrl &url)
{
profiler->updateCreating(typeName, url, line, column);
m_typeName = typeName;
m_url = url;
m_line = line;
m_column = column;
profiler->updateCreating(obj, ref, url, typeName);
}
private:
@ -310,8 +389,7 @@ public:
profiler(parent->profiler)
{
Q_QML_PROFILE_IF_ENABLED(QQmlProfilerDefinitions::ProfileCreating, profiler, {
QQmlVmeProfiler::Data data = parent->pop();
profiler->startCreating(data.m_typeName, data.m_url, data.m_line, data.m_column);
profiler->startCreating(parent->pop());
});
}
@ -326,5 +404,6 @@ private:
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QVector<QQmlProfilerData>)
Q_DECLARE_METATYPE(QQmlProfiler::LocationHash)
#endif // QQMLPROFILER_P_H

View File

@ -112,7 +112,7 @@ when passed from C++ to QML and vice-versa:
\li QVector2D, QVector3D, QVector4D
\li \l vector2d, \l vector3d, \l vector4d
\row
\li Enums declared with Q_ENUMS()
\li Enums declared with Q_ENUM() or Q_ENUMS()
\li \l enumeration
\endtable
@ -261,6 +261,9 @@ In particular, QML currently supports:
\li \c {QList<bool>}
\li \c {QList<QString>} and \c{QStringList}
\li \c {QList<QUrl>}
\li \c {QVector<int>}
\li \c {QVector<qreal>}
\li \c {QVector<bool>}
\endlist
These sequence types are implemented directly in terms of the underlying C++
@ -303,6 +306,9 @@ The default-constructed values for each sequence type are as follows:
\row \li QList<bool> \li boolean value \c {false}
\row \li QList<QString> and QStringList \li empty QString
\row \li QList<QUrl> \li empty QUrl
\row \li QVector<int> \li integer value 0
\row \li QVector<qreal> \li real value 0.0
\row \li QVector<bool> \li boolean value \c {false}
\endtable
If you wish to remove elements from a sequence rather than simply replace
@ -341,7 +347,7 @@ properties:
\section1 Enumeration Types
To use a custom enumeration as a data type, its class must be registered and
the enumeration must also be declared with Q_ENUMS() to register it with Qt's
the enumeration must also be declared with Q_ENUM() to register it with Qt's
meta object system. For example, the \c Message class below has a \c Status
enum:
@ -349,7 +355,6 @@ enum:
class Message : public QObject
{
Q_OBJECT
Q_ENUMS(Status)
Q_PROPERTY(Status status READ status NOTIFY statusChanged)
public:
enum Status {
@ -357,6 +362,7 @@ enum:
Loading,
Error
};
Q_ENUM(Status)
Status status() const;
signals:
void statusChanged();

View File

@ -386,12 +386,26 @@ directory.
\quotefile tutorials/extending-qml/chapter6-plugins/import/import.pro
In this example, the \c Charts directory is located at the same level as the application
that uses our new import module. This way, the QML engine will find our module
as the default search path for QML imports includes the directory of the application
executable. Alternatively, we could control what directories the \l {QML Import Path}
{QML import path} contains, useful if there are multiple QML applications using the
same QML imports.
When building this example on Windows or Linux, the \c Charts directory will be
located at the same level as the application that uses our new import module.
This way, the QML engine will find our module as the default search path for QML
imports includes the directory of the application executable. On OS X, the
plugin binary is copied to \c Contents/PlugIns in the the application bundle;
this path is set in \l {tutorials/extending-qml/chapter6-plugins/app.pro}
{chapter6-plugins/app.pro}:
\quotefromfile tutorials/extending-qml/chapter6-plugins/app.pro
\skipto osx
\printuntil }
To account for this, we also need to add this location as a
\l {QML Import Path}{QML import path} in \c main.cpp:
\snippet tutorials/extending-qml/chapter6-plugins/main.cpp 0
\dots
Defining custom import paths is useful also when there are multiple
applications using the same QML imports.
The \c .pro file also contains additional magic to ensure that the
\l {Module Definition qmldir Files}{module definition qmldir file} is always copied

View File

@ -508,7 +508,7 @@ built-in \l {Rectangle::color} property:
Any object that use this type and refer to its \c color property will be
referring to the alias rather than the ordinary \l {Rectangle::color} property.
Internally, however, the red can correctly set its \c color
Internally, however, the rectangle can correctly set its \c color
property and refer to the actual defined property rather than the alias.

View File

@ -134,7 +134,8 @@ public:
static int ebxIdx = -1;
if (ebxIdx == -1) {
int calleeSaves = 0;
foreach (const RegisterInfo &info, getRegisterInfo()) {
const auto infos = getRegisterInfo();
for (const RegisterInfo &info : infos) {
if (info.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
ebxIdx = calleeSaves;
break;

View File

@ -247,6 +247,11 @@ Q_DECLARE_METATYPE(QList<int>)
QT_BEGIN_NAMESPACE
static void checkForApplicationInstance()
{
if (!QCoreApplication::instance())
qFatal("QJSEngine: Must construct a QCoreApplication before a QJSEngine");
}
/*!
Constructs a QJSEngine object.
@ -270,6 +275,8 @@ QJSEngine::QJSEngine(QObject *parent)
: QObject(*new QJSEnginePrivate, parent)
, d(new QV8Engine(this))
{
checkForApplicationInstance();
QJSEnginePrivate::addToDebugServer(this);
}
@ -280,6 +287,7 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent)
: QObject(dd, parent)
, d(new QV8Engine(this))
{
checkForApplicationInstance();
}
/*!

View File

@ -287,7 +287,13 @@ void SimpleArrayData::push_front(Object *o, const Value *values, uint n)
Q_ASSERT(o->d()->arrayData->type == Heap::ArrayData::Simple);
dd = o->d()->arrayData.cast<Heap::SimpleArrayData>();
}
dd->offset = (dd->offset - n) % dd->alloc;
if (n <= dd->offset) {
dd->offset -= n; // there is enough space left in front
} else {
// we need to wrap around, so:
dd->offset = dd->alloc - // start at the back, but subtract:
(n - dd->offset); // the number of items we can put in the free space at the start of the allocated array
}
dd->len += n;
for (uint i = 0; i < n; ++i)
dd->data(i) = values[i].asReturnedValue();

View File

@ -338,7 +338,7 @@ static inline double currentTime()
static inline double TimeClip(double t)
{
if (! qIsFinite(t) || fabs(t) > 8.64e15)
if (! qt_is_finite(t) || fabs(t) > 8.64e15)
return qt_qnan();
return Primitive::toInteger(t);
}

View File

@ -160,13 +160,9 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
if (i > 0)
trace += QLatin1Char('\n');
const StackFrame &frame = This->d()->stackTrace[i];
trace += frame.function;
trace += QLatin1Char('@');
trace += frame.source;
if (frame.line >= 0) {
trace += QLatin1Char(':');
trace += QString::number(frame.line);
}
trace += frame.function + QLatin1Char('@') + frame.source;
if (frame.line >= 0)
trace += QLatin1Char(':') + QString::number(frame.line);
}
This->d()->stack = ctx->d()->engine->newString(trace);
}

View File

@ -131,7 +131,7 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const
return 0;
Q_ASSERT(d->entries);
uint hash = String::createHashValue(str.constData(), str.length());
uint hash = String::createHashValue(str.constData(), str.length(), Q_NULLPTR);
uint idx = hash % d->alloc;
while (1) {
if (!d->entries[idx].identifier)

View File

@ -118,7 +118,8 @@ void IdentifierTable::addEntry(Heap::String *str)
Heap::String *IdentifierTable::insertString(const QString &s)
{
uint hash = String::createHashValue(s.constData(), s.length());
uint subtype;
uint hash = String::createHashValue(s.constData(), s.length(), &subtype);
uint idx = hash % alloc;
while (Heap::String *e = entries[idx]) {
if (e->stringHash == hash && e->toQString() == s)
@ -128,6 +129,8 @@ Heap::String *IdentifierTable::insertString(const QString &s)
}
Heap::String *str = engine->newString(s);
str->stringHash = hash;
str->subtype = subtype;
addEntry(str);
return str;
}
@ -178,7 +181,8 @@ Identifier *IdentifierTable::identifier(const QString &s)
Identifier *IdentifierTable::identifier(const char *s, int len)
{
uint hash = String::createHashValue(s, len);
uint subtype;
uint hash = String::createHashValue(s, len, &subtype);
if (hash == UINT_MAX)
return identifier(QString::fromUtf8(s, len));
@ -192,6 +196,8 @@ Identifier *IdentifierTable::identifier(const char *s, int len)
}
Heap::String *str = engine->newString(QString::fromLatin1(s, len));
str->stringHash = hash;
str->subtype = subtype;
addEntry(str);
return str->identifier;
}

View File

@ -429,11 +429,13 @@ InternalClass *InternalClass::propertiesFrozen() const
void InternalClass::destroy()
{
QList<InternalClass *> destroyStack;
destroyStack.append(this);
std::vector<InternalClass *> destroyStack;
destroyStack.reserve(64);
destroyStack.push_back(this);
while (!destroyStack.isEmpty()) {
InternalClass *next = destroyStack.takeLast();
while (!destroyStack.empty()) {
InternalClass *next = destroyStack.back();
destroyStack.pop_back();
if (!next->engine)
continue;
next->engine = 0;
@ -441,13 +443,13 @@ void InternalClass::destroy()
next->nameMap.~SharedInternalClassData<Identifier *>();
next->propertyData.~SharedInternalClassData<PropertyAttributes>();
if (next->m_sealed)
destroyStack.append(next->m_sealed);
destroyStack.push_back(next->m_sealed);
if (next->m_frozen)
destroyStack.append(next->m_frozen);
destroyStack.push_back(next->m_frozen);
for (size_t i = 0; i < next->transitions.size(); ++i) {
Q_ASSERT(next->transitions.at(i).lookup);
destroyStack.append(next->transitions.at(i).lookup);
destroyStack.push_back(next->transitions.at(i).lookup);
}
next->transitions.~vector<Transition>();

View File

@ -590,8 +590,7 @@ bool JsonParser::parseString(QString *string)
return false;
}
if (QChar::requiresSurrogates(ch)) {
*string += QChar(QChar::highSurrogate(ch));
*string += QChar(QChar::lowSurrogate(ch));
*string += QChar(QChar::highSurrogate(ch)) + QChar(QChar::lowSurrogate(ch));
} else {
*string += QChar(ch);
}
@ -672,8 +671,8 @@ static QString quote(const QString &str)
default:
if (c.unicode() <= 0x1f) {
product += QStringLiteral("\\u00");
product += c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0');
product += QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]);
product += (c.unicode() > 0xf ? QLatin1Char('1') : QLatin1Char('0')) +
QLatin1Char("0123456789abcdef"[c.unicode() & 0xf]);
} else {
product += c;
}

View File

@ -753,9 +753,8 @@ void Object::internalPut(String *name, const Value &value)
reject:
if (engine()->current->strictMode) {
QString message = QStringLiteral("Cannot assign to read-only property \"");
message += name->toQString();
message += QLatin1Char('\"');
QString message = QStringLiteral("Cannot assign to read-only property \"") +
name->toQString() + QLatin1Char('\"');
engine()->throwTypeError(message);
}
}

View File

@ -46,26 +46,32 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace Profiling {
FunctionCallProperties FunctionCall::resolve() const
FunctionLocation FunctionCall::resolveLocation() const
{
return FunctionLocation(m_function->name()->toQString(),
m_function->compilationUnit->fileName(),
m_function->compiledFunction->location.line,
m_function->compiledFunction->location.column);
}
FunctionCallProperties FunctionCall::properties() const
{
FunctionCallProperties props = {
m_start,
m_end,
m_function->name()->toQString(),
m_function->compilationUnit->fileName(),
m_function->compiledFunction->location.line,
m_function->compiledFunction->location.column
reinterpret_cast<quintptr>(m_function)
};
return props;
}
Profiler::Profiler(QV4::ExecutionEngine *engine) : featuresEnabled(0), m_engine(engine)
{
static int meta = qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >();
static int meta2 = qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >();
Q_UNUSED(meta);
Q_UNUSED(meta2);
static const int metatypes[] = {
qRegisterMetaType<QVector<QV4::Profiling::FunctionCallProperties> >(),
qRegisterMetaType<QVector<QV4::Profiling::MemoryAllocationProperties> >(),
qRegisterMetaType<FunctionLocationHash>()
};
Q_UNUSED(metatypes);
m_timer.start();
}
@ -85,13 +91,18 @@ bool operator<(const FunctionCall &call1, const FunctionCall &call2)
void Profiler::reportData()
{
std::sort(m_data.begin(), m_data.end());
QVector<FunctionCallProperties> resolved;
resolved.reserve(m_data.size());
QVector<FunctionCallProperties> properties;
FunctionLocationHash locations;
properties.reserve(m_data.size());
foreach (const FunctionCall &call, m_data)
resolved.append(call.resolve());
foreach (const FunctionCall &call, m_data) {
properties.append(call.properties());
FunctionLocation &location = locations[properties.constLast().id];
if (!location.isValid())
location = call.resolveLocation();
}
emit dataReady(resolved, m_memory_data);
emit dataReady(locations, properties, m_memory_data);
m_data.clear();
m_memory_data.clear();
}

View File

@ -77,12 +77,28 @@ enum MemoryType {
struct FunctionCallProperties {
qint64 start;
qint64 end;
quintptr id;
};
struct FunctionLocation {
FunctionLocation(const QString &name = QString(), const QString &file = QString(),
int line = -1, int column = -1) :
name(name), file(file), line(line), column(column)
{}
bool isValid()
{
return !name.isEmpty();
}
QString name;
QString file;
int line;
int column;
};
typedef QHash<quintptr, QV4::Profiling::FunctionLocation> FunctionLocationHash;
struct MemoryAllocationProperties {
qint64 timestamp;
qint64 size;
@ -118,7 +134,8 @@ public:
return *this;
}
FunctionCallProperties resolve() const;
FunctionLocation resolveLocation() const;
FunctionCallProperties properties() const;
private:
friend bool operator<(const FunctionCall &call1, const FunctionCall &call2);
@ -173,7 +190,8 @@ public slots:
void setTimer(const QElapsedTimer &timer) { m_timer = timer; }
signals:
void dataReady(const QVector<QV4::Profiling::FunctionCallProperties> &,
void dataReady(const QV4::Profiling::FunctionLocationHash &,
const QVector<QV4::Profiling::FunctionCallProperties> &,
const QVector<QV4::Profiling::MemoryAllocationProperties> &);
private:
@ -218,8 +236,10 @@ public:
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);
QT_END_NAMESPACE
Q_DECLARE_METATYPE(QV4::Profiling::FunctionLocationHash)
Q_DECLARE_METATYPE(QVector<QV4::Profiling::FunctionCallProperties>)
Q_DECLARE_METATYPE(QVector<QV4::Profiling::MemoryAllocationProperties>)

View File

@ -1285,6 +1285,8 @@ static int MatchScore(const QV4::Value &actual, int conversionType)
return 10;
} else if (conversionType == QMetaType::QJsonObject) {
return 5;
} else if (conversionType == qMetaTypeId<QJSValue>()) {
return 0;
} else {
return 10;
}
@ -1768,17 +1770,13 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co
QString result;
if (const QMetaObject *metaObject = d()->metaObject()) {
result += QString::fromUtf8(metaObject->className());
result += QLatin1String("(0x");
result += QString::number((quintptr)d()->object.data(),16);
result += QString::fromUtf8(metaObject->className()) +
QLatin1String("(0x") + QString::number((quintptr)d()->object.data(),16);
if (d()->object) {
QString objectName = d()->object->objectName();
if (!objectName.isEmpty()) {
result += QLatin1String(", \"");
result += objectName;
result += QLatin1Char('\"');
}
if (!objectName.isEmpty())
result += QLatin1String(", \"") + objectName + QLatin1Char('\"');
}
result += QLatin1Char(')');

View File

@ -185,8 +185,7 @@ QRegExp RegExpObject::toQRegExp() const
QString RegExpObject::toString() const
{
QString result = QLatin1Char('/') + source();
result += QLatin1Char('/');
QString result = QLatin1Char('/') + source() + QLatin1Char('/');
if (global())
result += QLatin1Char('g');
if (value()->ignoreCase)

View File

@ -984,10 +984,9 @@ ReturnedValue Runtime::method_callQmlScopeObjectProperty(ExecutionEngine *engine
Scope scope(engine);
ScopedFunctionObject o(scope, method_getQmlScopeObjectProperty(engine, callData->thisObject, propertyIndex));
if (!o) {
QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow());
QString error = QStringLiteral("Property '%1' of scope object is not a function").arg(propertyIndex);
return engine->throwTypeError(error);
}
return o->call(callData);
}
@ -996,7 +995,7 @@ ReturnedValue Runtime::method_callQmlContextObjectProperty(ExecutionEngine *engi
Scope scope(engine);
ScopedFunctionObject o(scope, method_getQmlContextObjectProperty(engine, callData->thisObject, propertyIndex));
if (!o) {
QString error = QStringLiteral("Property '%1' of object %2 is not a function").arg(propertyIndex).arg(callData->thisObject.toQStringNoThrow());
QString error = QStringLiteral("Property '%1' of context object is not a function").arg(propertyIndex);
return engine->throwTypeError(error);
}
@ -1623,6 +1622,351 @@ void Runtime::method_convertThisToObject(ExecutionEngine *engine)
}
}
ReturnedValue Runtime::method_uPlus(const Value &value)
{
TRACE1(value);
if (value.isNumber())
return value.asReturnedValue();
if (value.integerCompatible())
return Encode(value.int_32());
double n = value.toNumberImpl();
return Encode(n);
}
ReturnedValue Runtime::method_uMinus(const Value &value)
{
TRACE1(value);
// +0 != -0, so we need to convert to double when negating 0
if (value.isInteger() && value.integerValue())
return Encode(-value.integerValue());
else {
double n = RuntimeHelpers::toNumber(value);
return Encode(-n);
}
}
ReturnedValue Runtime::method_complement(const Value &value)
{
TRACE1(value);
int n = value.toInt32();
return Encode((int)~n);
}
ReturnedValue Runtime::method_uNot(const Value &value)
{
TRACE1(value);
bool b = value.toBoolean();
return Encode(!b);
}
// binary operators
ReturnedValue Runtime::method_bitOr(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32();
return Encode(lval | rval);
}
ReturnedValue Runtime::method_bitXor(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32();
return Encode(lval ^ rval);
}
ReturnedValue Runtime::method_bitAnd(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32();
return Encode(lval & rval);
}
#ifndef V4_BOOTSTRAP
ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
if (Q_LIKELY(left.isInteger() && right.isInteger()))
return add_int32(left.integerValue(), right.integerValue());
if (left.isNumber() && right.isNumber())
return Primitive::fromDouble(left.asDouble() + right.asDouble()).asReturnedValue();
return RuntimeHelpers::addHelper(engine, left, right);
}
#endif // V4_BOOTSTRAP
ReturnedValue Runtime::method_sub(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Q_LIKELY(left.isInteger() && right.isInteger()))
return sub_int32(left.integerValue(), right.integerValue());
double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
return Primitive::fromDouble(lval - rval).asReturnedValue();
}
ReturnedValue Runtime::method_mul(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Q_LIKELY(left.isInteger() && right.isInteger()))
return mul_int32(left.integerValue(), right.integerValue());
double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
return Primitive::fromDouble(lval * rval).asReturnedValue();
}
ReturnedValue Runtime::method_div(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right)) {
int lval = left.integerValue();
int rval = right.integerValue();
if (rval != 0 && (lval % rval == 0))
return Encode(int(lval / rval));
else
return Encode(double(lval) / rval);
}
double lval = left.toNumber();
double rval = right.toNumber();
return Primitive::fromDouble(lval / rval).asReturnedValue();
}
ReturnedValue Runtime::method_mod(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right) && right.integerValue() != 0) {
int intRes = left.integerValue() % right.integerValue();
if (intRes != 0 || left.integerValue() >= 0)
return Encode(intRes);
}
double lval = RuntimeHelpers::toNumber(left);
double rval = RuntimeHelpers::toNumber(right);
#ifdef fmod
# undef fmod
#endif
return Primitive::fromDouble(std::fmod(lval, rval)).asReturnedValue();
}
ReturnedValue Runtime::method_shl(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32() & 0x1f;
return Encode((int)(lval << rval));
}
ReturnedValue Runtime::method_shr(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
unsigned rval = right.toUInt32() & 0x1f;
return Encode((int)(lval >> rval));
}
ReturnedValue Runtime::method_ushr(const Value &left, const Value &right)
{
TRACE2(left, right);
unsigned lval = left.toUInt32();
unsigned rval = right.toUInt32() & 0x1f;
uint res = lval >> rval;
return Encode(res);
}
ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareGreaterThan(left, right);
return Encode(r);
}
ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareLessThan(left, right);
return Encode(r);
}
ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareGreaterEqual(left, right);
return Encode(r);
}
ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareLessEqual(left, right);
return Encode(r);
}
Bool Runtime::method_compareEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
if (left.rawValue() == right.rawValue())
// NaN != NaN
return !left.isNaN();
if (left.type() == right.type()) {
if (!left.isManaged())
return false;
if (left.isString() == right.isString())
return left.cast<Managed>()->isEqualTo(right.cast<Managed>());
}
return RuntimeHelpers::equalHelper(left, right);
}
ReturnedValue Runtime::method_equal(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareEqual(left, right);
return Encode(r);
}
ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = !method_compareEqual(left, right);
return Encode(r);
}
ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = RuntimeHelpers::strictEqual(left, right);
return Encode(r);
}
ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = ! RuntimeHelpers::strictEqual(left, right);
return Encode(r);
}
Bool Runtime::method_compareNotEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
return !Runtime::method_compareEqual(left, right);
}
Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
return RuntimeHelpers::strictEqual(left, right);
}
Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
return ! RuntimeHelpers::strictEqual(left, right);
}
Bool Runtime::method_toBoolean(const Value &value)
{
return value.toBoolean();
}
ReturnedValue Runtime::method_accessQmlScopeObjectQRealProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
qreal rv = 0;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
ReturnedValue Runtime::method_accessQmlScopeObjectIntProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
int rv = 0;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
ReturnedValue Runtime::method_accessQmlScopeObjectBoolProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
bool rv = false;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
ReturnedValue Runtime::method_accessQmlScopeObjectQStringProperty(ExecutionEngine *engine,
const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
QString rv;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(engine->newString(rv));
#else
Q_UNUSED(engine);
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
#endif // V4_BOOTSTRAP
} // namespace QV4

View File

@ -140,349 +140,6 @@ inline double RuntimeHelpers::toNumber(const Value &value)
{
return value.toNumber();
}
inline ReturnedValue Runtime::method_uPlus(const Value &value)
{
TRACE1(value);
if (value.isNumber())
return value.asReturnedValue();
if (value.integerCompatible())
return Encode(value.int_32());
double n = value.toNumberImpl();
return Encode(n);
}
inline ReturnedValue Runtime::method_uMinus(const Value &value)
{
TRACE1(value);
// +0 != -0, so we need to convert to double when negating 0
if (value.isInteger() && value.integerValue())
return Encode(-value.integerValue());
else {
double n = RuntimeHelpers::toNumber(value);
return Encode(-n);
}
}
inline ReturnedValue Runtime::method_complement(const Value &value)
{
TRACE1(value);
int n = value.toInt32();
return Encode((int)~n);
}
inline ReturnedValue Runtime::method_uNot(const Value &value)
{
TRACE1(value);
bool b = value.toBoolean();
return Encode(!b);
}
// binary operators
inline ReturnedValue Runtime::method_bitOr(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32();
return Encode(lval | rval);
}
inline ReturnedValue Runtime::method_bitXor(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32();
return Encode(lval ^ rval);
}
inline ReturnedValue Runtime::method_bitAnd(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32();
return Encode(lval & rval);
}
#ifndef V4_BOOTSTRAP
inline ReturnedValue Runtime::method_add(ExecutionEngine *engine, const Value &left, const Value &right)
{
TRACE2(left, right);
if (Q_LIKELY(left.isInteger() && right.isInteger()))
return add_int32(left.integerValue(), right.integerValue());
if (left.isNumber() && right.isNumber())
return Primitive::fromDouble(left.asDouble() + right.asDouble()).asReturnedValue();
return RuntimeHelpers::addHelper(engine, left, right);
}
#endif // V4_BOOTSTRAP
inline ReturnedValue Runtime::method_sub(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Q_LIKELY(left.isInteger() && right.isInteger()))
return sub_int32(left.integerValue(), right.integerValue());
double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
return Primitive::fromDouble(lval - rval).asReturnedValue();
}
inline ReturnedValue Runtime::method_mul(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Q_LIKELY(left.isInteger() && right.isInteger()))
return mul_int32(left.integerValue(), right.integerValue());
double lval = left.isNumber() ? left.asDouble() : left.toNumberImpl();
double rval = right.isNumber() ? right.asDouble() : right.toNumberImpl();
return Primitive::fromDouble(lval * rval).asReturnedValue();
}
inline ReturnedValue Runtime::method_div(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right)) {
int lval = left.integerValue();
int rval = right.integerValue();
if (rval != 0 && (lval % rval == 0))
return Encode(int(lval / rval));
else
return Encode(double(lval) / rval);
}
double lval = left.toNumber();
double rval = right.toNumber();
return Primitive::fromDouble(lval / rval).asReturnedValue();
}
inline ReturnedValue Runtime::method_mod(const Value &left, const Value &right)
{
TRACE2(left, right);
if (Value::integerCompatible(left, right) && right.integerValue() != 0) {
int intRes = left.integerValue() % right.integerValue();
if (intRes != 0 || left.integerValue() >= 0)
return Encode(intRes);
}
double lval = RuntimeHelpers::toNumber(left);
double rval = RuntimeHelpers::toNumber(right);
return Primitive::fromDouble(std::fmod(lval, rval)).asReturnedValue();
}
inline ReturnedValue Runtime::method_shl(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
int rval = right.toInt32() & 0x1f;
return Encode((int)(lval << rval));
}
inline ReturnedValue Runtime::method_shr(const Value &left, const Value &right)
{
TRACE2(left, right);
int lval = left.toInt32();
unsigned rval = right.toUInt32() & 0x1f;
return Encode((int)(lval >> rval));
}
inline ReturnedValue Runtime::method_ushr(const Value &left, const Value &right)
{
TRACE2(left, right);
unsigned lval = left.toUInt32();
unsigned rval = right.toUInt32() & 0x1f;
uint res = lval >> rval;
return Encode(res);
}
inline ReturnedValue Runtime::method_greaterThan(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareGreaterThan(left, right);
return Encode(r);
}
inline ReturnedValue Runtime::method_lessThan(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareLessThan(left, right);
return Encode(r);
}
inline ReturnedValue Runtime::method_greaterEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareGreaterEqual(left, right);
return Encode(r);
}
inline ReturnedValue Runtime::method_lessEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareLessEqual(left, right);
return Encode(r);
}
inline Bool Runtime::method_compareEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
if (left.rawValue() == right.rawValue())
// NaN != NaN
return !left.isNaN();
if (left.type() == right.type()) {
if (!left.isManaged())
return false;
if (left.isString() == right.isString())
return left.cast<Managed>()->isEqualTo(right.cast<Managed>());
}
return RuntimeHelpers::equalHelper(left, right);
}
inline ReturnedValue Runtime::method_equal(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = method_compareEqual(left, right);
return Encode(r);
}
inline ReturnedValue Runtime::method_notEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = !method_compareEqual(left, right);
return Encode(r);
}
inline ReturnedValue Runtime::method_strictEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = RuntimeHelpers::strictEqual(left, right);
return Encode(r);
}
inline ReturnedValue Runtime::method_strictNotEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
bool r = ! RuntimeHelpers::strictEqual(left, right);
return Encode(r);
}
inline Bool Runtime::method_compareNotEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
return !Runtime::method_compareEqual(left, right);
}
inline Bool Runtime::method_compareStrictEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
return RuntimeHelpers::strictEqual(left, right);
}
inline Bool Runtime::method_compareStrictNotEqual(const Value &left, const Value &right)
{
TRACE2(left, right);
return ! RuntimeHelpers::strictEqual(left, right);
}
inline Bool Runtime::method_toBoolean(const Value &value)
{
return value.toBoolean();
}
inline ReturnedValue Runtime::method_accessQmlScopeObjectQRealProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
qreal rv = 0;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
inline ReturnedValue Runtime::method_accessQmlScopeObjectIntProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
int rv = 0;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
inline ReturnedValue Runtime::method_accessQmlScopeObjectBoolProperty(const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
bool rv = false;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(rv);
#else
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
inline ReturnedValue Runtime::method_accessQmlScopeObjectQStringProperty(ExecutionEngine *engine,
const Value &context,
QQmlAccessors *accessors)
{
#ifndef V4_BOOTSTRAP
const QmlContext &c = static_cast<const QmlContext &>(context);
QString rv;
accessors->read(c.d()->qml->scopeObject, &rv);
return QV4::Encode(engine->newString(rv));
#else
Q_UNUSED(engine);
Q_UNUSED(context);
Q_UNUSED(accessors);
return QV4::Encode::undefined();
#endif
}
} // namespace QV4
QT_END_NAMESPACE

View File

@ -75,6 +75,9 @@ static void generateWarning(QV4::ExecutionEngine *v4, const QString& description
// F(elementType, elementTypeName, sequenceType, defaultValue)
#define FOREACH_QML_SEQUENCE_TYPE(F) \
F(int, IntVector, QVector<int>, 0) \
F(qreal, RealVector, QVector<qreal>, 0.0) \
F(bool, BoolVector, QVector<bool>, false) \
F(int, Int, QList<int>, 0) \
F(qreal, Real, QList<qreal>, 0.0) \
F(bool, Bool, QList<bool>, false) \
@ -578,6 +581,15 @@ Heap::QQmlSequence<Container>::QQmlSequence(QObject *object, int propertyIndex)
namespace QV4 {
typedef QQmlSequence<QVector<int> > QQmlIntVectorList;
template<>
DEFINE_OBJECT_VTABLE(QQmlIntVectorList);
typedef QQmlSequence<QVector<qreal> > QQmlRealVectorList;
template<>
DEFINE_OBJECT_VTABLE(QQmlRealVectorList);
typedef QQmlSequence<QVector<bool> > QQmlBoolVectorList;
template<>
DEFINE_OBJECT_VTABLE(QQmlBoolVectorList);
typedef QQmlSequence<QStringList> QQmlQStringList;
template<>
DEFINE_OBJECT_VTABLE(QQmlQStringList);

View File

@ -46,12 +46,19 @@
#include "qv4stringobject_p.h"
#endif
#include <QtCore/QHash>
#include <QtCore/private/qnumeric_p.h>
using namespace QV4;
static uint toArrayIndex(const QChar *ch, const QChar *end)
static inline uint toUInt(const QChar *ch) { return ch->unicode(); }
#ifndef V4_BOOTSTRAP
static inline uint toUInt(const char *ch) { return *ch; }
#endif
template <typename T>
static inline uint toArrayIndex(const T *ch, const T *end)
{
uint i = ch->unicode() - '0';
uint i = toUInt(ch) - '0';
if (i > 9)
return UINT_MAX;
++ch;
@ -60,14 +67,11 @@ static uint toArrayIndex(const QChar *ch, const QChar *end)
return UINT_MAX;
while (ch < end) {
uint x = ch->unicode() - '0';
uint x = toUInt(ch) - '0';
if (x > 9)
return UINT_MAX;
uint n = i*10 + x;
if (n < i)
// overflow
if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i))
return UINT_MAX;
i = n;
++ch;
}
return i;
@ -75,30 +79,26 @@ static uint toArrayIndex(const QChar *ch, const QChar *end)
#ifndef V4_BOOTSTRAP
static uint toArrayIndex(const char *ch, const char *end)
template <typename T>
static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype)
{
uint i = *ch - '0';
if (i > 9)
return UINT_MAX;
++ch;
// reject "01", "001", ...
if (i == 0 && ch != end)
return UINT_MAX;
// array indices get their number as hash value
uint h = ::toArrayIndex(ch, end);
if (h != UINT_MAX) {
if (subtype)
*subtype = Heap::String::StringType_ArrayIndex;
return h;
}
while (ch < end) {
uint x = *ch - '0';
if (x > 9)
return UINT_MAX;
uint n = i*10 + x;
if (n < i)
// overflow
return UINT_MAX;
i = n;
h = 31 * h + toUInt(ch);
++ch;
}
return i;
}
if (subtype)
*subtype = Heap::String::StringType_Regular;
return h;
}
DEFINE_MANAGED_VTABLE(String);
@ -198,31 +198,6 @@ void Heap::String::simplifyString() const
mm->growUnmanagedHeapSizeUsage(size_t(text->size) * sizeof(QChar));
}
void Heap::String::createHashValue() const
{
if (largestSubLength)
simplifyString();
Q_ASSERT(!largestSubLength);
const QChar *ch = reinterpret_cast<const QChar *>(text->data());
const QChar *end = ch + text->size;
// array indices get their number as hash value
stringHash = ::toArrayIndex(ch, end);
if (stringHash != UINT_MAX) {
subtype = Heap::String::StringType_ArrayIndex;
return;
}
uint h = 0xffffffff;
while (ch < end) {
h = 31 * h + ch->unicode();
++ch;
}
stringHash = h;
subtype = Heap::String::StringType_Regular;
}
void Heap::String::append(const String *data, QChar *ch)
{
std::vector<const String *> worklist;
@ -243,45 +218,26 @@ void Heap::String::append(const String *data, QChar *ch)
}
}
uint String::createHashValue(const QChar *ch, int length)
void Heap::String::createHashValue() const
{
const QChar *end = ch + length;
// array indices get their number as hash value
uint stringHash = ::toArrayIndex(ch, end);
if (stringHash != UINT_MAX)
return stringHash;
uint h = 0xffffffff;
while (ch < end) {
h = 31 * h + ch->unicode();
++ch;
}
return h;
if (largestSubLength)
simplifyString();
Q_ASSERT(!largestSubLength);
const QChar *ch = reinterpret_cast<const QChar *>(text->data());
const QChar *end = ch + text->size;
stringHash = calculateHashValue(ch, end, &subtype);
}
uint String::createHashValue(const char *ch, int length)
uint String::createHashValue(const QChar *ch, int length, uint *subtype)
{
const QChar *end = ch + length;
return calculateHashValue(ch, end, subtype);
}
uint String::createHashValue(const char *ch, int length, uint *subtype)
{
const char *end = ch + length;
// array indices get their number as hash value
uint stringHash = ::toArrayIndex(ch, end);
if (stringHash != UINT_MAX)
return stringHash;
uint h = 0xffffffff;
while (ch < end) {
if ((uchar)(*ch) >= 0x80)
return UINT_MAX;
h = 31 * h + *ch;
++ch;
}
return h;
return calculateHashValue(ch, end, subtype);
}
uint String::getLength(const Managed *m)

View File

@ -183,8 +183,8 @@ struct Q_QML_PRIVATE_EXPORT String : public Managed {
void makeIdentifierImpl(ExecutionEngine *e) const;
static uint createHashValue(const QChar *ch, int length);
static uint createHashValue(const char *ch, int length);
static uint createHashValue(const QChar *ch, int length, uint *subtype);
static uint createHashValue(const char *ch, int length, uint *subtype);
bool startsWithUpper() const {
const String::Data *l = d();

View File

@ -174,7 +174,7 @@ public:
inline DiagnosticMessage diagnosticMessage() const
{
foreach (const DiagnosticMessage &d, diagnostic_messages) {
for (const DiagnosticMessage &d : diagnostic_messages) {
if (d.kind != DiagnosticMessage::Warning)
return d;
}

View File

@ -41,12 +41,12 @@
inline quint32 stringHash(const QChar* data, int length)
{
return QV4::String::createHashValue(data, length);
return QV4::String::createHashValue(data, length, Q_NULLPTR);
}
inline quint32 stringHash(const char *data, int length)
{
return QV4::String::createHashValue(data, length);
return QV4::String::createHashValue(data, length, Q_NULLPTR);
}
void QHashedString::computeHash() const

View File

@ -168,7 +168,7 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
return;
}
QQmlBindingProfiler prof(ep->profiler, f);
QQmlBindingProfiler prof(ep->profiler, this, f);
setUpdatingFlag(true);
QQmlJavaScriptExpression::DeleteWatcher watcher(this);

View File

@ -56,7 +56,6 @@
#include <private/qv4value_p.h>
#include <QtCore/qstringbuilder.h>
#include <QtCore/qdebug.h>
@ -81,9 +80,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
// Add some leading whitespace to account for the binding's column offset.
// It's 2 off because a, we start counting at 1 and b, the '(' below is not counted.
function.fill(QChar(QChar::Space), qMax(column, (quint16)2) - 2);
function += QStringLiteral("(function ");
function += handlerName;
function += QLatin1Char('(');
function += QStringLiteral("(function ") + handlerName + QLatin1Char('(');
if (parameterString.isEmpty()) {
QString error;
@ -99,10 +96,7 @@ QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
} else
function += parameterString;
function += QStringLiteral(") { ");
function += expression;
function += QStringLiteral(" })");
function += QStringLiteral(") { ") + expression + QStringLiteral(" })");
m_function.set(v4, evalFunction(context(), scopeObject(), function, fileName, line));
if (m_function.isNullOrUndefined())

View File

@ -89,8 +89,6 @@ public:
QQmlEngine *engine;
QString fileName() const { return compilationUnit->fileName(); }
QUrl url() const { return compilationUnit->url(); }
QQmlTypeNameCache *importCache;
int metaTypeId;

View File

@ -570,7 +570,7 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, QQmlCompiledData *cc, int start
d->cc = cc;
cc->addref();
d->start = start;
d->url = cc->url();
d->url = cc->compilationUnit->url();
d->progress = 1.0;
}

View File

@ -293,7 +293,7 @@ inline void QQmlEnginePrivate::dereferenceScarceResources()
// if the refcount is zero, then evaluation of the "top level"
// expression must have completed. We can safely release the
// scarce resources.
if (scarceResourcesRefCount == 0) {
if (Q_LIKELY(scarceResourcesRefCount == 0)) {
QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine());
if (Q_UNLIKELY(!engine->scarceResources.isEmpty())) {
cleanupScarceResources();

View File

@ -43,6 +43,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
#include <QtCore/qstringlist.h>
#include <QtCore/qvector.h>
#include <private/qv4errorobject_p.h>
@ -288,11 +289,11 @@ QDebug operator<<(QDebug debug, const QQmlError &error)
stream.setCodec("UTF-8");
#endif
const QString code = stream.readAll();
const QStringList lines = code.split(QLatin1Char('\n'));
const auto lines = code.splitRef(QLatin1Char('\n'));
if (lines.count() >= error.line()) {
const QString &line = lines.at(error.line() - 1);
debug << "\n " << qPrintable(line);
const QStringRef &line = lines.at(error.line() - 1);
debug << "\n " << line.toLocal8Bit().constData();
if(error.column() > 0) {
int column = qMax(0, error.column() - 1);

View File

@ -66,7 +66,7 @@ public:
Q_DECLARE_INTERFACE(QQmlTypesExtensionInterface, "org.qt-project.Qt.QQmlTypesExtensionInterface/1.0")
#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface"
#define QQmlExtensionInterface_iid "org.qt-project.Qt.QQmlExtensionInterface/1.0"
Q_DECLARE_INTERFACE(QQmlExtensionInterface, QQmlExtensionInterface_iid)

View File

@ -605,7 +605,7 @@ QString QQmlFile::urlToLocalFileOrQrc(const QString& url)
{
if (url.startsWith(QLatin1String("qrc:"), Qt::CaseInsensitive)) {
if (url.length() > 4)
return QLatin1Char(':') + url.mid(4);
return QLatin1Char(':') + url.midRef(4);
return QString();
}

View File

@ -85,12 +85,11 @@ QString resolveLocalUrl(const QString &url, const QString &relative)
} else if (relative.at(0) == Slash || !url.contains(Slash)) {
return relative;
} else {
QString base(url.left(url.lastIndexOf(Slash) + 1));
const QStringRef baseRef = url.leftRef(url.lastIndexOf(Slash) + 1);
if (relative == QLatin1String("."))
return base;
return baseRef.toString();
base.append(relative);
QString base = baseRef + relative;
// Remove any relative directory elements in the path
int length = base.length();
@ -192,7 +191,7 @@ void qmlClearEnginePlugins()
{
StringRegisteredPluginMap *plugins = qmlEnginePluginsWithRegisteredTypes();
QMutexLocker lock(&plugins->mutex);
foreach (RegisteredPlugin plugin, plugins->values()) {
for (auto &plugin : qAsConst(*plugins)) {
QPluginLoader* loader = plugin.loader;
if (loader && !loader->unload())
qWarning("Unloading %s failed: %s", qPrintable(plugin.uri), qPrintable(loader->errorString()));
@ -303,7 +302,7 @@ public:
int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence = false);
#ifndef QT_NO_LIBRARY
bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri,
bool populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
const QString &qmldirPath, QList<QQmlError> *errors);
#endif
};
@ -483,20 +482,58 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
return scripts;
}
/*!
Form a complete path to a qmldir file, from a base URL, a module URI and version specification.
*/
QString QQmlImports::completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin,
ImportVersion version)
static QString joinStringRefs(const QVector<QStringRef> &refs, const QChar &sep)
{
QString url = uri;
url.replace(Dot, Slash);
QString str;
for (auto it = refs.cbegin(); it != refs.cend(); ++it) {
if (it != refs.cbegin())
str += sep;
str += *it;
}
return str;
}
QString dir = base;
if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
dir += Slash;
/*!
Forms complete paths to a qmldir file, from a base URL, a module URI and version specification.
return dir + url + versionString(vmaj, vmin, version) + Slash_qmldir;
For example, QtQml.Models 2.0:
- base/QtQml/Models.2.0/qmldir
- base/QtQml.2.0/Models/qmldir
- base/QtQml/Models.2/qmldir
- base/QtQml.2/Models/qmldir
- base/QtQml/Models/qmldir
*/
QStringList QQmlImports::completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin)
{
const QVector<QStringRef> parts = uri.splitRef(Dot, QString::SkipEmptyParts);
QStringList qmlDirPathsPaths;
// fully & partially versioned parts + 1 unversioned for each base path
qmlDirPathsPaths.reserve(basePaths.count() * (2 * parts.count() + 1));
for (int version = FullyVersioned; version <= Unversioned; ++version) {
const QString ver = versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
for (const QString &path : basePaths) {
QString dir = path;
if (!dir.endsWith(Slash) && !dir.endsWith(Backslash))
dir += Slash;
// append to the end
qmlDirPathsPaths += dir + joinStringRefs(parts, Slash) + ver + Slash_qmldir;
if (version != Unversioned) {
// insert in the middle
for (int index = parts.count() - 2; index >= 0; --index) {
qmlDirPathsPaths += dir + joinStringRefs(parts.mid(0, index + 1), Slash)
+ ver + Slash
+ joinStringRefs(parts.mid(index + 1), Slash) + Slash_qmldir;
}
}
}
}
return qmlDirPathsPaths;
}
QString QQmlImports::versionString(int vmaj, int vmin, ImportVersion version)
@ -777,11 +814,11 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
QString u1 = import->url;
QString u2 = import2->url;
if (base) {
QString b = *base;
QStringRef b(base);
int dot = b.lastIndexOf(Dot);
if (dot >= 0) {
b = b.left(dot+1);
QString l = b.left(dot);
QStringRef l = b.left(dot);
if (u1.startsWith(b))
u1 = u1.mid(b.count());
else if (u1 == l)
@ -841,14 +878,34 @@ QQmlImportNamespace *QQmlImportsPrivate::findQualifiedNamespace(const QHashedStr
return 0;
}
/*!
Returns the list of possible versioned URI combinations. For example, if \a uri is
QtQml.Models, \a vmaj is 2, and \a vmin is 0, this method returns the following:
[QtQml.Models.2.0, QtQml.2.0.Models, QtQml.Models.2, QtQml.2.Models, QtQml.Models]
*/
static QStringList versionUriList(const QString &uri, int vmaj, int vmin)
{
QStringList result;
for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
int index = uri.length();
do {
QString versionUri = uri;
versionUri.insert(index, QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version)));
result += versionUri;
index = uri.lastIndexOf(Dot, index - 1);
} while (index > 0 && version != QQmlImports::Unversioned);
}
return result;
}
#ifndef QT_NO_LIBRARY
/*!
Get all static plugins that are QML plugins and has a meta data URI that begins with \a uri.
Note that if e.g uri == "a", and different plugins have meta data "a", "a.2.1", "a.b.c", all
will be added to the result. So the result needs further version matching by the caller.
Get all static plugins that are QML plugins and has a meta data URI that matches with one of
\a versionUris, which is a list of all possible versioned URI combinations - see versionUriList()
above.
*/
bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri,
bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &result, const QString &uri, const QStringList &versionUris,
const QString &qmldirPath, QList<QQmlError> *errors)
{
static QVector<QStaticPlugin> plugins;
@ -856,8 +913,8 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
// To avoid traversing all static plugins for all imports, we cut down
// the list the first time called to only contain QML plugins:
foreach (const QStaticPlugin &plugin, QPluginLoader::staticPlugins()) {
if (qobject_cast<QQmlExtensionPlugin *>(plugin.instance()))
plugins.append(plugin);
if (plugin.metaData().value(QStringLiteral("IID")).toString() == QLatin1String(QQmlExtensionInterface_iid))
plugins.append(plugin);
}
}
@ -877,7 +934,7 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
}
// A plugin can be set up to handle multiple URIs, so go through the list:
foreach (const QJsonValue &metaTagUri, metaTagsUriList) {
if (metaTagUri.toString().startsWith(uri)) {
if (versionUris.contains(metaTagUri.toString())) {
result.append(qMakePair(plugin, metaTagsUriList));
break;
}
@ -970,14 +1027,13 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
// versioned to unversioned, we need to compare with differnt version strings. If a module
// has several plugins, they must all have the same version. Start by populating pluginPairs
// with relevant plugins to cut the list short early on:
const QStringList versionUris = versionUriList(uri, vmaj, vmin);
QVector<StaticPluginPair> pluginPairs;
if (!populatePluginPairVector(pluginPairs, uri, qmldirFilePath, errors))
if (!populatePluginPairVector(pluginPairs, uri, versionUris, qmldirFilePath, errors))
return false;
const QString basePath = QFileInfo(qmldirPath).absoluteFilePath();
for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned && staticPluginsFound == 0; ++version) {
QString versionUri = uri + QQmlImports::versionString(vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
for (const QString &versionUri : versionUris) {
foreach (const StaticPluginPair &pair, pluginPairs) {
foreach (const QJsonValue &metaTagUri, pair.second) {
if (versionUri == metaTagUri.toString()) {
@ -998,6 +1054,8 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
}
}
if (staticPluginsFound > 0)
break;
}
}
@ -1130,32 +1188,29 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
QStringList localImportPaths = database->importPathList(QQmlImportDatabase::Local);
// Search local import paths for a matching version
for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
foreach (const QString &path, localImportPaths) {
QString qmldirPath = QQmlImports::completeQmldirPath(uri, path, vmaj, vmin, static_cast<QQmlImports::ImportVersion>(version));
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(uri, localImportPaths, vmaj, vmin);
for (const QString &qmldirPath : qmlDirPaths) {
QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
if (!absoluteFilePath.isEmpty()) {
QString url;
const QStringRef absolutePath = absoluteFilePath.leftRef(absoluteFilePath.lastIndexOf(Slash) + 1);
if (absolutePath.at(0) == Colon)
url = QLatin1String("qrc://") + absolutePath.mid(1);
else
url = QUrl::fromLocalFile(absolutePath.toString()).toString();
QString absoluteFilePath = typeLoader.absoluteFilePath(qmldirPath);
if (!absoluteFilePath.isEmpty()) {
QString url;
QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1);
if (absolutePath.at(0) == Colon)
url = QLatin1String("qrc://") + absolutePath.mid(1);
else
url = QUrl::fromLocalFile(absolutePath).toString();
QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
cache->versionMajor = vmaj;
cache->versionMinor = vmin;
cache->qmldirFilePath = absoluteFilePath;
cache->qmldirPathUrl = url;
cache->next = cacheHead;
database->qmldirCache.insert(uri, cache);
QQmlImportDatabase::QmldirCache *cache = new QQmlImportDatabase::QmldirCache;
cache->versionMajor = vmaj;
cache->versionMinor = vmin;
cache->qmldirFilePath = absoluteFilePath;
cache->qmldirPathUrl = url;
cache->next = cacheHead;
database->qmldirCache.insert(uri, cache);
*outQmldirFilePath = absoluteFilePath;
*outQmldirPathUrl = url;
*outQmldirFilePath = absoluteFilePath;
*outQmldirPathUrl = url;
return true;
}
return true;
}
}
@ -1647,10 +1702,7 @@ QString QQmlImportDatabase::resolvePlugin(QQmlTypeLoader *typeLoader,
resolvedPath += Slash;
foreach (const QString &suffix, suffixes) {
QString pluginFileName = prefix;
pluginFileName += baseName;
pluginFileName += suffix;
QString pluginFileName = prefix + baseName + suffix;
QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName);
if (!absolutePath.isEmpty())

View File

@ -130,8 +130,7 @@ public:
QList<CompositeSingletonReference> resolvedCompositeSingletons() const;
static QString completeQmldirPath(const QString &uri, const QString &base, int vmaj, int vmin,
QQmlImports::ImportVersion version);
static QStringList completeQmldirPaths(const QString &uri, const QStringList &basePaths, int vmaj, int vmin);
static QString versionString(int vmaj, int vmin, ImportVersion version);
static bool isLocal(const QString &url);

View File

@ -281,7 +281,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!compiledData)
return;
QML_MEMORY_SCOPE_URL(compiledData->url());
QML_MEMORY_SCOPE_URL(compiledData->compilationUnit->url());
QExplicitlySharedDataPointer<QQmlIncubatorPrivate> protectThis(this);
@ -292,7 +292,7 @@ void QQmlIncubatorPrivate::incubate(QQmlInstantiationInterrupt &i)
if (!vmeGuard.isOK()) {
QQmlError error;
error.setUrl(compiledData->url());
error.setUrl(compiledData->compilationUnit->url());
error.setDescription(QQmlComponent::tr("Object destroyed during incubation"));
errors << error;
progress = QQmlIncubatorPrivate::Completed;

View File

@ -1914,14 +1914,11 @@ QList<QQmlType*> QQmlMetaType::qmlSingletonTypes()
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
QList<QQmlType*> alltypes = data->nameToType.values();
QList<QQmlType*> retn;
foreach (QQmlType* t, alltypes) {
if (t->isSingleton()) {
retn.append(t);
}
for (const auto type : qAsConst(data->nameToType)) {
if (type->isSingleton())
retn.append(type);
}
return retn;
}
@ -1929,9 +1926,9 @@ const QQmlPrivate::CachedQmlUnit *QQmlMetaType::findCachedCompilationUnit(const
{
QMutexLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
for (QVector<QQmlPrivate::QmlUnitCacheLookupFunction>::ConstIterator it = data->lookupCachedQmlUnit.constBegin(), end = data->lookupCachedQmlUnit.constEnd();
it != end; ++it) {
if (const QQmlPrivate::CachedQmlUnit *unit = (*it)(uri))
for (const auto lookup : qAsConst(data->lookupCachedQmlUnit)) {
if (const QQmlPrivate::CachedQmlUnit *unit = lookup(uri))
return unit;
}
return 0;
@ -1961,8 +1958,7 @@ QString QQmlMetaType::prettyTypeName(const QObject *object)
marker = typeName.indexOf(QLatin1String("_QML_"));
if (marker != -1) {
typeName = typeName.left(marker);
typeName += QLatin1Char('*');
typeName = typeName.left(marker) + QLatin1Char('*');
type = QQmlMetaType::qmlType(QMetaType::type(typeName.toLatin1()));
if (type) {
typeName = type->qmlTypeName();

View File

@ -375,7 +375,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
QString string = binding->valueAsString(qmlUnit);
// Encoded dir-separators defeat QUrl processing - decode them first
string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
QUrl value = string.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(string));
QUrl value = string.isEmpty() ? QUrl() : compiledData->compilationUnit->url().resolved(QUrl(string));
// Apply URL interceptor
if (engine->urlInterceptor())
value = engine->urlInterceptor()->intercept(value, QQmlAbstractUrlInterceptor::UrlString);
@ -570,7 +570,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const
} else if (property->propType == qMetaTypeId<QList<QUrl> >()) {
Q_ASSERT(binding->type == QV4::CompiledData::Binding::Type_String);
QString urlString = binding->valueAsString(qmlUnit);
QUrl u = urlString.isEmpty() ? QUrl() : compiledData->url().resolved(QUrl(urlString));
QUrl u = urlString.isEmpty() ? QUrl() : compiledData->compilationUnit->url().resolved(QUrl(urlString));
QList<QUrl> value;
value.append(u);
argv[0] = reinterpret_cast<void *>(&value);
@ -664,7 +664,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip)
if (qmlTypeForObject(_bindingTarget)) {
quint32 bindingSkipList = 0;
QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultProperty != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
QQmlPropertyData *defaultProperty = _compiledObject->indexOfDefaultPropertyOrAlias != -1 ? _propertyCache->parent()->defaultProperty() : _propertyCache->defaultProperty();
const QV4::CompiledData::Binding *binding = _compiledObject->bindingTable();
for (quint32 i = 0; i < _compiledObject->nBindings; ++i, ++binding) {
@ -999,7 +999,7 @@ void QQmlObjectCreator::setupFunctions()
void QQmlObjectCreator::recordError(const QV4::CompiledData::Location &location, const QString &description)
{
QQmlError error;
error.setUrl(compiledData->url());
error.setUrl(compiledData->compilationUnit->url());
error.setLine(location.line);
error.setColumn(location.column);
error.setDescription(description);
@ -1037,8 +1037,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (compiledData->isComponent(index)) {
isComponent = true;
QQmlComponent *component = new QQmlComponent(engine, compiledData, index, parent);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(QStringLiteral("<component>"),
context->url(), obj->location.line, obj->location.column));
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
compiledData, obj, QStringLiteral("<component>"), context->url()));
QQmlComponentPrivate::get(component)->creationContext = context;
instance = component;
ddata = QQmlData::get(instance, /*create*/true);
@ -1048,8 +1048,8 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
installPropertyCache = !typeRef->isFullyDynamicType;
QQmlType *type = typeRef->type;
if (type) {
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(type->qmlTypeName(),
context->url(), obj->location.line, obj->location.column));
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
compiledData, obj, type->qmlTypeName(), context->url()));
instance = type->create();
if (!instance) {
recordError(obj->location, tr("Unable to create object of type %1").arg(stringAt(obj->inheritedTypeNameIndex)));
@ -1071,8 +1071,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
sharedState->allCreatedObjects.push(instance);
} else {
Q_ASSERT(typeRef->component);
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(typeRef->component->fileName(),
context->url(), obj->location.line, obj->location.column));
Q_QML_OC_PROFILE(sharedState->profiler, profiler.update(
compiledData, obj, typeRef->component->compilationUnit->fileName(),
context->url()));
if (typeRef->component->compilationUnit->data->isSingleton())
{
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
@ -1115,7 +1116,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
parserStatus->classBegin();
// push() the profiler state here, together with the parserStatus, as we'll pop() them
// together, too.
Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(profiler));
Q_QML_OC_PROFILE(sharedState->profiler, sharedState->profiler.push(obj));
sharedState->allParserStatusCallbacks.push(parserStatus);
parserStatus->d = &sharedState->allParserStatusCallbacks.top();
}
@ -1288,7 +1289,7 @@ bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QObject *
if (!data.isEmpty()) {
Q_ASSERT(!cache.isNull());
// install on _object
vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()));
vmeMetaObject = new QQmlVMEMetaObject(_qobject, cache, reinterpret_cast<const QQmlVMEMetaData*>(data.constData()), compiledData->compilationUnit, _compiledObjectIndex);
if (_ddata->propertyCache)
_ddata->propertyCache->release();
_ddata->propertyCache = cache;

View File

@ -58,6 +58,7 @@
#include <private/qv4functionobject_p.h>
#include <QStringList>
#include <QVector>
#include <private/qmetaobject_p.h>
#include <private/qqmlvaluetypewrapper_p.h>
#include <QtCore/qdebug.h>
@ -240,14 +241,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlTypeNameCache *typeNameCache = context?context->imports:0;
QStringList path = name.split(QLatin1Char('.'));
const auto path = name.splitRef(QLatin1Char('.'));
if (path.isEmpty()) return;
QObject *currentObject = obj;
// Everything up to the last property must be an "object type" property
for (int ii = 0; ii < path.count() - 1; ++ii) {
const QString &pathName = path.at(ii);
const QStringRef &pathName = path.at(ii);
if (typeNameCache) {
QQmlTypeNameCache::Result r = typeNameCache->query(pathName);
@ -284,7 +285,7 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
QQmlPropertyData local;
QQmlPropertyData *property =
QQmlPropertyCache::property(engine, currentObject, pathName, context, local);
QQmlPropertyCache::property(engine, currentObject, pathName.toString(), context, local);
if (!property) return; // Not a property
if (property->isFunction())
@ -324,14 +325,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
}
const QString &terminal = path.last();
const QStringRef &terminal = path.last();
if (terminal.count() >= 3 &&
terminal.at(0) == QLatin1Char('o') &&
terminal.at(1) == QLatin1Char('n') &&
terminal.at(2).isUpper()) {
QString signalName = terminal.mid(2);
QString signalName = terminal.mid(2).toString();
signalName[0] = signalName.at(0).toLower();
// XXX - this code treats methods as signals
@ -376,13 +377,14 @@ void QQmlPropertyPrivate::initProperty(QObject *obj, const QString &name)
}
// Property
const QString terminalString = terminal.toString();
QQmlPropertyData local;
QQmlPropertyData *property =
QQmlPropertyCache::property(engine, currentObject, terminal, context, local);
QQmlPropertyCache::property(engine, currentObject, terminalString, context, local);
if (property && !property->isFunction()) {
object = currentObject;
core = *property;
nameCache = terminal;
nameCache = terminalString;
isNameCached = true;
}
}

View File

@ -661,7 +661,7 @@ void QQmlDataBlob::notifyComplete(QQmlDataBlob *blob)
Q_ASSERT(m_waitingFor.contains(blob));
Q_ASSERT(blob->status() == Error || blob->status() == Complete);
QQmlCompilingProfiler prof(QQmlEnginePrivate::get(typeLoader()->engine())->profiler,
blob->url());
blob);
m_inCallback = true;
@ -1121,6 +1121,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob)
}
#define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16
#define TYPELOADER_MINIMUM_TRIM_THRESHOLD 64
#ifndef QT_NO_NETWORK
void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply)
@ -1225,7 +1226,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, QQmlFile *file)
void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url());
QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob);
blob->m_inCallback = true;
@ -1245,7 +1246,7 @@ void QQmlTypeLoader::setData(QQmlDataBlob *blob, const QQmlDataBlob::Data &d)
void QQmlTypeLoader::setCachedUnit(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit)
{
QML_MEMORY_SCOPE_URL(blob->url());
QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob->url());
QQmlCompilingProfiler prof(QQmlEnginePrivate::get(engine())->profiler, blob);
blob->m_inCallback = true;
@ -1398,13 +1399,10 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
// Probe for all possible locations
int priority = 0;
for (int version = QQmlImports::FullyVersioned; version <= QQmlImports::Unversioned; ++version) {
foreach (const QString &path, remotePathList) {
QString qmldirUrl = QQmlImports::completeQmldirPath(importUri, path, import->majorVersion, import->minorVersion,
static_cast<QQmlImports::ImportVersion>(version));
if (!fetchQmldir(QUrl(qmldirUrl), import, ++priority, errors))
return false;
}
const QStringList qmlDirPaths = QQmlImports::completeQmldirPaths(importUri, remotePathList, import->majorVersion, import->minorVersion);
for (const QString &qmldirPath : qmlDirPaths) {
if (!fetchQmldir(QUrl(qmldirPath), import, ++priority, errors))
return false;
}
}
}
@ -1602,7 +1600,8 @@ bool QQmlTypeLoader::QmldirContent::designerSupported() const
Constructs a new type loader that uses the given \a engine.
*/
QQmlTypeLoader::QQmlTypeLoader(QQmlEngine *engine)
: m_engine(engine), m_thread(new QQmlTypeLoaderThread(this))
: m_engine(engine), m_thread(new QQmlTypeLoaderThread(this)),
m_typeCacheTrimThreshold(TYPELOADER_MINIMUM_TRIM_THRESHOLD)
{
}
@ -1639,6 +1638,10 @@ QQmlTypeData *QQmlTypeLoader::getType(const QUrl &url, Mode mode)
QQmlTypeData *typeData = m_typeCache.value(url);
if (!typeData) {
// Trim before adding the new type, so that we don't immediately trim it away
if (m_typeCache.size() >= m_typeCacheTrimThreshold)
trimCache();
typeData = new QQmlTypeData(url, this);
// TODO: if (compiledData == 0), is it safe to omit this insertion?
m_typeCache.insert(url, typeData);
@ -1943,12 +1946,22 @@ void QQmlTypeLoader::clearCache()
qDeleteAll(m_importQmlDirCache);
m_typeCache.clear();
m_typeCacheTrimThreshold = TYPELOADER_MINIMUM_TRIM_THRESHOLD;
m_scriptCache.clear();
m_qmldirCache.clear();
m_importDirCache.clear();
m_importQmlDirCache.clear();
}
void QQmlTypeLoader::updateTypeCacheTrimThreshold()
{
int size = m_typeCache.size();
if (size > m_typeCacheTrimThreshold)
m_typeCacheTrimThreshold = size * 2;
if (size < m_typeCacheTrimThreshold / 2)
m_typeCacheTrimThreshold = qMax(size * 2, TYPELOADER_MINIMUM_TRIM_THRESHOLD);
}
void QQmlTypeLoader::trimCache()
{
while (true) {
@ -1973,6 +1986,8 @@ void QQmlTypeLoader::trimCache()
}
}
updateTypeCacheTrimThreshold();
// TODO: release any scripts which are no longer referenced by any types
}

View File

@ -374,6 +374,7 @@ private:
NetworkReplies m_networkReplies;
#endif
TypeCache m_typeCache;
int m_typeCacheTrimThreshold;
ScriptCache m_scriptCache;
QmldirCache m_qmldirCache;
ImportDirCache m_importDirCache;
@ -381,6 +382,7 @@ private:
template<typename Loader>
void doLoad(const Loader &loader, QQmlDataBlob *blob, Mode mode);
void updateTypeCacheTrimThreshold();
friend struct PlainLoader;
friend struct CachedLoader;

View File

@ -50,6 +50,7 @@
#include <private/qv4functionobject_p.h>
#include <private/qv4variantobject_p.h>
#include <private/qv4alloca_p.h>
#include <private/qv4objectiterator_p.h>
QT_BEGIN_NAMESPACE
@ -244,6 +245,34 @@ PropertyAttributes QQmlValueTypeWrapper::query(const Managed *m, String *name)
return result ? Attr_Data : Attr_Invalid;
}
void QQmlValueTypeWrapper::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{
name->setM(0);
*index = UINT_MAX;
QQmlValueTypeWrapper *that = static_cast<QQmlValueTypeWrapper*>(m);
if (QQmlValueTypeReference *ref = that->as<QQmlValueTypeReference>()) {
if (!ref->readReferenceValue())
return;
}
if (that->d()->propertyCache) {
const QMetaObject *mo = that->d()->propertyCache->createMetaObject();
const int propertyCount = mo->propertyCount();
if (it->arrayIndex < static_cast<uint>(propertyCount)) {
Scope scope(that->engine());
ScopedString propName(scope, that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name())));
name->setM(propName->d());
++it->arrayIndex;
*attributes = QV4::Attr_Data;
p->value = that->QV4::Object::get(propName);
return;
}
}
QV4::Object::advanceIterator(m, it, name, index, p, attributes);
}
bool QQmlValueTypeWrapper::isEqual(const QVariant& value)
{
if (QQmlValueTypeReference *ref = as<QQmlValueTypeReference>())
@ -302,8 +331,7 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx)
if (QMetaType::convert(w->d()->gadgetPtr, w->d()->valueType->typeId, &convertResult, QMetaType::QString)) {
result = convertResult;
} else {
result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId));
result += QLatin1Char('(');
result = QString::fromUtf8(QMetaType::typeName(w->d()->valueType->typeId)) + QLatin1Char('(');
const QMetaObject *mo = w->d()->propertyCache->metaObject();
const int propCount = mo->propertyCount();
for (int i = 0; i < propCount; ++i) {

View File

@ -99,6 +99,7 @@ public:
static void put(Managed *m, String *name, const Value &value);
static bool isEqualTo(Managed *m, Managed *other);
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static QV4::ReturnedValue method_toString(CallContext *ctx);

View File

@ -64,8 +64,6 @@
#include <private/qqmlengine_p.h>
#include <private/qfinitestack_p.h>
#include <private/qqmlprofiler_p.h>
QT_BEGIN_NAMESPACE
class QObject;

View File

@ -99,10 +99,10 @@ void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
return;
if (m_index >= 0) {
QV4::ExecutionEngine *v4 = m_target->properties.engine();
QV4::ExecutionEngine *v4 = m_target->propertyAndMethodStorage.engine();
if (v4) {
QV4::Scope scope(v4);
QV4::Scoped<QV4::MemberData> sp(scope, m_target->properties.value());
QV4::Scoped<QV4::MemberData> sp(scope, m_target->propertyAndMethodStorage.value());
if (sp)
*(sp->data() + m_index) = QV4::Primitive::nullValue();
}
@ -140,17 +140,19 @@ void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *e, void **)
void QQmlVMEMetaObjectEndpoint::tryConnect()
{
Q_ASSERT(metaObject->compiledObject);
int aliasId = this - metaObject->aliasEndpoints;
if (metaObject.flag()) {
// This is actually notify
int sigIdx = metaObject->methodOffset() + aliasId + metaObject->metaData->propertyCount;
int sigIdx = metaObject->methodOffset() + aliasId + metaObject->compiledObject->nProperties;
metaObject->activate(metaObject->object, sigIdx, 0);
} else {
const QV4::CompiledData::Alias *aliasData = &metaObject->compiledObject->aliasTable()[aliasId];
QQmlVMEMetaData::AliasData *d = metaObject->metaData->aliasData() + aliasId;
if (!d->isObjectAlias()) {
if (!aliasData->isObjectAlias()) {
QQmlContextData *ctxt = metaObject->ctxt;
QObject *target = ctxt->idValues[d->contextIdx].data();
QObject *target = ctxt->idValues[aliasData->targetObjectId].data();
if (!target)
return;
@ -304,135 +306,128 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje
QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
QQmlPropertyCache *cache,
const QQmlVMEMetaData *meta)
const QQmlVMEMetaData *meta, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId)
: QQmlInterceptorMetaObject(obj, cache),
ctxt(QQmlData::get(obj, true)->outerContext), metaData(meta),
aliasEndpoints(0),
methods(0)
aliasEndpoints(0), compilationUnit(qmlCompilationUnit), compiledObject(0)
{
cache->addref();
QQmlData::get(obj)->hasVMEMetaObject = true;
int qobject_type = qMetaTypeId<QObject*>();
int variant_type = qMetaTypeId<QVariant>();
// Need JS wrapper to ensure properties are marked.
// ### FIXME: I hope that this can be removed once we have the proper scope chain
// set up and the JS wrappers always exist.
bool needsJSWrapper = (metaData->propertyCount > 0);
if (compilationUnit && qmlObjectId >= 0) {
compiledObject = compilationUnit->data->objectAt(qmlObjectId);
// ### Optimize
for (int ii = 0; ii < metaData->propertyCount; ++ii) {
int t = (metaData->propertyData() + ii)->propertyType;
if (t == qobject_type || t == variant_type) {
needsJSWrapper = true;
break;
if (compiledObject->nProperties || compiledObject->nFunctions) {
Q_ASSERT(cache && cache->engine);
QV4::ExecutionEngine *v4 = cache->engine;
QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions);
propertyAndMethodStorage.set(v4, data);
std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
// Need JS wrapper to ensure properties/methods are marked.
ensureQObjectWrapper();
}
}
if (needsJSWrapper)
ensureQObjectWrapper();
}
QQmlVMEMetaObject::~QQmlVMEMetaObject()
{
if (parent.isT1()) parent.asT1()->objectDestroyed(object);
delete [] aliasEndpoints;
delete [] methods;
qDeleteAll(varObjectGuards);
cache->release();
}
QV4::MemberData *QQmlVMEMetaObject::propertiesAsMemberData()
QV4::MemberData *QQmlVMEMetaObject::propertyAndMethodStorageAsMemberData()
{
if (properties.isUndefined()) {
if (properties.valueRef())
if (propertyAndMethodStorage.isUndefined()) {
if (propertyAndMethodStorage.valueRef())
// in some situations, the QObject wrapper (and associated data,
// such as the varProperties array) will have been cleaned up, but the
// QObject ptr will not yet have been deleted (eg, waiting on deleteLater).
// In this situation, return 0.
return 0;
allocateProperties();
}
return static_cast<QV4::MemberData*>(properties.asManaged());
return static_cast<QV4::MemberData*>(propertyAndMethodStorage.asManaged());
}
void QQmlVMEMetaObject::writeProperty(int id, int v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::Primitive::fromInt32(v);
}
void QQmlVMEMetaObject::writeProperty(int id, bool v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::Primitive::fromBoolean(v);
}
void QQmlVMEMetaObject::writeProperty(int id, double v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::Primitive::fromDouble(v);
}
void QQmlVMEMetaObject::writeProperty(int id, const QString& v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newString(v);
}
void QQmlVMEMetaObject::writeProperty(int id, const QUrl& v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDate& v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QDateTime& v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QPointF& v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QSizeF& v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, const QRectF& v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = cache->engine->newVariantObject(QVariant::fromValue(v));
}
void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
*(md->data() + id) = QV4::QObjectWrapper::wrap(cache->engine, v);
@ -447,7 +442,7 @@ void QQmlVMEMetaObject::writeProperty(int id, QObject* v)
int QQmlVMEMetaObject::readPropertyAsInt(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0;
@ -460,7 +455,7 @@ int QQmlVMEMetaObject::readPropertyAsInt(int id)
bool QQmlVMEMetaObject::readPropertyAsBool(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return false;
@ -473,7 +468,7 @@ bool QQmlVMEMetaObject::readPropertyAsBool(int id)
double QQmlVMEMetaObject::readPropertyAsDouble(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0.0;
@ -486,7 +481,7 @@ double QQmlVMEMetaObject::readPropertyAsDouble(int id)
QString QQmlVMEMetaObject::readPropertyAsString(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QString();
@ -499,7 +494,7 @@ QString QQmlVMEMetaObject::readPropertyAsString(int id)
QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QUrl();
@ -513,7 +508,7 @@ QUrl QQmlVMEMetaObject::readPropertyAsUrl(int id)
QDate QQmlVMEMetaObject::readPropertyAsDate(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QDate();
@ -527,7 +522,7 @@ QDate QQmlVMEMetaObject::readPropertyAsDate(int id)
QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QDateTime();
@ -541,7 +536,7 @@ QDateTime QQmlVMEMetaObject::readPropertyAsDateTime(int id)
QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QSizeF();
@ -555,7 +550,7 @@ QSizeF QQmlVMEMetaObject::readPropertyAsSizeF(int id)
QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QPointF();
@ -569,7 +564,7 @@ QPointF QQmlVMEMetaObject::readPropertyAsPointF(int id)
QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0;
@ -583,7 +578,7 @@ QObject* QQmlVMEMetaObject::readPropertyAsQObject(int id)
QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return 0;
@ -599,7 +594,7 @@ QList<QObject *> *QQmlVMEMetaObject::readPropertyAsList(int id)
QRectF QQmlVMEMetaObject::readPropertyAsRectF(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QRectF();
@ -621,15 +616,20 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (intercept(c, _id, a))
return -1;
const int propertyCount = compiledObject ? int(compiledObject->nProperties) : 0;
const int aliasCount = compiledObject ? int(compiledObject->nAliases) : 0;
const int signalCount = compiledObject ? int(compiledObject->nSignals) : 0;
const int methodCount = compiledObject ? int(compiledObject->nFunctions) : 0;
if (c == QMetaObject::ReadProperty || c == QMetaObject::WriteProperty || c == QMetaObject::ResetProperty) {
if (id >= propOffset()) {
id -= propOffset();
if (id < metaData->propertyCount) {
int t = (metaData->propertyData() + id)->propertyType;
if (id < propertyCount) {
const QV4::CompiledData::Property::Type t = static_cast<QV4::CompiledData::Property::Type>(compiledObject->propertyTable()[id].type);
bool needActivate = false;
if (t == QQmlVMEMetaData::VarPropertyType) {
if (t == QV4::CompiledData::Property::Var) {
// the context can be null if accessing var properties from cpp after re-parenting an item.
QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine();
@ -645,131 +645,179 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
}
} else {
int fallbackMetaType = QMetaType::UnknownType;
switch (t) {
case QV4::CompiledData::Property::Font:
fallbackMetaType = QMetaType::QFont;
break;
case QV4::CompiledData::Property::Time:
fallbackMetaType = QMetaType::QTime;
break;
case QV4::CompiledData::Property::Color:
fallbackMetaType = QMetaType::QColor;
break;
case QV4::CompiledData::Property::Vector2D:
fallbackMetaType = QMetaType::QVector2D;
break;
case QV4::CompiledData::Property::Vector3D:
fallbackMetaType = QMetaType::QVector3D;
break;
case QV4::CompiledData::Property::Vector4D:
fallbackMetaType = QMetaType::QVector4D;
break;
case QV4::CompiledData::Property::Matrix4x4:
fallbackMetaType = QMetaType::QMatrix4x4;
break;
case QV4::CompiledData::Property::Quaternion:
fallbackMetaType = QMetaType::QQuaternion;
break;
default: break;
}
if (c == QMetaObject::ReadProperty) {
switch(t) {
case QVariant::Int:
switch (t) {
case QV4::CompiledData::Property::Int:
*reinterpret_cast<int *>(a[0]) = readPropertyAsInt(id);
break;
case QVariant::Bool:
case QV4::CompiledData::Property::Bool:
*reinterpret_cast<bool *>(a[0]) = readPropertyAsBool(id);
break;
case QVariant::Double:
case QV4::CompiledData::Property::Real:
*reinterpret_cast<double *>(a[0]) = readPropertyAsDouble(id);
break;
case QVariant::String:
case QV4::CompiledData::Property::String:
*reinterpret_cast<QString *>(a[0]) = readPropertyAsString(id);
break;
case QVariant::Url:
case QV4::CompiledData::Property::Url:
*reinterpret_cast<QUrl *>(a[0]) = readPropertyAsUrl(id);
break;
case QVariant::Date:
case QV4::CompiledData::Property::Date:
*reinterpret_cast<QDate *>(a[0]) = readPropertyAsDate(id);
break;
case QVariant::DateTime:
case QV4::CompiledData::Property::DateTime:
*reinterpret_cast<QDateTime *>(a[0]) = readPropertyAsDateTime(id);
break;
case QVariant::RectF:
case QV4::CompiledData::Property::Rect:
*reinterpret_cast<QRectF *>(a[0]) = readPropertyAsRectF(id);
break;
case QVariant::SizeF:
case QV4::CompiledData::Property::Size:
*reinterpret_cast<QSizeF *>(a[0]) = readPropertyAsSizeF(id);
break;
case QVariant::PointF:
case QV4::CompiledData::Property::Point:
*reinterpret_cast<QPointF *>(a[0]) = readPropertyAsPointF(id);
break;
case QMetaType::QObjectStar:
case QV4::CompiledData::Property::Custom:
*reinterpret_cast<QObject **>(a[0]) = readPropertyAsQObject(id);
break;
case QMetaType::QVariant:
case QV4::CompiledData::Property::Variant:
*reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
break;
default:
{
if (t == qMetaTypeId<QQmlListProperty<QObject> >()) {
QList<QObject *> *list = readPropertyAsList(id);
QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
*p = QQmlListProperty<QObject>(object, list,
list_append, list_count, list_at,
list_clear);
p->dummy1 = this;
p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
} else {
QV4::MemberData *md = propertiesAsMemberData();
if (md) {
QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (v)
QQml_valueTypeProvider()->readValueType(v->d()->data, a[0], t);
}
}
case QV4::CompiledData::Property::CustomList: {
QList<QObject *> *list = readPropertyAsList(id);
QQmlListProperty<QObject> *p = static_cast<QQmlListProperty<QObject> *>(a[0]);
*p = QQmlListProperty<QObject>(object, list,
list_append, list_count, list_at,
list_clear);
p->dummy1 = this;
p->dummy2 = reinterpret_cast<void *>(quintptr(methodOffset() + id));
break;
}
case QV4::CompiledData::Property::Font:
case QV4::CompiledData::Property::Time:
case QV4::CompiledData::Property::Color:
case QV4::CompiledData::Property::Vector2D:
case QV4::CompiledData::Property::Vector3D:
case QV4::CompiledData::Property::Vector4D:
case QV4::CompiledData::Property::Matrix4x4:
case QV4::CompiledData::Property::Quaternion:
Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (v)
QQml_valueTypeProvider()->readValueType(v->d()->data, a[0], fallbackMetaType);
}
break;
case QV4::CompiledData::Property::Var:
Q_UNREACHABLE();
}
} else if (c == QMetaObject::WriteProperty) {
switch(t) {
case QVariant::Int:
case QV4::CompiledData::Property::Int:
needActivate = *reinterpret_cast<int *>(a[0]) != readPropertyAsInt(id);
writeProperty(id, *reinterpret_cast<int *>(a[0]));
break;
case QVariant::Bool:
case QV4::CompiledData::Property::Bool:
needActivate = *reinterpret_cast<bool *>(a[0]) != readPropertyAsBool(id);
writeProperty(id, *reinterpret_cast<bool *>(a[0]));
break;
case QVariant::Double:
case QV4::CompiledData::Property::Real:
needActivate = *reinterpret_cast<double *>(a[0]) != readPropertyAsDouble(id);
writeProperty(id, *reinterpret_cast<double *>(a[0]));
break;
case QVariant::String:
case QV4::CompiledData::Property::String:
needActivate = *reinterpret_cast<QString *>(a[0]) != readPropertyAsString(id);
writeProperty(id, *reinterpret_cast<QString *>(a[0]));
break;
case QVariant::Url:
case QV4::CompiledData::Property::Url:
needActivate = *reinterpret_cast<QUrl *>(a[0]) != readPropertyAsUrl(id);
writeProperty(id, *reinterpret_cast<QUrl *>(a[0]));
break;
case QVariant::Date:
case QV4::CompiledData::Property::Date:
needActivate = *reinterpret_cast<QDate *>(a[0]) != readPropertyAsDate(id);
writeProperty(id, *reinterpret_cast<QDate *>(a[0]));
break;
case QVariant::DateTime:
case QV4::CompiledData::Property::DateTime:
needActivate = *reinterpret_cast<QDateTime *>(a[0]) != readPropertyAsDateTime(id);
writeProperty(id, *reinterpret_cast<QDateTime *>(a[0]));
break;
case QVariant::RectF:
case QV4::CompiledData::Property::Rect:
needActivate = *reinterpret_cast<QRectF *>(a[0]) != readPropertyAsRectF(id);
writeProperty(id, *reinterpret_cast<QRectF *>(a[0]));
break;
case QVariant::SizeF:
case QV4::CompiledData::Property::Size:
needActivate = *reinterpret_cast<QSizeF *>(a[0]) != readPropertyAsSizeF(id);
writeProperty(id, *reinterpret_cast<QSizeF *>(a[0]));
break;
case QVariant::PointF:
case QV4::CompiledData::Property::Point:
needActivate = *reinterpret_cast<QPointF *>(a[0]) != readPropertyAsPointF(id);
writeProperty(id, *reinterpret_cast<QPointF *>(a[0]));
break;
case QMetaType::QObjectStar:
case QV4::CompiledData::Property::Custom:
needActivate = *reinterpret_cast<QObject **>(a[0]) != readPropertyAsQObject(id);
writeProperty(id, *reinterpret_cast<QObject **>(a[0]));
break;
case QMetaType::QVariant:
case QV4::CompiledData::Property::Variant:
writeProperty(id, *reinterpret_cast<QVariant *>(a[0]));
break;
default: {
QV4::MemberData *md = propertiesAsMemberData();
if (md) {
case QV4::CompiledData::Property::CustomList:
// Writing such a property is not supported. Content is added through the list property
// methods.
break;
case QV4::CompiledData::Property::Font:
case QV4::CompiledData::Property::Time:
case QV4::CompiledData::Property::Color:
case QV4::CompiledData::Property::Vector2D:
case QV4::CompiledData::Property::Vector3D:
case QV4::CompiledData::Property::Vector4D:
case QV4::CompiledData::Property::Matrix4x4:
case QV4::CompiledData::Property::Quaternion:
Q_ASSERT(fallbackMetaType != QMetaType::UnknownType);
if (QV4::MemberData *md = propertyAndMethodStorageAsMemberData()) {
QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
if (!v) {
*(md->data() + id) = cache->engine->newVariantObject(QVariant());
v = (md->data() + id)->as<QV4::VariantObject>();
QQml_valueTypeProvider()->initValueType(t, v->d()->data);
QQml_valueTypeProvider()->initValueType(fallbackMetaType, v->d()->data);
}
needActivate = !QQml_valueTypeProvider()->equalValueType(t, a[0], v->d()->data);
QQml_valueTypeProvider()->writeValueType(t, a[0], v->d()->data);
needActivate = !QQml_valueTypeProvider()->equalValueType(fallbackMetaType, a[0], v->d()->data);
QQml_valueTypeProvider()->writeValueType(fallbackMetaType, a[0], v->d()->data);
}
break;
}
case QV4::CompiledData::Property::Var:
Q_UNREACHABLE();
}
}
@ -782,13 +830,12 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1;
}
id -= metaData->propertyCount;
id -= propertyCount;
if (id < metaData->aliasCount) {
if (id < aliasCount) {
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[id];
QQmlVMEMetaData::AliasData *d = metaData->aliasData() + id;
if (d->flags & QML_ALIAS_FLAG_PTR && c == QMetaObject::ReadProperty)
if ((aliasData->flags & QV4::CompiledData::Alias::AliasPointsToPointerObject) && c == QMetaObject::ReadProperty)
*reinterpret_cast<void **>(a[0]) = 0;
if (!ctxt) return -1;
@ -796,42 +843,52 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QQmlContext *context = ctxt->asQQmlContext();
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
QObject *target = ctxtPriv->data->idValues[d->contextIdx].data();
QObject *target = ctxtPriv->data->idValues[aliasData->targetObjectId].data();
if (!target)
return -1;
connectAlias(id);
if (d->isObjectAlias()) {
if (aliasData->isObjectAlias()) {
*reinterpret_cast<QObject **>(a[0]) = target;
return -1;
}
QQmlData *targetDData = QQmlData::get(target, /*create*/false);
if (!targetDData)
return -1;
int coreIndex;
const int valueTypePropertyIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, &coreIndex);
// Remove binding (if any) on write
if(c == QMetaObject::WriteProperty) {
int flags = *reinterpret_cast<int*>(a[3]);
if (flags & QQmlPropertyPrivate::RemoveBindingOnAliasWrite) {
QQmlData *targetData = QQmlData::get(target);
if (targetData && targetData->hasBindingBit(d->propertyIndex()))
QQmlPropertyPrivate::removeBinding(target, d->propertyIdx);
if (targetData && targetData->hasBindingBit(coreIndex))
QQmlPropertyPrivate::removeBinding(target, aliasData->encodedMetaPropertyIndex);
}
}
if (d->isValueTypeAlias()) {
if (valueTypePropertyIndex != -1) {
if (!targetDData->propertyCache)
return -1;
const QQmlPropertyData *pd = targetDData->propertyCache->property(coreIndex);
// Value type property
QQmlValueType *valueType = QQmlValueTypeFactory::valueType(d->valueType());
QQmlValueType *valueType = QQmlValueTypeFactory::valueType(pd->propType);
Q_ASSERT(valueType);
valueType->read(target, d->propertyIndex());
int rv = QMetaObject::metacall(valueType, c, d->valueTypeIndex(), a);
valueType->read(target, coreIndex);
int rv = QMetaObject::metacall(valueType, c, valueTypePropertyIndex, a);
if (c == QMetaObject::WriteProperty)
valueType->write(target, d->propertyIndex(), 0x00);
valueType->write(target, coreIndex, 0x00);
return rv;
} else {
return QMetaObject::metacall(target, c, d->propertyIndex(), a);
return QMetaObject::metacall(target, c, coreIndex, a);
}
}
@ -844,8 +901,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
if (id >= methodOffset()) {
id -= methodOffset();
int plainSignals = metaData->signalCount + metaData->propertyCount +
metaData->aliasCount;
int plainSignals = signalCount + propertyCount + aliasCount;
if (id < plainSignals) {
activate(object, _id, a);
return -1;
@ -853,7 +909,7 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
id -= plainSignals;
if (id < metaData->methodCount) {
if (id < methodCount) {
if (!ctxt->engine)
return -1; // We can't run the method
@ -877,12 +933,11 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
return -1; // The dynamic method with that id is not available.
}
QQmlVMEMetaData::MethodData *data = metaData->methodData() + id;
QV4::ScopedCallData callData(scope, data->parameterCount);
const unsigned int parameterCount = function->formalParameterCount();
QV4::ScopedCallData callData(scope, parameterCount);
callData->thisObject = ep->v8engine()->global();
for (int ii = 0; ii < data->parameterCount; ++ii)
for (uint ii = 0; ii < parameterCount; ++ii)
callData->args[ii] = scope.engine->fromVariant(*(QVariant *)a[ii + 1]);
QV4::ScopedValue result(scope);
@ -911,22 +966,23 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void *
QV4::ReturnedValue QQmlVMEMetaObject::method(int index)
{
if (!ctxt || !ctxt->isValid()) {
if (!ctxt || !ctxt->isValid() || !compiledObject) {
qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
return QV4::Encode::undefined();
}
if (!methods)
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return QV4::Encode::undefined();
return methods[index].value();
return (md->data() + index + compiledObject->nProperties)->asReturnedValue();
}
QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id)
{
Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType);
Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var);
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md)
return (md->data() + id)->asReturnedValue();
return QV4::Primitive::undefinedValue().asReturnedValue();
@ -934,7 +990,7 @@ QV4::ReturnedValue QQmlVMEMetaObject::readVarProperty(int id)
QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
{
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md) {
const QV4::QObjectWrapper *wrapper = (md->data() + id)->as<QV4::QObjectWrapper>();
if (wrapper)
@ -949,9 +1005,9 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
{
Q_ASSERT((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType);
Q_ASSERT(compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var);
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
@ -989,8 +1045,8 @@ void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
{
if ((metaData->propertyData() + id)->propertyType == QQmlVMEMetaData::VarPropertyType) {
QV4::MemberData *md = propertiesAsMemberData();
if (compiledObject && compiledObject->propertyTable()[id].type == QV4::CompiledData::Property::Var) {
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
@ -1020,7 +1076,7 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
needActivate = readPropertyAsQObject(id) != o; // TODO: still correct?
writeProperty(id, o);
} else {
QV4::MemberData *md = propertiesAsMemberData();
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (md) {
QV4::VariantObject *v = (md->data() + id)->as<QV4::VariantObject>();
needActivate = (!v ||
@ -1039,30 +1095,16 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
}
}
quint16 QQmlVMEMetaObject::vmeMethodLineNumber(int index)
{
if (index < methodOffset()) {
Q_ASSERT(parentVMEMetaObject());
return parentVMEMetaObject()->vmeMethodLineNumber(index);
}
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
int rawIndex = index - methodOffset() - plainSignals;
QQmlVMEMetaData::MethodData *data = metaData->methodData() + rawIndex;
return data->lineNumber;
}
QV4::ReturnedValue QQmlVMEMetaObject::vmeMethod(int index)
{
if (index < methodOffset()) {
Q_ASSERT(parentVMEMetaObject());
return parentVMEMetaObject()->vmeMethod(index);
}
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
if (!compiledObject)
return QV4::Primitive::undefinedValue().asReturnedValue();
const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases;
Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions)));
return method(index - methodOffset() - plainSignals);
}
@ -1073,14 +1115,16 @@ void QQmlVMEMetaObject::setVmeMethod(int index, const QV4::Value &function)
Q_ASSERT(parentVMEMetaObject());
return parentVMEMetaObject()->setVmeMethod(index, function);
}
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
if (!methods)
methods = new QV4::PersistentValue[metaData->methodCount];
if (!compiledObject)
return;
const int plainSignals = compiledObject->nSignals + compiledObject->nProperties + compiledObject->nAliases;
Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + int(compiledObject->nFunctions)));
int methodIndex = index - methodOffset() - plainSignals;
methods[methodIndex].set(function.as<QV4::Object>()->engine(), function);
QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
if (!md)
return;
*(md->data() + methodIndex + compiledObject->nProperties) = function;
}
QV4::ReturnedValue QQmlVMEMetaObject::vmeProperty(int index)
@ -1115,25 +1159,15 @@ void QQmlVMEMetaObject::mark(QV4::ExecutionEngine *e)
if (v4 != e)
return;
properties.markOnce(e);
propertyAndMethodStorage.markOnce(e);
if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
parent->mark(e);
}
void QQmlVMEMetaObject::allocateProperties()
{
Q_ASSERT(cache && cache->engine);
Q_ASSERT(!properties.valueRef());
QV4::ExecutionEngine *v4 = cache->engine;
QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, metaData->propertyCount);
properties.set(v4, data);
std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
}
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
{
Q_ASSERT(index >= propOffset() + metaData->propertyCount);
Q_ASSERT(compiledObject && (index >= propOffset() + int(compiledObject->nProperties)));
*target = 0;
*coreIndex = -1;
@ -1142,31 +1176,24 @@ bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex,
if (!ctxt)
return false;
QQmlVMEMetaData::AliasData *d = metaData->aliasData() + (index - propOffset() - metaData->propertyCount);
QQmlContext *context = ctxt->asQQmlContext();
QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(context);
*target = ctxtPriv->data->idValues[d->contextIdx].data();
const int aliasId = index - propOffset() - compiledObject->nProperties;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
*target = ctxt->idValues[aliasData->targetObjectId].data();
if (!*target)
return false;
if (d->isObjectAlias()) {
} else if (d->isValueTypeAlias()) {
*coreIndex = d->propertyIndex();
*valueTypeIndex = d->valueTypeIndex();
} else {
*coreIndex = d->propertyIndex();
}
if (!aliasData->isObjectAlias())
*valueTypeIndex = QQmlPropertyData::decodeValueTypePropertyIndex(aliasData->encodedMetaPropertyIndex, coreIndex);
return true;
}
void QQmlVMEMetaObject::connectAlias(int aliasId)
{
Q_ASSERT(compiledObject);
if (!aliasEndpoints)
aliasEndpoints = new QQmlVMEMetaObjectEndpoint[metaData->aliasCount];
aliasEndpoints = new QQmlVMEMetaObjectEndpoint[compiledObject->nAliases];
QQmlVMEMetaData::AliasData *d = metaData->aliasData() + aliasId;
const QV4::CompiledData::Alias *aliasData = &compiledObject->aliasTable()[aliasId];
QQmlVMEMetaObjectEndpoint *endpoint = aliasEndpoints + aliasId;
if (endpoint->metaObject.data()) {
@ -1176,14 +1203,15 @@ void QQmlVMEMetaObject::connectAlias(int aliasId)
}
endpoint->metaObject = this;
endpoint->connect(&ctxt->idValues[d->contextIdx].bindings);
endpoint->connect(&ctxt->idValues[aliasData->targetObjectId].bindings);
endpoint->tryConnect();
}
void QQmlVMEMetaObject::connectAliasSignal(int index, bool indexInSignalRange)
{
int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - metaData->propertyCount;
if (aliasId < 0 || aliasId >= metaData->aliasCount)
Q_ASSERT(compiledObject);
int aliasId = (index - (indexInSignalRange ? signalOffset() : methodOffset())) - compiledObject->nProperties;
if (aliasId < 0 || aliasId >= int(compiledObject->nAliases))
return;
connectAlias(aliasId);

View File

@ -74,69 +74,17 @@
QT_BEGIN_NAMESPACE
#define QML_ALIAS_FLAG_PTR 0x00000001
struct QQmlVMEMetaData
{
short propertyCount;
short aliasCount;
short signalCount;
short methodCount;
// Make sure this structure is always aligned to int
int dummy;
struct AliasData {
int contextIdx;
int propertyIdx;
int propType;
int flags;
int notifySignal;
bool isObjectAlias() const {
return propertyIdx == -1;
}
bool isPropertyAlias() const {
return !isObjectAlias() && valueTypeIndex() == -1;
}
bool isValueTypeAlias() const {
return !isObjectAlias() && valueTypeIndex() != -1;
}
int propertyIndex() const {
int index;
QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx, &index);
return index;
}
int valueTypeIndex() const {
return QQmlPropertyData::decodeValueTypePropertyIndex(propertyIdx);
}
int valueType() const {
return (valueTypeIndex() != -1) ? propType : 0;
}
};
enum {
VarPropertyType = -1
};
struct PropertyData {
int propertyType;
};
struct MethodData {
int runtimeFunctionIndex;
int parameterCount;
quint16 lineNumber;
};
PropertyData *propertyData() const {
return (PropertyData *)(((char *)const_cast<QQmlVMEMetaData *>(this)) + sizeof(QQmlVMEMetaData));
}
AliasData *aliasData() const {
return (AliasData *)(propertyData() + propertyCount);
}
MethodData *methodData() const {
return (MethodData *)(aliasData() + aliasCount);
return (AliasData *)(((char *)const_cast<QQmlVMEMetaData *>(this)) + sizeof(QQmlVMEMetaData));
}
};
@ -199,12 +147,11 @@ class QQmlVMEMetaObjectEndpoint;
class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
{
public:
QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data);
QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data, QV4::CompiledData::CompilationUnit *qmlCompilationUnit, int qmlObjectId);
~QQmlVMEMetaObject();
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
QV4::ReturnedValue vmeMethod(int index);
quint16 vmeMethodLineNumber(int index);
void setVmeMethod(int index, const QV4::Value &function);
QV4::ReturnedValue vmeProperty(int index);
void setVMEProperty(int index, const QV4::Value &v);
@ -230,9 +177,8 @@ public:
QQmlVMEMetaObjectEndpoint *aliasEndpoints;
QV4::WeakValue properties;
inline void allocateProperties();
QV4::MemberData *propertiesAsMemberData();
QV4::WeakValue propertyAndMethodStorage;
QV4::MemberData *propertyAndMethodStorageAsMemberData();
int readPropertyAsInt(int id);
bool readPropertyAsBool(int id);
@ -265,7 +211,6 @@ public:
void connectAlias(int aliasId);
QV4::PersistentValue *methods;
QV4::ReturnedValue method(int);
QV4::ReturnedValue readVarProperty(int);
@ -280,6 +225,12 @@ public:
QList<QQmlVMEVariantQObjectPtr *> varObjectGuards;
QQmlVMEVariantQObjectPtr *getQObjectGuardForProperty(int) const;
// keep a reference to the compilation unit in order to still
// do property access when the context has been invalidated.
QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
const QV4::CompiledData::Object *compiledObject;
};
QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj)

View File

@ -88,22 +88,18 @@ struct StaticQtMetaObject : public QObject
};
Heap::QtObject::QtObject(QQmlEngine *qmlEngine)
: enumeratorIterator(0)
, keyIterator(0)
{
Scope scope(internalClass->engine);
ScopedObject o(scope, this);
// Set all the enums from the "Qt" namespace
const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
ScopedString str(scope);
ScopedValue v(scope);
for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
QMetaEnum enumerator = qtMetaObject->enumerator(ii);
for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
o->put((str = scope.engine->newString(QString::fromUtf8(enumerator.key(jj)))), (v = QV4::Primitive::fromInt32(enumerator.value(jj))));
}
{
ScopedString str(scope);
ScopedValue v(scope);
o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0)));
o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1)));
}
o->put((str = scope.engine->newString(QStringLiteral("Asynchronous"))), (v = QV4::Primitive::fromInt32(0)));
o->put((str = scope.engine->newString(QStringLiteral("Synchronous"))), (v = QV4::Primitive::fromInt32(1)));
o->defineDefaultProperty(QStringLiteral("include"), QV4Include::method_include);
o->defineDefaultProperty(QStringLiteral("isQtObject"), QV4::QtObject::method_isQtObject);
@ -154,6 +150,70 @@ Heap::QtObject::QtObject(QQmlEngine *qmlEngine)
o->defineDefaultProperty(QStringLiteral("callLater"), QV4::QtObject::method_callLater);
}
void QtObject::addAll()
{
bool dummy = false;
findAndAdd(nullptr, dummy);
}
ReturnedValue QtObject::findAndAdd(const QString *name, bool &foundProperty) const
{
Scope scope(engine());
ScopedObject o(scope, this);
ScopedString key(scope);
ScopedValue value(scope);
const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
for (int enumCount = qtMetaObject->enumeratorCount(); d()->enumeratorIterator < enumCount;
++d()->enumeratorIterator) {
QMetaEnum enumerator = qtMetaObject->enumerator(d()->enumeratorIterator);
for (int keyCount = enumerator.keyCount(); d()->keyIterator < keyCount; ++d()->keyIterator) {
key = scope.engine->newString(QString::fromUtf8(enumerator.key(d()->keyIterator)));
value = QV4::Primitive::fromInt32(enumerator.value(d()->keyIterator));
o->put(key, value);
if (name && key->toQString() == *name) {
++d()->keyIterator;
foundProperty = true;
return value->asReturnedValue();
}
}
d()->keyIterator = 0;
}
d()->enumeratorIterator = Heap::QtObject::Finished;
foundProperty = false;
return Encode::undefined();
}
ReturnedValue QtObject::get(const Managed *m, String *name, bool *hasProperty)
{
bool hasProp = false;
if (hasProperty == nullptr) {
hasProperty = &hasProp;
}
ReturnedValue ret = QV4::Object::get(m, name, hasProperty);
if (*hasProperty) {
return ret;
}
auto that = static_cast<const QtObject*>(m);
if (!that->d()->isComplete()) {
const QString key = name->toQString();
ret = that->findAndAdd(&key, *hasProperty);
}
return ret;
}
void QtObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{
auto that = static_cast<QtObject*>(m);
if (!that->d()->isComplete()) {
that->addAll();
}
QV4::Object::advanceIterator(m, it, name, index, p, attributes);
}
/*!
\qmlmethod bool Qt::isQtObject(object)

View File

@ -67,6 +67,13 @@ struct QtObject : Object {
QtObject(QQmlEngine *qmlEngine);
QObject *platform;
QObject *application;
enum { Finished = -1 };
int enumeratorIterator;
int keyIterator;
bool isComplete() const
{ return enumeratorIterator == Finished; }
};
struct ConsoleObject : Object {
@ -86,6 +93,9 @@ struct QtObject : Object
{
V4_OBJECT2(QtObject, Object)
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static ReturnedValue method_isQtObject(CallContext *ctx);
static ReturnedValue method_rgba(CallContext *ctx);
static ReturnedValue method_hsla(CallContext *ctx);
@ -126,6 +136,10 @@ struct QtObject : Object
static ReturnedValue method_get_styleHints(CallContext *ctx);
static ReturnedValue method_callLater(CallContext *ctx);
private:
void addAll();
ReturnedValue findAndAdd(const QString *name, bool &foundProperty) const;
};
struct ConsoleObject : Object

View File

@ -156,8 +156,7 @@ QV8Engine::QV8Engine(QJSEngine* qq)
QV8Engine::~QV8Engine()
{
for (int ii = 0; ii < m_extensionData.count(); ++ii)
delete m_extensionData[ii];
qDeleteAll(m_extensionData);
m_extensionData.clear();
#if !defined(QT_NO_XMLSTREAMREADER) && defined(QT_NO_NETWORK)

View File

@ -1040,7 +1040,7 @@ QString QQmlDelegateModelPrivate::stringValue(Compositor::Group group, int index
return QString();
int from = dot+1;
dot = name.indexOf(QLatin1Char('.'), from);
value = obj->property(name.mid(from, dot-from).toUtf8());
value = obj->property(name.midRef(from, dot - from).toUtf8());
}
return value.toString();
}
@ -1557,29 +1557,6 @@ bool QQmlDelegateModel::isDescendantOf(const QPersistentModelIndex& desc, const
return false;
}
void QQmlDelegateModel::_q_layoutAboutToBeChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_D(QQmlDelegateModel);
if (!d->m_complete)
return;
if (hint == QAbstractItemModel::VerticalSortHint) {
d->m_storedPersistentIndexes.clear();
if (!parents.isEmpty() && d->m_adaptorModel.rootIndex.isValid() && !isDescendantOf(d->m_adaptorModel.rootIndex, parents)) {
return;
}
for (int i = 0; i < d->m_count; ++i) {
const QModelIndex index = d->m_adaptorModel.aim()->index(i, 0, d->m_adaptorModel.rootIndex);
d->m_storedPersistentIndexes.append(index);
}
} else if (hint == QAbstractItemModel::HorizontalSortHint) {
// Ignored
} else {
// Triggers model reset, no preparations for that are needed
}
}
void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &parents, QAbstractItemModel::LayoutChangeHint hint)
{
Q_D(QQmlDelegateModel);
@ -1591,19 +1568,7 @@ void QQmlDelegateModel::_q_layoutChanged(const QList<QPersistentModelIndex> &par
return;
}
for (int i = 0, c = d->m_storedPersistentIndexes.count(); i < c; ++i) {
const QPersistentModelIndex &index = d->m_storedPersistentIndexes.at(i);
if (i == index.row())
continue;
_q_itemsMoved(i, index.row(), 1);
}
d->m_storedPersistentIndexes.clear();
// layoutUpdate does not necessarily have any move changes, but it can
// also mean data changes. We can't detect what exactly has changed, so
// just emit it for all items
// mark all items as changed
_q_itemsChanged(0, d->m_count, QVector<int>());
} else if (hint == QAbstractItemModel::HorizontalSortHint) {

View File

@ -146,7 +146,6 @@ private Q_SLOTS:
void _q_rowsRemoved(const QModelIndex &,int,int);
void _q_rowsMoved(const QModelIndex &, int, int, const QModelIndex &, int);
void _q_dataChanged(const QModelIndex&,const QModelIndex&,const QVector<int> &);
void _q_layoutAboutToBeChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
void _q_layoutChanged(const QList<QPersistentModelIndex>&, QAbstractItemModel::LayoutChangeHint);
private:

View File

@ -337,8 +337,6 @@ public:
};
QQmlDelegateModelGroup *m_groups[Compositor::MaximumGroupCount];
};
QList<QPersistentModelIndex> m_storedPersistentIndexes;
};
class QQmlPartsModel : public QQmlInstanceModel, public QQmlDelegateModelGroupEmitter

View File

@ -470,8 +470,6 @@ public:
vdm, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
QObject::disconnect(aim, SIGNAL(modelReset()),
vdm, SLOT(_q_modelReset()));
QObject::disconnect(aim, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
vdm, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
QObject::disconnect(aim, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
vdm, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
}
@ -928,8 +926,6 @@ void QQmlAdaptorModel::setModel(const QVariant &variant, QQmlDelegateModel *vdm,
vdm, QQmlDelegateModel, SLOT(_q_rowsMoved(QModelIndex,int,int,QModelIndex,int)));
qmlobject_connect(model, QAbstractItemModel, SIGNAL(modelReset()),
vdm, QQmlDelegateModel, SLOT(_q_modelReset()));
qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
vdm, QQmlDelegateModel, SLOT(_q_layoutAboutToBeChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
qmlobject_connect(model, QAbstractItemModel, SIGNAL(layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)),
vdm, QQmlDelegateModel, SLOT(_q_layoutChanged(QList<QPersistentModelIndex>,QAbstractItemModel::LayoutChangeHint)));
} else {

View File

@ -352,7 +352,7 @@ int quick_test_main(int argc, char **argv, const char *name, const char *sourceD
QTestRootObject::instance()->init();
QString path = fi.absoluteFilePath();
if (path.startsWith(QLatin1String(":/")))
view->setSource(QUrl(QLatin1String("qrc:") + path.mid(2)));
view->setSource(QUrl(QLatin1String("qrc:") + path.midRef(2)));
else
view->setSource(QUrl::fromLocalFile(path));

View File

@ -79,23 +79,9 @@ struct MetaPropertyData {
QVector<QPair<QVariant, bool> > m_data;
};
static bool constructedMetaData(const QQmlVMEMetaData* data)
{
return data->propertyCount == 0
&& data->aliasCount == 0
&& data->signalCount == 0
&& data->methodCount == 0;
}
static QQmlVMEMetaData* fakeMetaData()
{
QQmlVMEMetaData* data = new QQmlVMEMetaData;
data->propertyCount = 0;
data->aliasCount = 0;
data->signalCount = 0;
data->methodCount = 0;
return data;
return new QQmlVMEMetaData;
}
static const QQmlVMEMetaData* vMEMetaDataForObject(QObject *object)
@ -125,7 +111,15 @@ QQmlDesignerMetaObject* QQmlDesignerMetaObject::getNodeInstanceMetaObject(QObjec
return static_cast<QQmlDesignerMetaObject *>(parent);
// we just create one and the ownership goes automatically to the object in nodeinstance see init method
return new QQmlDesignerMetaObject(object, engine);
QQmlData *ddata = QQmlData::get(object, false);
const bool hadVMEMetaObject = ddata ? ddata->hasVMEMetaObject : false;
QQmlDesignerMetaObject *mo = new QQmlDesignerMetaObject(object, engine);
//If our parent is not a VMEMetaObject we just set the flag to false again
if (ddata)
ddata->hasVMEMetaObject = hadVMEMetaObject;
return mo;
}
void QQmlDesignerMetaObject::init(QObject *object, QQmlEngine *engine)
@ -140,20 +134,20 @@ void QQmlDesignerMetaObject::init(QObject *object, QQmlEngine *engine)
QObjectPrivate *op = QObjectPrivate::get(object);
op->metaObject = this;
//create cache
cache = m_cache = QQmlEnginePrivate::get(engine)->cache(this);
cache->addref();
m_cache = QQmlEnginePrivate::get(engine)->cache(this);
//If our parent is not a VMEMetaObject we just se the flag to false again
if (constructedMetaData(metaData))
QQmlData::get(object)->hasVMEMetaObject = false;
if (m_cache != cache) {
m_cache->addref();
cache->release();
cache = m_cache;
}
nodeInstanceMetaObjectList.insert(this, true);
hasAssignedMetaObjectData = true;
}
QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine)
: QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object)),
: QQmlVMEMetaObject(object, cacheForObject(object, engine), vMEMetaDataForObject(object), /*qml compilation unit*/nullptr, /*qmlObjectId*/-1),
m_context(engine->contextForObject(object)),
m_data(new MetaPropertyData),
m_cache(0)
@ -161,22 +155,20 @@ QQmlDesignerMetaObject::QQmlDesignerMetaObject(QObject *object, QQmlEngine *engi
init(object, engine);
QQmlData *ddata = QQmlData::get(object, false);
//Assign cache to object
if (ddata && ddata->propertyCache) {
cache->setParent(ddata->propertyCache);
cache->invalidate(engine, this);
ddata->propertyCache->release();
ddata->propertyCache = m_cache;
m_cache->addref();
}
}
QQmlDesignerMetaObject::~QQmlDesignerMetaObject()
{
if (cache->count() > 1) // qml is crashing because the property cache is not removed from the engine
cache->release();
else
m_type->release();
m_type->release();
nodeInstanceMetaObjectList.remove(this);
}

View File

@ -70,7 +70,6 @@ public:
static void registerNotifyPropertyChangeCallBack(void (*callback)(QObject*, const QQuickDesignerSupport::PropertyName &propertyName));
protected:
QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine);
static QQmlDesignerMetaObject* getNodeInstanceMetaObject(QObject *object, QQmlEngine *engine);
void createNewDynamicProperty(const QString &name);
@ -95,6 +94,7 @@ protected:
void copyTypeMetaObject();
private:
QQmlDesignerMetaObject(QObject *object, QQmlEngine *engine);
void init(QObject *, QQmlEngine *engine);
QPointer<QQmlContext> m_context;

View File

@ -189,17 +189,17 @@ QTransform QQuickDesignerSupport::parentTransform(QQuickItem *referencedItem)
return parentTransform;
}
QString propertyNameForAnchorLine(const QQuickAnchorLine::AnchorLine &anchorLine)
QString propertyNameForAnchorLine(const QQuickAnchors::Anchor &anchorLine)
{
switch (anchorLine) {
case QQuickAnchorLine::Left: return QLatin1String("left");
case QQuickAnchorLine::Right: return QLatin1String("right");
case QQuickAnchorLine::Top: return QLatin1String("top");
case QQuickAnchorLine::Bottom: return QLatin1String("bottom");
case QQuickAnchorLine::HCenter: return QLatin1String("horizontalCenter");
case QQuickAnchorLine::VCenter: return QLatin1String("verticalCenter");
case QQuickAnchorLine::Baseline: return QLatin1String("baseline");
case QQuickAnchorLine::Invalid:
case QQuickAnchors::LeftAnchor: return QLatin1String("left");
case QQuickAnchors::RightAnchor: return QLatin1String("right");
case QQuickAnchors::TopAnchor: return QLatin1String("top");
case QQuickAnchors::BottomAnchor: return QLatin1String("bottom");
case QQuickAnchors::HCenterAnchor: return QLatin1String("horizontalCenter");
case QQuickAnchors::VCenterAnchor: return QLatin1String("verticalCenter");
case QQuickAnchors::BaselineAnchor: return QLatin1String("baseline");
case QQuickAnchors::InvalidAnchor: // fallthrough:
default: return QString();
}
}
@ -345,7 +345,7 @@ QPair<QString, QObject*> QQuickDesignerSupport::anchorLineTarget(QQuickItem *ite
return QPair<QString, QObject*>();
QQuickAnchorLine anchorLine = metaProperty.read().value<QQuickAnchorLine>();
if (anchorLine.anchorLine != QQuickAnchorLine::Invalid) {
if (anchorLine.anchorLine != QQuickAnchors::InvalidAnchor) {
targetObject = anchorLine.item;
targetName = propertyNameForAnchorLine(anchorLine.anchorLine);
}

View File

@ -0,0 +1,76 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
//![0]
import QtQuick 2.8
Item {
width: 200; height: 200
Rectangle {
anchors.centerIn: parent
width: text.implicitWidth + 20; height: text.implicitHeight + 10
color: "green"
radius: 5
Drag.active: dragArea.drag.active
Drag.dragType: Drag.Automatic
Drag.supportedActions: Qt.CopyAction
Drag.mimeData: {
"text/plain": "Copied text"
}
Text {
id: text
anchors.centerIn: parent
text: "Drag me"
}
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
onPressed: parent.grabToImage(function(result) {
parent.Drag.imageSource = result.url
})
}
}
}
//![0]

View File

@ -66,6 +66,7 @@
#include <private/qv4scopedvalue_p.h>
#include <QtCore/qmath.h>
#include <QtCore/qvector.h>
#include <QtCore/private/qnumeric_p.h>
#include <QtCore/QRunnable>
#include <QtGui/qguiapplication.h>
@ -205,7 +206,7 @@ QColor qt_color_from_string(const QV4::Value &name)
return QColor();
}
static int qParseFontSizeFromToken(const QString &fontSizeToken, bool &ok)
static int qParseFontSizeFromToken(const QStringRef &fontSizeToken, bool &ok)
{
ok = false;
float size = fontSizeToken.trimmed().toFloat(&ok);
@ -221,11 +222,11 @@ static int qParseFontSizeFromToken(const QString &fontSizeToken, bool &ok)
\c true if successful. If the font size is invalid, \c false is returned
and a warning is printed.
*/
static bool qSetFontSizeFromToken(QFont &font, const QString &fontSizeToken)
static bool qSetFontSizeFromToken(QFont &font, const QStringRef &fontSizeToken)
{
const QString trimmedToken = fontSizeToken.trimmed();
const QString unitStr = trimmedToken.right(2);
const QString value = trimmedToken.left(trimmedToken.size() - 2);
const QStringRef trimmedToken = fontSizeToken.trimmed();
const QStringRef unitStr = trimmedToken.right(2);
const QStringRef value = trimmedToken.left(trimmedToken.size() - 2);
bool ok = false;
int size = 0;
if (unitStr == QLatin1String("px")) {
@ -251,7 +252,7 @@ static bool qSetFontSizeFromToken(QFont &font, const QString &fontSizeToken)
each family is separated by spaces. Families with spaces in their name
must be quoted.
*/
static QStringList qExtractFontFamiliesFromString(const QString &fontFamiliesString)
static QStringList qExtractFontFamiliesFromString(const QStringRef &fontFamiliesString)
{
QStringList extractedFamilies;
int quoteIndex = -1;
@ -264,7 +265,7 @@ static QStringList qExtractFontFamiliesFromString(const QString &fontFamiliesStr
} else {
if (ch == fontFamiliesString.at(quoteIndex)) {
// Found the matching quote. +1/-1 because we don't want the quote as part of the name.
const QString family = fontFamiliesString.mid(quoteIndex + 1, index - quoteIndex - 1);
const QString family = fontFamiliesString.mid(quoteIndex + 1, index - quoteIndex - 1).toString();
extractedFamilies.push_back(family);
currentFamily.clear();
quoteIndex = -1;
@ -395,16 +396,17 @@ static QFont qt_font_from_string(const QString& fontString, const QFont &current
fontSizeEnd += 3;
QFont newFont;
if (!qSetFontSizeFromToken(newFont, fontString.mid(fontSizeStart, fontSizeEnd - fontSizeStart)))
if (!qSetFontSizeFromToken(newFont, fontString.midRef(fontSizeStart, fontSizeEnd - fontSizeStart)))
return currentFont;
// We don't want to parse the size twice, so remove it now.
QString remainingFontString = fontString;
remainingFontString.remove(fontSizeStart, fontSizeEnd - fontSizeStart);
QStringRef remainingFontStringRef(&remainingFontString);
// Next, we have to take any font families out, as QString::split() will ruin quoted family names.
const QString fontFamiliesString = remainingFontString.mid(fontSizeStart);
remainingFontString.chop(remainingFontString.length() - fontSizeStart);
const QStringRef fontFamiliesString = remainingFontStringRef.mid(fontSizeStart);
remainingFontStringRef.truncate(fontSizeStart);
QStringList fontFamilies = qExtractFontFamiliesFromString(fontFamiliesString);
if (fontFamilies.isEmpty()) {
return currentFont;
@ -413,16 +415,16 @@ static QFont qt_font_from_string(const QString& fontString, const QFont &current
return currentFont;
// Now that we've removed the messy parts, we can split the font string on spaces.
const QString trimmedTokensStr = remainingFontString.trimmed();
const QStringRef trimmedTokensStr = remainingFontStringRef.trimmed();
if (trimmedTokensStr.isEmpty()) {
// No optional properties.
return newFont;
}
const QStringList tokens = trimmedTokensStr.split(QLatin1Char(' '));
const auto tokens = trimmedTokensStr.split(QLatin1Char(' '));
int usedTokens = NoTokens;
// Optional properties can be in any order, but font-size and font-family must be last.
for (const QString &token : tokens) {
for (const QStringRef &token : tokens) {
if (token.compare(QLatin1String("normal")) == 0) {
if (!(usedTokens & FontStyle) || !(usedTokens & FontVariant) || !(usedTokens & FontWeight)) {
// Could be font-style, font-variant or font-weight.
@ -943,7 +945,7 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32);
pixelData->d()->image.fill(0x00000000);
} else {
Q_ASSERT(image.width() == int(w) && image.height() == int(h));
Q_ASSERT(image.width() == qRound(w) && image.height() == qRound(h));
pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32);
}
@ -1263,7 +1265,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::CallContext *c
double globalAlpha = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
if (!qIsFinite(globalAlpha))
if (!qt_is_finite(globalAlpha))
return QV4::Encode::undefined();
if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->d()->context->state.globalAlpha != globalAlpha) {
@ -1547,10 +1549,10 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::
qreal x1 = ctx->args()[2].toNumber();
qreal y1 = ctx->args()[3].toNumber();
if (!qIsFinite(x0)
|| !qIsFinite(y0)
|| !qIsFinite(x1)
|| !qIsFinite(y1)) {
if (!qt_is_finite(x0)
|| !qt_is_finite(y0)
|| !qt_is_finite(x1)
|| !qt_is_finite(y1)) {
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
}
QQuickContext2DEngineData *ed = engineData(scope.engine);
@ -1592,12 +1594,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::
qreal y1 = ctx->args()[4].toNumber();
qreal r1 = ctx->args()[5].toNumber();
if (!qIsFinite(x0)
|| !qIsFinite(y0)
|| !qIsFinite(x1)
|| !qIsFinite(r0)
|| !qIsFinite(r1)
|| !qIsFinite(y1)) {
if (!qt_is_finite(x0)
|| !qt_is_finite(y0)
|| !qt_is_finite(x1)
|| !qt_is_finite(r0)
|| !qt_is_finite(r1)
|| !qt_is_finite(y1)) {
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
}
@ -1639,11 +1641,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4:
qreal x = ctx->args()[0].toNumber();
qreal y = ctx->args()[1].toNumber();
qreal angle = DEGREES(ctx->args()[2].toNumber());
if (!qIsFinite(x) || !qIsFinite(y)) {
if (!qt_is_finite(x) || !qt_is_finite(y)) {
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
}
if (!qIsFinite(angle)) {
if (!qt_is_finite(angle)) {
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
}
@ -1894,7 +1896,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::CallContext *ctx
qreal w = ctx->argc() ? ctx->args()[0].toNumber() : -1;
if (w > 0 && qIsFinite(w) && w != r->d()->context->state.lineWidth) {
if (w > 0 && qt_is_finite(w) && w != r->d()->context->state.lineWidth) {
r->d()->context->state.lineWidth = w;
r->d()->context->buffer()->setLineWidth(w);
}
@ -1923,7 +1925,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::CallContext *ct
qreal ml = ctx->argc() ? ctx->args()[0].toNumber() : -1;
if (ml > 0 && qIsFinite(ml) && ml != r->d()->context->state.miterLimit) {
if (ml > 0 && qt_is_finite(ml) && ml != r->d()->context->state.miterLimit) {
r->d()->context->state.miterLimit = ml;
r->d()->context->buffer()->setMiterLimit(ml);
}
@ -1952,7 +1954,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::CallContext *ct
qreal blur = ctx->argc() ? ctx->args()[0].toNumber() : -1;
if (blur > 0 && qIsFinite(blur) && blur != r->d()->context->state.shadowBlur) {
if (blur > 0 && qt_is_finite(blur) && blur != r->d()->context->state.shadowBlur) {
r->d()->context->state.shadowBlur = blur;
r->d()->context->buffer()->setShadowBlur(blur);
}
@ -2012,7 +2014,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::CallContext
CHECK_CONTEXT_SETTER(r)
qreal offsetX = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
if (qIsFinite(offsetX) && offsetX != r->d()->context->state.shadowOffsetX) {
if (qt_is_finite(offsetX) && offsetX != r->d()->context->state.shadowOffsetX) {
r->d()->context->state.shadowOffsetX = offsetX;
r->d()->context->buffer()->setShadowOffsetX(offsetX);
}
@ -2040,7 +2042,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(QV4::CallContext
CHECK_CONTEXT_SETTER(r)
qreal offsetY = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
if (qIsFinite(offsetY) && offsetY != r->d()->context->state.shadowOffsetY) {
if (qt_is_finite(offsetY) && offsetY != r->d()->context->state.shadowOffsetY) {
r->d()->context->state.shadowOffsetY = offsetY;
r->d()->context->buffer()->setShadowOffsetY(offsetY);
}
@ -2170,7 +2172,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::CallContext *ctx)
qreal radius = ctx->args()[2].toNumber();
if (qIsFinite(radius) && radius < 0)
if (qt_is_finite(radius) && radius < 0)
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
r->d()->context->arc(ctx->args()[0].toNumber(),
@ -2216,7 +2218,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::CallContext *ct
if (ctx->argc() >= 5) {
qreal radius = ctx->args()[4].toNumber();
if (qIsFinite(radius) && radius < 0)
if (qt_is_finite(radius) && radius < 0)
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
r->d()->context->arcTo(ctx->args()[0].toNumber(),
@ -2279,7 +2281,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::CallCon
qreal x = ctx->args()[4].toNumber();
qreal y = ctx->args()[5].toNumber();
if (!qIsFinite(cp1x) || !qIsFinite(cp1y) || !qIsFinite(cp2x) || !qIsFinite(cp2y) || !qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(cp1x) || !qt_is_finite(cp1y) || !qt_is_finite(cp2x) || !qt_is_finite(cp2y) || !qt_is_finite(x) || !qt_is_finite(y))
return ctx->thisObject().asReturnedValue();
r->d()->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
@ -2375,7 +2377,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::CallContext *c
qreal x = ctx->args()[0].toNumber();
qreal y = ctx->args()[1].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return ctx->thisObject().asReturnedValue();
r->d()->context->lineTo(x, y);
@ -2399,7 +2401,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::CallContext *c
qreal x = ctx->args()[0].toNumber();
qreal y = ctx->args()[1].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return ctx->thisObject().asReturnedValue();
r->d()->context->moveTo(x, y);
}
@ -2425,7 +2427,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::Call
qreal x = ctx->args()[2].toNumber();
qreal y = ctx->args()[3].toNumber();
if (!qIsFinite(cpx) || !qIsFinite(cpy) || !qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(cpx) || !qt_is_finite(cpy) || !qt_is_finite(x) || !qt_is_finite(y))
return ctx->thisObject().asReturnedValue();
r->d()->context->quadraticCurveTo(cpx, cpy, x, y);
@ -2509,7 +2511,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::CallContext *ctx
qreal x = ctx->args()[1].toNumber();
qreal y = ctx->args()[2].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return ctx->thisObject().asReturnedValue();
r->d()->context->text(ctx->args()[0].toQStringNoThrow(), x, y);
}
@ -2774,7 +2776,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::CallContext
if (ctx->argc() >= 3) {
qreal x = ctx->args()[1].toNumber();
qreal y = ctx->args()[2].toNumber();
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return ctx->thisObject().asReturnedValue();
QPainterPath textPath = r->d()->context->createTextGlyphs(x, y, ctx->args()[0].toQStringNoThrow());
r->d()->context->buffer()->fill(textPath);
@ -2973,14 +2975,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
return ctx->thisObject().asReturnedValue();
}
if (!qIsFinite(sx)
|| !qIsFinite(sy)
|| !qIsFinite(sw)
|| !qIsFinite(sh)
|| !qIsFinite(dx)
|| !qIsFinite(dy)
|| !qIsFinite(dw)
|| !qIsFinite(dh))
if (!qt_is_finite(sx)
|| !qt_is_finite(sy)
|| !qt_is_finite(sw)
|| !qt_is_finite(sh)
|| !qt_is_finite(dx)
|| !qt_is_finite(dy)
|| !qt_is_finite(dw)
|| !qt_is_finite(dh))
return ctx->thisObject().asReturnedValue();
if (sx < 0
@ -3201,7 +3203,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallC
qreal w = ctx->args()[0].toNumber();
qreal h = ctx->args()[1].toNumber();
if (!qIsFinite(w) || !qIsFinite(h))
if (!qt_is_finite(w) || !qt_is_finite(h))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
if (w > 0 && h > 0)
@ -3227,7 +3229,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::CallCont
qreal y = ctx->args()[1].toNumber();
qreal w = ctx->args()[2].toNumber();
qreal h = ctx->args()[3].toNumber();
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
if (w <= 0 || h <= 0)
@ -3259,7 +3261,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
qreal dy = ctx->args()[2].toNumber();
qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
if (!qIsFinite(dx) || !qIsFinite(dy))
if (!qt_is_finite(dx) || !qt_is_finite(dy))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg0);
@ -3277,7 +3279,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
dirtyWidth = ctx->args()[5].toNumber();
dirtyHeight = ctx->args()[6].toNumber();
if (!qIsFinite(dirtyX) || !qIsFinite(dirtyY) || !qIsFinite(dirtyWidth) || !qIsFinite(dirtyHeight))
if (!qt_is_finite(dirtyX) || !qt_is_finite(dirtyY) || !qt_is_finite(dirtyWidth) || !qt_is_finite(dirtyHeight))
V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
@ -3364,7 +3366,7 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallCo
} else {
color = qt_color_from_string(ctx->args()[1]);
}
if (pos < 0.0 || pos > 1.0 || !qIsFinite(pos)) {
if (pos < 0.0 || pos > 1.0 || !qt_is_finite(pos)) {
V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
}
@ -3384,7 +3386,7 @@ void QQuickContext2D::scale(qreal x, qreal y)
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return;
QTransform newTransform = state.matrix;
@ -3405,7 +3407,7 @@ void QQuickContext2D::rotate(qreal angle)
if (!state.invertibleCTM)
return;
if (!qIsFinite(angle))
if (!qt_is_finite(angle))
return;
QTransform newTransform =state.matrix;
@ -3426,7 +3428,7 @@ void QQuickContext2D::shear(qreal h, qreal v)
if (!state.invertibleCTM)
return;
if (!qIsFinite(h) || !qIsFinite(v))
if (!qt_is_finite(h) || !qt_is_finite(v))
return ;
QTransform newTransform = state.matrix;
@ -3447,7 +3449,7 @@ void QQuickContext2D::translate(qreal x, qreal y)
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return ;
QTransform newTransform = state.matrix;
@ -3468,7 +3470,7 @@ void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qre
if (!state.invertibleCTM)
return;
if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
if (!qt_is_finite(a) || !qt_is_finite(b) || !qt_is_finite(c) || !qt_is_finite(d) || !qt_is_finite(e) || !qt_is_finite(f))
return;
QTransform transform(a, b, c, d, e, f);
@ -3485,7 +3487,7 @@ void QQuickContext2D::transform(qreal a, qreal b, qreal c, qreal d, qreal e, qre
void QQuickContext2D::setTransform(qreal a, qreal b, qreal c, qreal d, qreal e, qreal f)
{
if (!qIsFinite(a) || !qIsFinite(b) || !qIsFinite(c) || !qIsFinite(d) || !qIsFinite(e) || !qIsFinite(f))
if (!qt_is_finite(a) || !qt_is_finite(b) || !qt_is_finite(c) || !qt_is_finite(d) || !qt_is_finite(e) || !qt_is_finite(f))
return;
QTransform ctm = state.matrix;
@ -3542,7 +3544,7 @@ void QQuickContext2D::fillRect(qreal x, qreal y, qreal w, qreal h)
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
return;
buffer()->fillRect(QRectF(x, y, w, h));
@ -3553,7 +3555,7 @@ void QQuickContext2D::strokeRect(qreal x, qreal y, qreal w, qreal h)
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
return;
buffer()->strokeRect(QRectF(x, y, w, h));
@ -3564,7 +3566,7 @@ void QQuickContext2D::clearRect(qreal x, qreal y, qreal w, qreal h)
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
return;
buffer()->clearRect(QRectF(x, y, w, h));
@ -3575,7 +3577,7 @@ void QQuickContext2D::drawText(const QString& text, qreal x, qreal y, bool fill)
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return;
QPainterPath textPath = createTextGlyphs(x, y, text);
@ -3721,7 +3723,7 @@ void QQuickContext2D::arcTo(qreal x1, qreal y1,
if (!state.invertibleCTM)
return;
if (!qIsFinite(x1) || !qIsFinite(y1) || !qIsFinite(x2) || !qIsFinite(y2) || !qIsFinite(radius))
if (!qt_is_finite(x1) || !qt_is_finite(y1) || !qt_is_finite(x2) || !qt_is_finite(y2) || !qt_is_finite(radius))
return;
QPointF st(x1, y1);
@ -3739,7 +3741,7 @@ void QQuickContext2D::rect(qreal x, qreal y, qreal w, qreal h)
{
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
return;
if (!w && !h) {
@ -3756,7 +3758,7 @@ void QQuickContext2D::roundedRect(qreal x, qreal y,
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h) || !qIsFinite(xr) || !qIsFinite(yr))
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h) || !qt_is_finite(xr) || !qt_is_finite(yr))
return;
if (!w && !h) {
@ -3772,7 +3774,7 @@ void QQuickContext2D::ellipse(qreal x, qreal y,
if (!state.invertibleCTM)
return;
if (!qIsFinite(x) || !qIsFinite(y) || !qIsFinite(w) || !qIsFinite(h))
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
return;
if (!w && !h) {
@ -3798,7 +3800,7 @@ void QQuickContext2D::arc(qreal xc, qreal yc, qreal radius, qreal sar, qreal ear
if (!state.invertibleCTM)
return;
if (!qIsFinite(xc) || !qIsFinite(yc) || !qIsFinite(sar) || !qIsFinite(ear) || !qIsFinite(radius))
if (!qt_is_finite(xc) || !qt_is_finite(yc) || !qt_is_finite(sar) || !qt_is_finite(ear) || !qt_is_finite(radius))
return;
if (sar == ear)
@ -3937,13 +3939,13 @@ bool QQuickContext2D::isPointInPath(qreal x, qreal y) const
if (!m_path.elementCount())
return false;
if (!qIsFinite(x) || !qIsFinite(y))
if (!qt_is_finite(x) || !qt_is_finite(y))
return false;
QPointF point(x, y);
QTransform ctm = state.matrix;
QPointF p = ctm.inverted().map(point);
if (!qIsFinite(p.x()) || !qIsFinite(p.y()))
if (!qt_is_finite(p.x()) || !qt_is_finite(p.y()))
return false;
const_cast<QQuickContext2D *>(this)->m_path.setFillRule(state.fillRule);

View File

@ -39,19 +39,48 @@
#include "qquickanchors_p_p.h"
#include "qquickitem.h"
#include "qquickitem_p.h"
#include <qqmlinfo.h>
QT_BEGIN_NAMESPACE
static Q_ALWAYS_INLINE QQuickItem *readParentItem(const QQuickItem *item)
{
return QQuickItemPrivate::get(item)->parentItem;
}
static Q_ALWAYS_INLINE qreal readX(const QQuickItem *item)
{
return QQuickItemPrivate::get(item)->x;
}
static Q_ALWAYS_INLINE qreal readY(const QQuickItem *item)
{
return QQuickItemPrivate::get(item)->y;
}
static Q_ALWAYS_INLINE qreal readWidth(const QQuickItem *item)
{
return QQuickItemPrivate::get(item)->width;
}
static Q_ALWAYS_INLINE qreal readHeight(const QQuickItem *item)
{
return QQuickItemPrivate::get(item)->height;
}
static Q_ALWAYS_INLINE qreal readBaselineOffset(const QQuickItem *item)
{
return QQuickItemPrivate::get(item)->baselineOffset;
}
//TODO: should we cache relationships, so we don't have to check each time (parent-child or sibling)?
//TODO: support non-parent, non-sibling (need to find lowest common ancestor)
static inline qreal hcenter(QQuickItem const *item)
static inline qreal hcenter(const QQuickItem *item)
{
qreal width = item->width();
qreal width = readWidth(item);
if (QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors) {
if (!QQuickAnchorsPrivate::get(anchors)->centerAligned)
return width / 2;
@ -63,9 +92,9 @@ static inline qreal hcenter(QQuickItem const *item)
return width / 2;
}
static inline qreal vcenter(QQuickItem const *item)
static inline qreal vcenter(const QQuickItem *item)
{
qreal height = item->height();
qreal height = readHeight(item);
if (QQuickAnchors *anchors = QQuickItemPrivate::get(item)->_anchors) {
if (!QQuickAnchorsPrivate::get(anchors)->centerAligned)
return height / 2;
@ -78,30 +107,30 @@ static inline qreal vcenter(QQuickItem const *item)
}
//local position
static qreal position(QQuickItem const *item, QQuickAnchorLine::AnchorLine anchorLine)
static inline qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
{
qreal ret = 0.0;
switch (anchorLine) {
case QQuickAnchorLine::Left:
ret = item->x();
case QQuickAnchors::LeftAnchor:
ret = readX(item);
break;
case QQuickAnchorLine::Right:
ret = item->x() + item->width();
case QQuickAnchors::RightAnchor:
ret = readX(item) + readWidth(item);
break;
case QQuickAnchorLine::Top:
ret = item->y();
case QQuickAnchors::TopAnchor:
ret = readY(item);
break;
case QQuickAnchorLine::Bottom:
ret = item->y() + item->height();
case QQuickAnchors::BottomAnchor:
ret = readY(item) + readHeight(item);
break;
case QQuickAnchorLine::HCenter:
ret = item->x() + hcenter(item);
case QQuickAnchors::HCenterAnchor:
ret = readX(item) + hcenter(item);
break;
case QQuickAnchorLine::VCenter:
ret = item->y() + vcenter(item);
case QQuickAnchors::VCenterAnchor:
ret = readY(item) + vcenter(item);
break;
case QQuickAnchorLine::Baseline:
ret = item->y() + item->baselineOffset();
case QQuickAnchors::BaselineAnchor:
ret = readY(item) + readBaselineOffset(item);
break;
default:
break;
@ -111,30 +140,30 @@ static qreal position(QQuickItem const *item, QQuickAnchorLine::AnchorLine ancho
}
//position when origin is 0,0
static qreal adjustedPosition(QQuickItem *item, QQuickAnchorLine::AnchorLine anchorLine)
static inline qreal adjustedPosition(QQuickItem *item, QQuickAnchors::Anchor anchorLine)
{
qreal ret = 0.0;
switch (anchorLine) {
case QQuickAnchorLine::Left:
case QQuickAnchors::LeftAnchor:
ret = 0.0;
break;
case QQuickAnchorLine::Right:
ret = item->width();
case QQuickAnchors::RightAnchor:
ret = readWidth(item);
break;
case QQuickAnchorLine::Top:
case QQuickAnchors::TopAnchor:
ret = 0.0;
break;
case QQuickAnchorLine::Bottom:
ret = item->height();
case QQuickAnchors::BottomAnchor:
ret = readHeight(item);
break;
case QQuickAnchorLine::HCenter:
case QQuickAnchors::HCenterAnchor:
ret = hcenter(item);
break;
case QQuickAnchorLine::VCenter:
case QQuickAnchors::VCenterAnchor:
ret = vcenter(item);
break;
case QQuickAnchorLine::Baseline:
ret = item->baselineOffset();
case QQuickAnchors::BaselineAnchor:
ret = readBaselineOffset(item);
break;
default:
break;
@ -154,13 +183,13 @@ QQuickAnchors::~QQuickAnchors()
d->inDestructor = true;
d->remDepend(d->fill);
d->remDepend(d->centerIn);
d->remDepend(d->left.item);
d->remDepend(d->right.item);
d->remDepend(d->top.item);
d->remDepend(d->bottom.item);
d->remDepend(d->vCenter.item);
d->remDepend(d->hCenter.item);
d->remDepend(d->baseline.item);
d->remDepend(d->leftAnchorItem);
d->remDepend(d->rightAnchorItem);
d->remDepend(d->topAnchorItem);
d->remDepend(d->bottomAnchorItem);
d->remDepend(d->vCenterAnchorItem);
d->remDepend(d->hCenterAnchorItem);
d->remDepend(d->baselineAnchorItem);
}
void QQuickAnchorsPrivate::fillChanged()
@ -174,12 +203,13 @@ void QQuickAnchorsPrivate::fillChanged()
qreal horizontalMargin = q->mirrored() ? rightMargin : leftMargin;
if (fill == item->parentItem()) { //child-parent
if (fill == readParentItem(item)) { //child-parent
setItemPos(QPointF(horizontalMargin, topMargin));
} else if (fill->parentItem() == item->parentItem()) { //siblings
setItemPos(QPointF(fill->x()+horizontalMargin, fill->y()+topMargin));
} else if (readParentItem(fill) == readParentItem(item)) { //siblings
setItemPos(QPointF(readX(fill)+horizontalMargin, readY(fill) + topMargin));
}
setItemSize(QSizeF(fill->width()-leftMargin-rightMargin, fill->height()-topMargin-bottomMargin));
setItemSize(QSizeF(readWidth(fill) - leftMargin - rightMargin,
readHeight(fill) - topMargin - bottomMargin));
--updatingFill;
} else {
@ -199,12 +229,12 @@ void QQuickAnchorsPrivate::centerInChanged()
++updatingCenterIn;
qreal effectiveHCenterOffset = q->mirrored() ? -hCenterOffset : hCenterOffset;
if (centerIn == item->parentItem()) {
QPointF p(hcenter(item->parentItem()) - hcenter(item) + effectiveHCenterOffset,
vcenter(item->parentItem()) - vcenter(item) + vCenterOffset);
if (centerIn == readParentItem(item)) {
QPointF p(hcenter(readParentItem(item)) - hcenter(item) + effectiveHCenterOffset,
vcenter(readParentItem(item)) - vcenter(item) + vCenterOffset);
setItemPos(p);
} else if (centerIn->parentItem() == item->parentItem()) {
} else if (readParentItem(centerIn) == readParentItem(item)) {
QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + effectiveHCenterOffset,
centerIn->y() + vcenter(centerIn) - vcenter(item) + vCenterOffset);
setItemPos(p);
@ -225,32 +255,32 @@ void QQuickAnchorsPrivate::clearItem(QQuickItem *item)
fill = 0;
if (centerIn == item)
centerIn = 0;
if (left.item == item) {
left.item = 0;
if (leftAnchorItem == item) {
leftAnchorItem = 0;
usedAnchors &= ~QQuickAnchors::LeftAnchor;
}
if (right.item == item) {
right.item = 0;
if (rightAnchorItem == item) {
rightAnchorItem = 0;
usedAnchors &= ~QQuickAnchors::RightAnchor;
}
if (top.item == item) {
top.item = 0;
if (topAnchorItem == item) {
topAnchorItem = 0;
usedAnchors &= ~QQuickAnchors::TopAnchor;
}
if (bottom.item == item) {
bottom.item = 0;
if (bottomAnchorItem == item) {
bottomAnchorItem = 0;
usedAnchors &= ~QQuickAnchors::BottomAnchor;
}
if (vCenter.item == item) {
vCenter.item = 0;
if (vCenterAnchorItem == item) {
vCenterAnchorItem = 0;
usedAnchors &= ~QQuickAnchors::VCenterAnchor;
}
if (hCenter.item == item) {
hCenter.item = 0;
if (hCenterAnchorItem == item) {
hCenterAnchorItem = 0;
usedAnchors &= ~QQuickAnchors::HCenterAnchor;
}
if (baseline.item == item) {
baseline.item = 0;
if (baselineAnchorItem == item) {
baselineAnchorItem = 0;
usedAnchors &= ~QQuickAnchors::BaselineAnchor;
}
}
@ -263,7 +293,7 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
return dependency;
if (fill == controlItem) {
if (controlItem == item->parentItem())
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::SizeChange;
else //sibling
dependency |= QQuickItemPrivate::GeometryChange;
@ -271,27 +301,27 @@ int QQuickAnchorsPrivate::calculateDependency(QQuickItem *controlItem)
}
if (centerIn == controlItem) {
if (controlItem == item->parentItem())
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::SizeChange;
else //sibling
dependency |= QQuickItemPrivate::GeometryChange;
return dependency; //exit early
}
if ((usedAnchors & QQuickAnchors::LeftAnchor && left.item == controlItem) ||
(usedAnchors & QQuickAnchors::RightAnchor && right.item == controlItem) ||
(usedAnchors & QQuickAnchors::HCenterAnchor && hCenter.item == controlItem)) {
if (controlItem == item->parentItem())
if ((usedAnchors & QQuickAnchors::LeftAnchor && leftAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::RightAnchor && rightAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::HCenterAnchor && hCenterAnchorItem == controlItem)) {
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::WidthChange;
else //sibling
dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::XChange | QQuickItemPrivate::WidthChange);
}
if ((usedAnchors & QQuickAnchors::TopAnchor && top.item == controlItem) ||
(usedAnchors & QQuickAnchors::BottomAnchor && bottom.item == controlItem) ||
(usedAnchors & QQuickAnchors::VCenterAnchor && vCenter.item == controlItem) ||
(usedAnchors & QQuickAnchors::BaselineAnchor && baseline.item == controlItem)) {
if (controlItem == item->parentItem())
if ((usedAnchors & QQuickAnchors::TopAnchor && topAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::BottomAnchor && bottomAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::VCenterAnchor && vCenterAnchorItem == controlItem) ||
(usedAnchors & QQuickAnchors::BaselineAnchor && baselineAnchorItem == controlItem)) {
if (controlItem == readParentItem(item))
dependency |= QQuickItemPrivate::HeightChange;
else //sibling
dependency |= QFlags<QQuickItemPrivate::GeometryChangeType>(QQuickItemPrivate::YChange | QQuickItemPrivate::HeightChange);
@ -422,13 +452,13 @@ void QQuickAnchorsPrivate::updateOnComplete()
QQuickItem *dependencies[9];
dependencies[0] = fill;
dependencies[1] = centerIn;
dependencies[2] = left.item;
dependencies[3] = right.item;
dependencies[4] = hCenter.item;
dependencies[5] = top.item;
dependencies[6] = bottom.item;
dependencies[7] = vCenter.item;
dependencies[8] = baseline.item;
dependencies[2] = leftAnchorItem;
dependencies[3] = rightAnchorItem;
dependencies[4] = hCenterAnchorItem;
dependencies[5] = topAnchorItem;
dependencies[6] = bottomAnchorItem;
dependencies[7] = vCenterAnchorItem;
dependencies[8] = baselineAnchorItem;
std::sort(dependencies, dependencies + 9);
@ -447,22 +477,38 @@ void QQuickAnchorsPrivate::updateOnComplete()
void QQuickAnchorsPrivate::update()
{
fillChanged();
centerInChanged();
if (usedAnchors & QQuickAnchorLine::Horizontal_Mask)
updateHorizontalAnchors();
if (usedAnchors & QQuickAnchorLine::Vertical_Mask)
updateVerticalAnchors();
if (!isItemComplete())
return;
if (fill) {
fillChanged();
} else if (centerIn) {
centerInChanged();
} else {
if (usedAnchors & QQuickAnchors::Horizontal_Mask)
updateHorizontalAnchors();
if (usedAnchors & QQuickAnchors::Vertical_Mask)
updateVerticalAnchors();
}
}
void QQuickAnchorsPrivate::itemGeometryChanged(QQuickItem *, const QRectF &newG, const QRectF &oldG)
{
fillChanged();
centerInChanged();
if ((usedAnchors & QQuickAnchorLine::Horizontal_Mask) && (newG.x() != oldG.x() || newG.width() != oldG.width()))
updateHorizontalAnchors();
if ((usedAnchors & QQuickAnchorLine::Vertical_Mask) && (newG.y() != oldG.y() || newG.height() != oldG.height()))
updateVerticalAnchors();
if (!isItemComplete())
return;
if (fill) {
fillChanged();
} else if (centerIn) {
centerInChanged();
} else {
if ((usedAnchors & QQuickAnchors::Horizontal_Mask)
&& (newG.x() != oldG.x() || newG.width() != oldG.width()))
updateHorizontalAnchors();
if ((usedAnchors & QQuickAnchors::Vertical_Mask)
&& (newG.y() != oldG.y() || newG.height() != oldG.height()))
updateVerticalAnchors();
}
}
QQuickItem *QQuickAnchors::fill() const
@ -484,7 +530,7 @@ void QQuickAnchors::setFill(QQuickItem *f)
emit fillChanged();
return;
}
if (f != d->item->parentItem() && f->parentItem() != d->item->parentItem()){
if (f != readParentItem(d->item) && readParentItem(f) != readParentItem(d->item)){
qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
return;
}
@ -520,7 +566,7 @@ void QQuickAnchors::setCenterIn(QQuickItem* c)
emit centerInChanged();
return;
}
if (c != d->item->parentItem() && c->parentItem() != d->item->parentItem()){
if (c != readParentItem(d->item) && readParentItem(c) != readParentItem(d->item)){
qmlInfo(d->item) << tr("Cannot anchor to an item that isn't a parent or sibling.");
return;
}
@ -537,29 +583,31 @@ void QQuickAnchors::resetCenterIn()
setCenterIn(0);
}
bool QQuickAnchorsPrivate::calcStretch(const QQuickAnchorLine &edge1,
const QQuickAnchorLine &edge2,
qreal offset1,
qreal offset2,
QQuickAnchorLine::AnchorLine line,
qreal &stretch)
bool QQuickAnchorsPrivate::calcStretch(QQuickItem *edge1Item,
QQuickAnchors::Anchor edge1Line,
QQuickItem *edge2Item,
QQuickAnchors::Anchor edge2Line,
qreal offset1,
qreal offset2,
QQuickAnchors::Anchor line,
qreal &stretch)
{
bool edge1IsParent = (edge1.item == item->parentItem());
bool edge2IsParent = (edge2.item == item->parentItem());
bool edge1IsSibling = (edge1.item->parentItem() == item->parentItem());
bool edge2IsSibling = (edge2.item->parentItem() == item->parentItem());
bool edge1IsParent = (edge1Item == readParentItem(item));
bool edge2IsParent = (edge2Item == readParentItem(item));
bool edge1IsSibling = (readParentItem(edge1Item) == readParentItem(item));
bool edge2IsSibling = (readParentItem(edge2Item) == readParentItem(item));
bool invalid = false;
if ((edge2IsParent && edge1IsParent) || (edge2IsSibling && edge1IsSibling)) {
stretch = (position(edge2.item, edge2.anchorLine) + offset2)
- (position(edge1.item, edge1.anchorLine) + offset1);
stretch = (position(edge2Item, edge2Line) + offset2)
- (position(edge1Item, edge1Line) + offset1);
} else if (edge2IsParent && edge1IsSibling) {
stretch = (position(edge2.item, edge2.anchorLine) + offset2)
- (position(item->parentItem(), line)
+ position(edge1.item, edge1.anchorLine) + offset1);
stretch = (position(edge2Item, edge2Line) + offset2)
- (position(readParentItem(item), line)
+ position(edge1Item, edge1Line) + offset1);
} else if (edge2IsSibling && edge1IsParent) {
stretch = (position(item->parentItem(), line) + position(edge2.item, edge2.anchorLine) + offset2)
- (position(edge1.item, edge1.anchorLine) + offset1);
stretch = (position(readParentItem(item), line) + position(edge2Item, edge2Line) + offset2)
- (position(edge1Item, edge1Line) + offset1);
} else
invalid = true;
@ -578,52 +626,60 @@ void QQuickAnchorsPrivate::updateVerticalAnchors()
bool invalid = true;
qreal height = 0.0;
if (usedAnchors & QQuickAnchors::BottomAnchor) {
invalid = calcStretch(top, bottom, topMargin, -bottomMargin, QQuickAnchorLine::Top, height);
invalid = calcStretch(topAnchorItem, topAnchorLine,
bottomAnchorItem, bottomAnchorLine,
topMargin, -bottomMargin, QQuickAnchors::TopAnchor, height);
} else if (usedAnchors & QQuickAnchors::VCenterAnchor) {
invalid = calcStretch(top, vCenter, topMargin, vCenterOffset, QQuickAnchorLine::Top, height);
invalid = calcStretch(topAnchorItem, topAnchorLine,
vCenterAnchorItem, vCenterAnchorLine,
topMargin, vCenterOffset, QQuickAnchors::TopAnchor, height);
height *= 2;
}
if (!invalid)
setItemHeight(height);
//Handle top
if (top.item == item->parentItem()) {
setItemY(adjustedPosition(top.item, top.anchorLine) + topMargin);
} else if (top.item->parentItem() == item->parentItem()) {
setItemY(position(top.item, top.anchorLine) + topMargin);
if (topAnchorItem == readParentItem(item)) {
setItemY(adjustedPosition(topAnchorItem, topAnchorLine) + topMargin);
} else if (readParentItem(topAnchorItem) == readParentItem(item)) {
setItemY(position(topAnchorItem, topAnchorLine) + topMargin);
}
} else if (usedAnchors & QQuickAnchors::BottomAnchor) {
//Handle stretching (top + bottom case is handled above)
if (usedAnchors & QQuickAnchors::VCenterAnchor) {
qreal height = 0.0;
bool invalid = calcStretch(vCenter, bottom, vCenterOffset, -bottomMargin,
QQuickAnchorLine::Top, height);
bool invalid = calcStretch(vCenterAnchorItem, vCenterAnchorLine,
bottomAnchorItem, bottomAnchorLine,
vCenterOffset, -bottomMargin, QQuickAnchors::TopAnchor,
height);
if (!invalid)
setItemHeight(height*2);
}
//Handle bottom
if (bottom.item == item->parentItem()) {
setItemY(adjustedPosition(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
} else if (bottom.item->parentItem() == item->parentItem()) {
setItemY(position(bottom.item, bottom.anchorLine) - item->height() - bottomMargin);
if (bottomAnchorItem == readParentItem(item)) {
setItemY(adjustedPosition(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin);
} else if (readParentItem(bottomAnchorItem) == readParentItem(item)) {
setItemY(position(bottomAnchorItem, bottomAnchorLine) - readHeight(item) - bottomMargin);
}
} else if (usedAnchors & QQuickAnchors::VCenterAnchor) {
//(stetching handled above)
//Handle vCenter
if (vCenter.item == item->parentItem()) {
setItemY(adjustedPosition(vCenter.item, vCenter.anchorLine)
if (vCenterAnchorItem == readParentItem(item)) {
setItemY(adjustedPosition(vCenterAnchorItem, vCenterAnchorLine)
- vcenter(item) + vCenterOffset);
} else if (vCenter.item->parentItem() == item->parentItem()) {
setItemY(position(vCenter.item, vCenter.anchorLine) - vcenter(item) + vCenterOffset);
} else if (readParentItem(vCenterAnchorItem) == readParentItem(item)) {
setItemY(position(vCenterAnchorItem, vCenterAnchorLine) - vcenter(item) + vCenterOffset);
}
} else if (usedAnchors & QQuickAnchors::BaselineAnchor) {
//Handle baseline
if (baseline.item == item->parentItem()) {
setItemY(adjustedPosition(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
} else if (baseline.item->parentItem() == item->parentItem()) {
setItemY(position(baseline.item, baseline.anchorLine) - item->baselineOffset() + baselineOffset);
if (baselineAnchorItem == readParentItem(item)) {
setItemY(adjustedPosition(baselineAnchorItem, baselineAnchorLine)
- readBaselineOffset(item) + baselineOffset);
} else if (readParentItem(baselineAnchorItem) == readParentItem(item)) {
setItemY(position(baselineAnchorItem, baselineAnchorLine)
- readBaselineOffset(item) + baselineOffset);
}
}
--updatingVerticalAnchor;
@ -633,12 +689,12 @@ void QQuickAnchorsPrivate::updateVerticalAnchors()
}
}
inline QQuickAnchorLine::AnchorLine reverseAnchorLine(QQuickAnchorLine::AnchorLine anchorLine)
static inline QQuickAnchors::Anchor reverseAnchorLine(QQuickAnchors::Anchor anchorLine)
{
if (anchorLine == QQuickAnchorLine::Left) {
return QQuickAnchorLine::Right;
} else if (anchorLine == QQuickAnchorLine::Right) {
return QQuickAnchorLine::Left;
if (anchorLine == QQuickAnchors::LeftAnchor) {
return QQuickAnchors::RightAnchor;
} else if (anchorLine == QQuickAnchors::RightAnchor) {
return QQuickAnchors::LeftAnchor;
} else {
return anchorLine;
}
@ -653,26 +709,30 @@ void QQuickAnchorsPrivate::updateHorizontalAnchors()
if (updatingHorizontalAnchor < 3) {
++updatingHorizontalAnchor;
qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset;
QQuickAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter;
QQuickItem *effectiveLeftItem, *effectiveRightItem, *effectiveHorizontalCenterItem;
QQuickAnchors::Anchor effectiveLeftLine, effectiveRightLine, effectiveHorizontalCenterLine;
QQuickAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor;
if (q->mirrored()) {
effectiveLeftAnchor = QQuickAnchors::RightAnchor;
effectiveRightAnchor = QQuickAnchors::LeftAnchor;
effectiveLeft.item = right.item;
effectiveLeft.anchorLine = reverseAnchorLine(right.anchorLine);
effectiveRight.item = left.item;
effectiveRight.anchorLine = reverseAnchorLine(left.anchorLine);
effectiveHorizontalCenter.item = hCenter.item;
effectiveHorizontalCenter.anchorLine = reverseAnchorLine(hCenter.anchorLine);
effectiveLeftItem = rightAnchorItem;
effectiveLeftLine = reverseAnchorLine(rightAnchorLine);
effectiveRightItem = leftAnchorItem;
effectiveRightLine = reverseAnchorLine(leftAnchorLine);
effectiveHorizontalCenterItem = hCenterAnchorItem;
effectiveHorizontalCenterLine = reverseAnchorLine(hCenterAnchorLine);
effectiveLeftMargin = rightMargin;
effectiveRightMargin = leftMargin;
effectiveHorizontalCenterOffset = -hCenterOffset;
} else {
effectiveLeftAnchor = QQuickAnchors::LeftAnchor;
effectiveRightAnchor = QQuickAnchors::RightAnchor;
effectiveLeft = left;
effectiveRight = right;
effectiveHorizontalCenter = hCenter;
effectiveLeftItem = leftAnchorItem;
effectiveLeftLine = leftAnchorLine;
effectiveRightItem = rightAnchorItem;
effectiveRightLine = rightAnchorLine;
effectiveHorizontalCenterItem = hCenterAnchorItem;
effectiveHorizontalCenterLine = hCenterAnchorLine;
effectiveLeftMargin = leftMargin;
effectiveRightMargin = rightMargin;
effectiveHorizontalCenterOffset = hCenterOffset;
@ -683,42 +743,53 @@ void QQuickAnchorsPrivate::updateHorizontalAnchors()
bool invalid = true;
qreal width = 0.0;
if (usedAnchors & effectiveRightAnchor) {
invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QQuickAnchorLine::Left, width);
invalid = calcStretch(effectiveLeftItem, effectiveLeftLine,
effectiveRightItem, effectiveRightLine,
effectiveLeftMargin, -effectiveRightMargin,
QQuickAnchors::LeftAnchor, width);
} else if (usedAnchors & QQuickAnchors::HCenterAnchor) {
invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QQuickAnchorLine::Left, width);
invalid = calcStretch(effectiveLeftItem, effectiveLeftLine,
effectiveHorizontalCenterItem, effectiveHorizontalCenterLine,
effectiveLeftMargin, effectiveHorizontalCenterOffset,
QQuickAnchors::LeftAnchor, width);
width *= 2;
}
if (!invalid)
setItemWidth(width);
//Handle left
if (effectiveLeft.item == item->parentItem()) {
setItemX(adjustedPosition(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
} else if (effectiveLeft.item->parentItem() == item->parentItem()) {
setItemX(position(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin);
if (effectiveLeftItem == readParentItem(item)) {
setItemX(adjustedPosition(effectiveLeftItem, effectiveLeftLine) + effectiveLeftMargin);
} else if (readParentItem(effectiveLeftItem) == readParentItem(item)) {
setItemX(position(effectiveLeftItem, effectiveLeftLine) + effectiveLeftMargin);
}
} else if (usedAnchors & effectiveRightAnchor) {
//Handle stretching (left + right case is handled in updateLeftAnchor)
if (usedAnchors & QQuickAnchors::HCenterAnchor) {
qreal width = 0.0;
bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin,
QQuickAnchorLine::Left, width);
bool invalid = calcStretch(effectiveHorizontalCenterItem,
effectiveHorizontalCenterLine,
effectiveRightItem, effectiveRightLine,
effectiveHorizontalCenterOffset, -effectiveRightMargin,
QQuickAnchors::LeftAnchor, width);
if (!invalid)
setItemWidth(width*2);
}
//Handle right
if (effectiveRight.item == item->parentItem()) {
setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
} else if (effectiveRight.item->parentItem() == item->parentItem()) {
setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - item->width() - effectiveRightMargin);
if (effectiveRightItem == readParentItem(item)) {
setItemX(adjustedPosition(effectiveRightItem, effectiveRightLine)
- readWidth(item) - effectiveRightMargin);
} else if (readParentItem(effectiveRightItem) == readParentItem(item)) {
setItemX(position(effectiveRightItem, effectiveRightLine)
- readWidth(item) - effectiveRightMargin);
}
} else if (usedAnchors & QQuickAnchors::HCenterAnchor) {
//Handle hCenter
if (effectiveHorizontalCenter.item == item->parentItem()) {
setItemX(adjustedPosition(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
} else if (effectiveHorizontalCenter.item->parentItem() == item->parentItem()) {
setItemX(position(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset);
if (effectiveHorizontalCenterItem == readParentItem(item)) {
setItemX(adjustedPosition(effectiveHorizontalCenterItem, effectiveHorizontalCenterLine) - hcenter(item) + effectiveHorizontalCenterOffset);
} else if (readParentItem(effectiveHorizontalCenterItem) == readParentItem(item)) {
setItemX(position(effectiveHorizontalCenterItem, effectiveHorizontalCenterLine) - hcenter(item) + effectiveHorizontalCenterOffset);
}
}
--updatingHorizontalAnchor;
@ -731,13 +802,14 @@ void QQuickAnchorsPrivate::updateHorizontalAnchors()
QQuickAnchorLine QQuickAnchors::top() const
{
Q_D(const QQuickAnchors);
return d->top;
return QQuickAnchorLine(d->topAnchorItem, d->topAnchorLine);
}
void QQuickAnchors::setTop(const QQuickAnchorLine &edge)
{
Q_D(QQuickAnchors);
if (!d->checkVAnchorValid(edge) || d->top == edge)
if (!d->checkVAnchorValid(edge) ||
(d->topAnchorItem == edge.item && d->topAnchorLine == edge.anchorLine))
return;
d->usedAnchors |= TopAnchor;
@ -747,10 +819,11 @@ void QQuickAnchors::setTop(const QQuickAnchorLine &edge)
return;
}
QQuickItem *oldTop = d->top.item;
d->top = edge;
QQuickItem *oldTop = d->topAnchorItem;
d->topAnchorItem = edge.item;
d->topAnchorLine = edge.anchorLine;
d->remDepend(oldTop);
d->addDepend(d->top.item);
d->addDepend(d->topAnchorItem);
emit topChanged();
d->updateVerticalAnchors();
}
@ -759,8 +832,9 @@ void QQuickAnchors::resetTop()
{
Q_D(QQuickAnchors);
d->usedAnchors &= ~TopAnchor;
d->remDepend(d->top.item);
d->top = QQuickAnchorLine();
d->remDepend(d->topAnchorItem);
d->topAnchorItem = Q_NULLPTR;
d->topAnchorLine = QQuickAnchors::InvalidAnchor;
emit topChanged();
d->updateVerticalAnchors();
}
@ -768,13 +842,14 @@ void QQuickAnchors::resetTop()
QQuickAnchorLine QQuickAnchors::bottom() const
{
Q_D(const QQuickAnchors);
return d->bottom;
return QQuickAnchorLine(d->bottomAnchorItem, d->bottomAnchorLine);
}
void QQuickAnchors::setBottom(const QQuickAnchorLine &edge)
{
Q_D(QQuickAnchors);
if (!d->checkVAnchorValid(edge) || d->bottom == edge)
if (!d->checkVAnchorValid(edge) ||
(d->bottomAnchorItem == edge.item && d->bottomAnchorLine == edge.anchorLine))
return;
d->usedAnchors |= BottomAnchor;
@ -784,10 +859,11 @@ void QQuickAnchors::setBottom(const QQuickAnchorLine &edge)
return;
}
QQuickItem *oldBottom = d->bottom.item;
d->bottom = edge;
QQuickItem *oldBottom = d->bottomAnchorItem;
d->bottomAnchorItem = edge.item;
d->bottomAnchorLine = edge.anchorLine;
d->remDepend(oldBottom);
d->addDepend(d->bottom.item);
d->addDepend(d->bottomAnchorItem);
emit bottomChanged();
d->updateVerticalAnchors();
}
@ -796,8 +872,9 @@ void QQuickAnchors::resetBottom()
{
Q_D(QQuickAnchors);
d->usedAnchors &= ~BottomAnchor;
d->remDepend(d->bottom.item);
d->bottom = QQuickAnchorLine();
d->remDepend(d->bottomAnchorItem);
d->bottomAnchorItem = Q_NULLPTR;
d->bottomAnchorLine = QQuickAnchors::InvalidAnchor;
emit bottomChanged();
d->updateVerticalAnchors();
}
@ -805,13 +882,14 @@ void QQuickAnchors::resetBottom()
QQuickAnchorLine QQuickAnchors::verticalCenter() const
{
Q_D(const QQuickAnchors);
return d->vCenter;
return QQuickAnchorLine(d->vCenterAnchorItem, d->vCenterAnchorLine);
}
void QQuickAnchors::setVerticalCenter(const QQuickAnchorLine &edge)
{
Q_D(QQuickAnchors);
if (!d->checkVAnchorValid(edge) || d->vCenter == edge)
if (!d->checkVAnchorValid(edge) ||
(d->vCenterAnchorItem == edge.item && d->vCenterAnchorLine == edge.anchorLine))
return;
d->usedAnchors |= VCenterAnchor;
@ -821,10 +899,11 @@ void QQuickAnchors::setVerticalCenter(const QQuickAnchorLine &edge)
return;
}
QQuickItem *oldVCenter = d->vCenter.item;
d->vCenter = edge;
QQuickItem *oldVCenter = d->vCenterAnchorItem;
d->vCenterAnchorItem = edge.item;
d->vCenterAnchorLine = edge.anchorLine;
d->remDepend(oldVCenter);
d->addDepend(d->vCenter.item);
d->addDepend(d->vCenterAnchorItem);
emit verticalCenterChanged();
d->updateVerticalAnchors();
}
@ -833,8 +912,9 @@ void QQuickAnchors::resetVerticalCenter()
{
Q_D(QQuickAnchors);
d->usedAnchors &= ~VCenterAnchor;
d->remDepend(d->vCenter.item);
d->vCenter = QQuickAnchorLine();
d->remDepend(d->vCenterAnchorItem);
d->vCenterAnchorItem = Q_NULLPTR;
d->vCenterAnchorLine = QQuickAnchors::InvalidAnchor;
emit verticalCenterChanged();
d->updateVerticalAnchors();
}
@ -842,13 +922,14 @@ void QQuickAnchors::resetVerticalCenter()
QQuickAnchorLine QQuickAnchors::baseline() const
{
Q_D(const QQuickAnchors);
return d->baseline;
return QQuickAnchorLine(d->baselineAnchorItem, d->baselineAnchorLine);
}
void QQuickAnchors::setBaseline(const QQuickAnchorLine &edge)
{
Q_D(QQuickAnchors);
if (!d->checkVAnchorValid(edge) || d->baseline == edge)
if (!d->checkVAnchorValid(edge) ||
(d->baselineAnchorItem == edge.item && d->baselineAnchorLine == edge.anchorLine))
return;
d->usedAnchors |= BaselineAnchor;
@ -858,10 +939,11 @@ void QQuickAnchors::setBaseline(const QQuickAnchorLine &edge)
return;
}
QQuickItem *oldBaseline = d->baseline.item;
d->baseline = edge;
QQuickItem *oldBaseline = d->baselineAnchorItem;
d->baselineAnchorItem = edge.item;
d->baselineAnchorLine = edge.anchorLine;
d->remDepend(oldBaseline);
d->addDepend(d->baseline.item);
d->addDepend(d->baselineAnchorItem);
emit baselineChanged();
d->updateVerticalAnchors();
}
@ -870,8 +952,9 @@ void QQuickAnchors::resetBaseline()
{
Q_D(QQuickAnchors);
d->usedAnchors &= ~BaselineAnchor;
d->remDepend(d->baseline.item);
d->baseline = QQuickAnchorLine();
d->remDepend(d->baselineAnchorItem);
d->baselineAnchorItem = Q_NULLPTR;
d->baselineAnchorLine = QQuickAnchors::InvalidAnchor;
emit baselineChanged();
d->updateVerticalAnchors();
}
@ -879,13 +962,14 @@ void QQuickAnchors::resetBaseline()
QQuickAnchorLine QQuickAnchors::left() const
{
Q_D(const QQuickAnchors);
return d->left;
return QQuickAnchorLine(d->leftAnchorItem, d->leftAnchorLine);
}
void QQuickAnchors::setLeft(const QQuickAnchorLine &edge)
{
Q_D(QQuickAnchors);
if (!d->checkHAnchorValid(edge) || d->left == edge)
if (!d->checkHAnchorValid(edge) ||
(d->leftAnchorItem == edge.item && d->leftAnchorLine == edge.anchorLine))
return;
d->usedAnchors |= LeftAnchor;
@ -895,10 +979,11 @@ void QQuickAnchors::setLeft(const QQuickAnchorLine &edge)
return;
}
QQuickItem *oldLeft = d->left.item;
d->left = edge;
QQuickItem *oldLeft = d->leftAnchorItem;
d->leftAnchorItem = edge.item;
d->leftAnchorLine = edge.anchorLine;
d->remDepend(oldLeft);
d->addDepend(d->left.item);
d->addDepend(d->leftAnchorItem);
emit leftChanged();
d->updateHorizontalAnchors();
}
@ -907,8 +992,9 @@ void QQuickAnchors::resetLeft()
{
Q_D(QQuickAnchors);
d->usedAnchors &= ~LeftAnchor;
d->remDepend(d->left.item);
d->left = QQuickAnchorLine();
d->remDepend(d->leftAnchorItem);
d->leftAnchorItem = Q_NULLPTR;
d->leftAnchorLine = QQuickAnchors::InvalidAnchor;
emit leftChanged();
d->updateHorizontalAnchors();
}
@ -916,13 +1002,14 @@ void QQuickAnchors::resetLeft()
QQuickAnchorLine QQuickAnchors::right() const
{
Q_D(const QQuickAnchors);
return d->right;
return QQuickAnchorLine(d->rightAnchorItem, d->rightAnchorLine);
}
void QQuickAnchors::setRight(const QQuickAnchorLine &edge)
{
Q_D(QQuickAnchors);
if (!d->checkHAnchorValid(edge) || d->right == edge)
if (!d->checkHAnchorValid(edge) ||
(d->rightAnchorItem == edge.item && d->rightAnchorLine == edge.anchorLine))
return;
d->usedAnchors |= RightAnchor;
@ -932,10 +1019,11 @@ void QQuickAnchors::setRight(const QQuickAnchorLine &edge)
return;
}
QQuickItem *oldRight = d->right.item;
d->right = edge;
QQuickItem *oldRight = d->rightAnchorItem;
d->rightAnchorItem = edge.item;
d->rightAnchorLine = edge.anchorLine;
d->remDepend(oldRight);
d->addDepend(d->right.item);
d->addDepend(d->rightAnchorItem);
emit rightChanged();
d->updateHorizontalAnchors();
}
@ -944,8 +1032,9 @@ void QQuickAnchors::resetRight()
{
Q_D(QQuickAnchors);
d->usedAnchors &= ~RightAnchor;
d->remDepend(d->right.item);
d->right = QQuickAnchorLine();
d->remDepend(d->rightAnchorItem);
d->rightAnchorItem = Q_NULLPTR;
d->rightAnchorLine = QQuickAnchors::InvalidAnchor;
emit rightChanged();
d->updateHorizontalAnchors();
}
@ -953,13 +1042,14 @@ void QQuickAnchors::resetRight()
QQuickAnchorLine QQuickAnchors::horizontalCenter() const
{
Q_D(const QQuickAnchors);
return d->hCenter;
return QQuickAnchorLine(d->hCenterAnchorItem, d->hCenterAnchorLine);
}
void QQuickAnchors::setHorizontalCenter(const QQuickAnchorLine &edge)
{
Q_D(QQuickAnchors);
if (!d->checkHAnchorValid(edge) || d->hCenter == edge)
if (!d->checkHAnchorValid(edge) ||
(d->hCenterAnchorItem == edge.item && d->hCenterAnchorLine == edge.anchorLine))
return;
d->usedAnchors |= HCenterAnchor;
@ -969,10 +1059,11 @@ void QQuickAnchors::setHorizontalCenter(const QQuickAnchorLine &edge)
return;
}
QQuickItem *oldHCenter = d->hCenter.item;
d->hCenter = edge;
QQuickItem *oldHCenter = d->hCenterAnchorItem;
d->hCenterAnchorItem = edge.item;
d->hCenterAnchorLine = edge.anchorLine;
d->remDepend(oldHCenter);
d->addDepend(d->hCenter.item);
d->addDepend(d->hCenterAnchorItem);
emit horizontalCenterChanged();
d->updateHorizontalAnchors();
}
@ -981,8 +1072,9 @@ void QQuickAnchors::resetHorizontalCenter()
{
Q_D(QQuickAnchors);
d->usedAnchors &= ~HCenterAnchor;
d->remDepend(d->hCenter.item);
d->hCenter = QQuickAnchorLine();
d->remDepend(d->hCenterAnchorItem);
d->hCenterAnchorItem = Q_NULLPTR;
d->hCenterAnchorLine = QQuickAnchors::InvalidAnchor;
emit horizontalCenterChanged();
d->updateHorizontalAnchors();
}
@ -1230,7 +1322,7 @@ void QQuickAnchors::setBaselineOffset(qreal offset)
QQuickAnchors::Anchors QQuickAnchors::usedAnchors() const
{
Q_D(const QQuickAnchors);
return d->usedAnchors;
return static_cast<QQuickAnchors::Anchors>(d->usedAnchors);
}
bool QQuickAnchorsPrivate::checkHValid() const
@ -1250,10 +1342,11 @@ bool QQuickAnchorsPrivate::checkHAnchorValid(QQuickAnchorLine anchor) const
if (!anchor.item) {
qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to a null item.");
return false;
} else if (anchor.anchorLine & QQuickAnchorLine::Vertical_Mask) {
} else if (anchor.anchorLine & QQuickAnchors::Vertical_Mask) {
qmlInfo(item) << QQuickAnchors::tr("Cannot anchor a horizontal edge to a vertical edge.");
return false;
} else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
} else if (anchor.item != readParentItem(item)
&& readParentItem(anchor.item) != readParentItem(item)) {
qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
return false;
} else if (anchor.item == item) {
@ -1287,10 +1380,11 @@ bool QQuickAnchorsPrivate::checkVAnchorValid(QQuickAnchorLine anchor) const
if (!anchor.item) {
qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to a null item.");
return false;
} else if (anchor.anchorLine & QQuickAnchorLine::Horizontal_Mask) {
} else if (anchor.anchorLine & QQuickAnchors::Horizontal_Mask) {
qmlInfo(item) << QQuickAnchors::tr("Cannot anchor a vertical edge to a horizontal edge.");
return false;
} else if (anchor.item != item->parentItem() && anchor.item->parentItem() != item->parentItem()){
} else if (anchor.item != readParentItem(item)
&& readParentItem(anchor.item) != readParentItem(item)) {
qmlInfo(item) << QQuickAnchors::tr("Cannot anchor to an item that isn't a parent or sibling.");
return false;
} else if (anchor.item == item){

Some files were not shown because too many files have changed in this diff Show More