From d0479bd33c7cd11e1f10de96adfaf9fabe142369 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 18 Dec 2009 18:53:20 +1000 Subject: Benchmark --- tests/benchmarks/declarative/text/tst_text.cpp | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/benchmarks/declarative/text/tst_text.cpp b/tests/benchmarks/declarative/text/tst_text.cpp index 5c57633..e69ecd8 100644 --- a/tests/benchmarks/declarative/text/tst_text.cpp +++ b/tests/benchmarks/declarative/text/tst_text.cpp @@ -58,8 +58,10 @@ public: private slots: void layout(); void paintLayoutToPixmap(); + void paintLayoutToPixmap_painterFill(); void document(); void paintDocToPixmap(); + void paintDocToPixmap_painterFill(); private: QString m_text; @@ -125,6 +127,21 @@ void tst_text::paintLayoutToPixmap() } } +void tst_text::paintLayoutToPixmap_painterFill() +{ + QTextLayout layout(m_text); + QSize size = setupTextLayout(&layout); + + QBENCHMARK { + QPixmap img(size); + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, img.width(), img.height(), Qt::transparent); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + layout.draw(&p, QPointF(0, 0)); + } +} + void tst_text::document() { QTextControl *control = new QTextControl(m_text); @@ -151,5 +168,22 @@ void tst_text::paintDocToPixmap() } } +void tst_text::paintDocToPixmap_painterFill() +{ + QTextControl *control = new QTextControl; + QTextDocument *doc = control->document(); + doc->setHtml(m_text); + QSize size = doc->size().toSize(); + + QBENCHMARK { + QPixmap img(size); + QPainter p(&img); + p.setCompositionMode(QPainter::CompositionMode_Source); + p.fillRect(0, 0, img.width(), img.height(), Qt::transparent); + p.setCompositionMode(QPainter::CompositionMode_SourceOver); + control->drawContents(&p, QRectF(QPointF(0, 0), QSizeF(size))); + } +} + QTEST_MAIN(tst_text) #include "tst_text.moc" -- cgit v0.12 From d49648884774f320473427fcea52a51ac2a4cca5 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 21 Dec 2009 09:43:33 +1000 Subject: Fix Flickable within Flickable, with parent flickable !interactive. --- .../graphicsitems/qmlgraphicsflickable.cpp | 20 ++++++++++++-------- .../graphicsitems/qmlgraphicsflickable_p.h | 3 ++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp index 393edb6..ed70b14 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflickable.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsflickable.cpp @@ -498,13 +498,16 @@ bool QmlGraphicsFlickable::isInteractive() const void QmlGraphicsFlickable::setInteractive(bool interactive) { Q_D(QmlGraphicsFlickable); - d->interactive = interactive; - if (!interactive && d->flicked) { - d->timeline.clear(); - d->vTime = d->timeline.time(); - d->flicked = false; - emit flickingChanged(); - emit flickEnded(); + if (interactive != d->interactive) { + d->interactive = interactive; + if (!interactive && d->flicked) { + d->timeline.clear(); + d->vTime = d->timeline.time(); + d->flicked = false; + emit flickingChanged(); + emit flickEnded(); + } + emit interactiveChanged(); } } @@ -1147,7 +1150,8 @@ bool QmlGraphicsFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) bool QmlGraphicsFlickable::sceneEventFilter(QGraphicsItem *i, QEvent *e) { - if (!isVisible()) + Q_D(QmlGraphicsFlickable); + if (!isVisible() || !d->interactive) return QmlGraphicsItem::sceneEventFilter(i, e); switch (e->type()) { case QEvent::GraphicsSceneMousePress: diff --git a/src/declarative/graphicsitems/qmlgraphicsflickable_p.h b/src/declarative/graphicsitems/qmlgraphicsflickable_p.h index aa29f3e..df6f6b1 100644 --- a/src/declarative/graphicsitems/qmlgraphicsflickable_p.h +++ b/src/declarative/graphicsitems/qmlgraphicsflickable_p.h @@ -72,7 +72,7 @@ class Q_DECLARATIVE_EXPORT QmlGraphicsFlickable : public QmlGraphicsItem Q_PROPERTY(bool flicking READ isFlicking NOTIFY flickingChanged) Q_PROPERTY(FlickDirection flickDirection READ flickDirection WRITE setFlickDirection NOTIFY flickDirectionChanged) - Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive) + Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged) Q_PROPERTY(int pressDelay READ pressDelay WRITE setPressDelay) Q_PROPERTY(bool atXEnd READ isAtXEnd NOTIFY isAtBoundaryChanged) @@ -159,6 +159,7 @@ Q_SIGNALS: void isAtBoundaryChanged(); void pageChanged(); void flickDirectionChanged(); + void interactiveChanged(); protected: virtual bool sceneEventFilter(QGraphicsItem *, QEvent *); -- cgit v0.12 From 944f41b814d826191a713de34cb9fdda439d14c5 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 21 Dec 2009 10:11:54 +1000 Subject: Remove unnecessary locking. --- src/declarative/util/qmlpixmapcache.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/declarative/util/qmlpixmapcache.cpp b/src/declarative/util/qmlpixmapcache.cpp index 99bcb7b..475a21e 100644 --- a/src/declarative/util/qmlpixmapcache.cpp +++ b/src/declarative/util/qmlpixmapcache.cpp @@ -84,7 +84,6 @@ private: void loadImage(Job &job); QList jobs; - Job runningJob; QMutex mutex; QWaitCondition haveJob; bool quit; @@ -119,22 +118,21 @@ void QmlImageReader::read(QmlPixmapReply *reply) Job job; job.reply = reply; jobs.append(job); - haveJob.wakeOne(); + if (jobs.count() == 1) + haveJob.wakeOne(); mutex.unlock(); } void QmlImageReader::cancel(QmlPixmapReply *reply) { mutex.lock(); - if (runningJob.reply != reply) { - QList::iterator it = jobs.begin(); - while (it != jobs.end()) { - if ((*it).reply == reply) { - jobs.erase(it); - break; - } - ++it; + QList::iterator it = jobs.begin(); + while (it != jobs.end()) { + if ((*it).reply == reply) { + jobs.erase(it); + break; } + ++it; } mutex.unlock(); } @@ -158,14 +156,12 @@ void QmlImageReader::run() haveJob.wait(&mutex); if (quit) break; - runningJob = jobs.takeFirst(); + Job runningJob = jobs.takeFirst(); runningJob.reply->addRef(); mutex.unlock(); + loadImage(runningJob); - mutex.lock(); QCoreApplication::postEvent(runningJob.reply, new QmlImageDecodeEvent(runningJob.error, runningJob.img)); - runningJob.reply = 0; - mutex.unlock(); } } -- cgit v0.12 From 53d385c01e0f99f26356716295614e3e2cff6b66 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Mon, 21 Dec 2009 10:38:27 +1000 Subject: Remove a couple of connects is ListView. --- src/declarative/graphicsitems/qmlgraphicslistview.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicslistview.cpp b/src/declarative/graphicsitems/qmlgraphicslistview.cpp index 351364e..6460a69 100644 --- a/src/declarative/graphicsitems/qmlgraphicslistview.cpp +++ b/src/declarative/graphicsitems/qmlgraphicslistview.cpp @@ -552,8 +552,7 @@ void QmlGraphicsListViewPrivate::init() { Q_Q(QmlGraphicsListView); q->setFlag(QGraphicsItem::ItemIsFocusScope); - QObject::connect(q, SIGNAL(heightChanged()), q, SLOT(refill())); - QObject::connect(q, SIGNAL(widthChanged()), q, SLOT(refill())); + addItemChangeListener(this, Geometry); QObject::connect(q, SIGNAL(movementEnded()), q, SLOT(animStopped())); q->setFlickDirection(QmlGraphicsFlickable::VerticalFlick); ::memset(sectionCache, 0, sizeof(QmlGraphicsItem*) * sectionCacheSize); -- cgit v0.12 From b0d54b07752e9e51b02eba4cb6066f91e71c3069 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 21 Dec 2009 12:01:35 +1000 Subject: Optimization: don't use QTextControl in Text element --- src/declarative/graphicsitems/qmlgraphicstext.cpp | 36 +++++++++------------- .../graphicsitems/qmlgraphicstext_p_p.h | 4 +-- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicstext.cpp b/src/declarative/graphicsitems/qmlgraphicstext.cpp index 52d68fd..459541e 100644 --- a/src/declarative/graphicsitems/qmlgraphicstext.cpp +++ b/src/declarative/graphicsitems/qmlgraphicstext.cpp @@ -50,10 +50,9 @@ #include #include #include +#include #include -#include - QT_BEGIN_NAMESPACE QML_DEFINE_TYPE(Qt,4,6,Text,QmlGraphicsText) @@ -159,11 +158,8 @@ void QmlGraphicsText::setText(const QString &n) d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n)); if (d->richText) { - if (!d->doc) - { - d->control = new QTextControl(this); - d->control->setTextInteractionFlags(Qt::TextBrowserInteraction); - d->doc = d->control->document(); + if (!d->doc) { + d->doc = new QTextDocument(this); d->doc->setDocumentMargin(0); } d->doc->setHtml(n); @@ -399,11 +395,8 @@ void QmlGraphicsText::setTextFormat(TextFormat format) d->updateSize(); d->markImgDirty(); } else if (!wasRich && d->richText) { - if (!d->doc) - { - d->control = new QTextControl(this); - d->control->setTextInteractionFlags(Qt::TextBrowserInteraction); - d->doc = d->control->document(); + if (!d->doc) { + d->doc = new QTextDocument(this); d->doc->setDocumentMargin(0); } d->doc->setHtml(d->text); @@ -643,19 +636,18 @@ QPixmap QmlGraphicsTextPrivate::richTextImage(bool drawStyle) img.fill(Qt::transparent); QPainter p(&img); + QAbstractTextDocumentLayout::PaintContext context; + if (drawStyle) { - QPalette pal = control->palette(); - pal.setColor(QPalette::Text, styleColor); - control->setPalette(pal); + context.palette.setColor(QPalette::Text, styleColor); + // ### Do we really want this? QTextOption colorOption; colorOption.setFlags(QTextOption::SuppressColors); doc->setDefaultTextOption(colorOption); } else { - QPalette pal = control->palette(); - pal.setColor(QPalette::Text, color); - control->setPalette(pal); + context.palette.setColor(QPalette::Text, color); } - control->drawContents(&p, QRectF(QPointF(0, 0), QSizeF(size))); + doc->documentLayout()->draw(&p, context); if (drawStyle) doc->setDefaultTextOption(QTextOption()); return img; @@ -790,11 +782,11 @@ void QmlGraphicsText::mousePressEvent(QGraphicsSceneMouseEvent *event) { Q_D(QmlGraphicsText); - if (!d->richText || !d->doc || d->control->anchorAt(event->pos()).isEmpty()) { + if (!d->richText || !d->doc || d->doc->documentLayout()->anchorAt(event->pos()).isEmpty()) { event->setAccepted(false); d->activeLink = QString(); } else { - d->activeLink = d->control->anchorAt(event->pos()); + d->activeLink = d->doc->documentLayout()->anchorAt(event->pos()); } // ### may malfunction if two of the same links are clicked & dragged onto each other) @@ -819,7 +811,7 @@ void QmlGraphicsText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) Q_D(QmlGraphicsText); // ### confirm the link, and send a signal out - if (d->richText && d->doc && d->activeLink == d->control->anchorAt(event->pos())) + if (d->richText && d->doc && d->activeLink == d->doc->documentLayout()->anchorAt(event->pos())) emit linkActivated(d->activeLink); else event->setAccepted(false); diff --git a/src/declarative/graphicsitems/qmlgraphicstext_p_p.h b/src/declarative/graphicsitems/qmlgraphicstext_p_p.h index 7e77c69..79d1a4f 100644 --- a/src/declarative/graphicsitems/qmlgraphicstext_p_p.h +++ b/src/declarative/graphicsitems/qmlgraphicstext_p_p.h @@ -64,7 +64,6 @@ QT_BEGIN_NAMESPACE class QTextLayout; class QTextDocument; -class QTextControl; class QmlGraphicsTextPrivate : public QmlGraphicsItemPrivate { @@ -73,7 +72,7 @@ public: QmlGraphicsTextPrivate() : color((QRgb)0), style(QmlGraphicsText::Normal), imgDirty(true), hAlign(QmlGraphicsText::AlignLeft), vAlign(QmlGraphicsText::AlignTop), elideMode(QmlGraphicsText::ElideNone), - dirty(true), wrap(false), richText(false), singleline(false), control(0), doc(0), + dirty(true), wrap(false), richText(false), singleline(false), doc(0), format(QmlGraphicsText::AutoText) { } @@ -112,7 +111,6 @@ public: bool wrap:1; bool richText:1; bool singleline:1; - QTextControl *control; QTextDocument *doc; QTextLayout layout; QSize cachedLayoutSize; -- cgit v0.12 From 8216b5d7e5c47a2f3f04b5516bda49b68bd1da15 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 21 Dec 2009 15:52:00 +1000 Subject: Simply type management --- src/declarative/qml/qmlbindingvme.cpp | 82 +++++++++++++++-------------------- 1 file changed, 35 insertions(+), 47 deletions(-) diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index ab2aed5..b239883 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -72,6 +72,10 @@ struct Register { void *typeDataPtr() { return (void *)&data; } void *typeMemory() { return (void *)data; } + int gettype() { return type; } + void settype(int t) { type = t; } + + int type; // Optional type void *data[2]; // Object stored here }; @@ -198,7 +202,6 @@ struct Instr { struct { int output; int src; - int srcType; } genericunaryop; struct { int reg; @@ -207,13 +210,11 @@ struct Instr { struct { int reg; int src; - int typeReg; int name; int subscribeIndex; } find; struct { int reg; - int typeReg; } cleanup; struct { int offset; @@ -383,8 +384,7 @@ static QmlPropertyCache::Data *findproperty(QObject *obj, return property; } -static bool findproperty(QObject *obj, - Register *output, Register *type, +static bool findproperty(QObject *obj, Register *output, QmlEnginePrivate *enginePriv, QmlBindingVME::Config *config, int subIdx, const QScriptDeclarativeClass::Identifier &name, @@ -400,7 +400,7 @@ static bool findproperty(QObject *obj, if (property->flags & QmlPropertyCache::Data::IsQObjectDerived) { void *args[] = { output->typeDataPtr(), 0 }; QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); - type->setint(QMetaType::QObjectStar); + output->settype(QMetaType::QObjectStar); } else if (property->propType == qMetaTypeId()) { QVariant v; void *args[] = { &v, 0 }; @@ -408,12 +408,12 @@ static bool findproperty(QObject *obj, if (isTerminal) { new (output->typeDataPtr()) QVariant(v); - type->setint(qMetaTypeId()); + output->settype(qMetaTypeId()); } else { bool ok; output->setQObject(variantToQObject(v, &ok)); if (!ok) return false; - type->setint(QMetaType::QObjectStar); + output->settype(QMetaType::QObjectStar); } } else { @@ -423,11 +423,11 @@ static bool findproperty(QObject *obj, if (property->propType == QMetaType::QReal) { void *args[] = { output->typeDataPtr(), 0 }; QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); - type->setint(QMetaType::QReal); + output->settype(QMetaType::QReal); } else { new (output->typeDataPtr()) QVariant(obj->metaObject()->property(property->coreIndex).read(obj)); - type->setint(qMetaTypeId()); + output->settype(qMetaTypeId()); } } @@ -442,18 +442,17 @@ static bool findproperty(QObject *obj, } static bool findproperty(Register *input, - Register *output, Register *type, + Register *output, QmlEnginePrivate *enginePriv, QmlBindingVME::Config *config, int subIdx, const QScriptDeclarativeClass::Identifier &name, bool isTerminal) { - return findproperty(input->getQObject(), output, type, enginePriv, + return findproperty(input->getQObject(), output, enginePriv, config, subIdx, name, isTerminal); } static bool findgeneric(Register *output, // value output - Register *type, // value type output QmlBindingVME::Config *config, int subIdx, // Subscription index in config QmlContextPrivate *context, // Context to search in @@ -469,17 +468,17 @@ static bool findgeneric(Register *output, // val if (contextPropertyIndex < context->idValueCount) { output->setQObject(context->idValues[contextPropertyIndex]); - type->setint(QMetaType::QObjectStar); + output->settype(QMetaType::QObjectStar); } else { const QVariant &value = context->propertyValues.at(contextPropertyIndex); if (isTerminal) { new (output->typeDataPtr()) QVariant(value); - type->setint(qMetaTypeId()); + output->settype(qMetaTypeId()); } else { bool ok; output->setQObject(variantToQObject(value, &ok)); if (!ok) return false; - type->setint(QMetaType::QObjectStar); + output->settype(QMetaType::QObjectStar); } } @@ -496,7 +495,7 @@ static bool findgeneric(Register *output, // val if (QObject *root = context->defaultObjects.isEmpty()?0:context->defaultObjects.first()) { - if (findproperty(root, output, type, enginePriv, config, subIdx, name, isTerminal)) + if (findproperty(root, output, enginePriv, config, subIdx, name, isTerminal)) return true; } @@ -792,8 +791,8 @@ void QmlBindingVME::run(const char *programData, int instrIndex, // We start the search in the parent context, as we know that the // name is not present in the current context or it would have been // found during the static compile - if (!findgeneric(registers + instr->find.reg, registers + instr->find.typeReg, - config, instr->find.subscribeIndex, QmlContextPrivate::get(context->parent), + if (!findgeneric(registers + instr->find.reg, config, instr->find.subscribeIndex, + QmlContextPrivate::get(context->parent), config->identifiers[instr->find.name].identifier, instr->type == Instr::FindGenericTerminal)) { qWarning() << "ERROR - FindGeneric*"; @@ -803,8 +802,7 @@ void QmlBindingVME::run(const char *programData, int instrIndex, case Instr::FindPropertyTerminal: case Instr::FindProperty: - if (!findproperty(registers + instr->find.src, - registers + instr->find.reg, registers + instr->find.typeReg, + if (!findproperty(registers + instr->find.src, registers + instr->find.reg, QmlEnginePrivate::get(context->engine), config, instr->find.subscribeIndex, config->identifiers[instr->find.name].identifier, @@ -816,7 +814,7 @@ void QmlBindingVME::run(const char *programData, int instrIndex, case Instr::CleanupGeneric: { - int type = registers[instr->cleanup.typeReg].getint(); + int type = registers[instr->cleanup.reg].gettype(); if (type == qMetaTypeId()) { ((QVariant *)registers[instr->cleanup.reg].typeDataPtr())->~QVariant(); } @@ -825,21 +823,21 @@ void QmlBindingVME::run(const char *programData, int instrIndex, case Instr::ConvertGenericToReal: { - int type = registers[instr->genericunaryop.srcType].getint(); + int type = registers[instr->genericunaryop.src].gettype(); registers[instr->genericunaryop.output].setqreal(toReal(registers + instr->genericunaryop.src, type)); } break; case Instr::ConvertGenericToBool: { - int type = registers[instr->genericunaryop.srcType].getint(); + int type = registers[instr->genericunaryop.src].gettype(); registers[instr->genericunaryop.output].setbool(toBool(registers + instr->genericunaryop.src, type)); } break; case Instr::ConvertGenericToString: { - int type = registers[instr->genericunaryop.srcType].getint(); + int type = registers[instr->genericunaryop.src].gettype(); void *regPtr = registers[instr->genericunaryop.output].typeDataPtr(); new (regPtr) QString(toString(registers + instr->genericunaryop.src, type)); } @@ -847,7 +845,7 @@ void QmlBindingVME::run(const char *programData, int instrIndex, case Instr::ConvertGenericToUrl: { - int type = registers[instr->genericunaryop.srcType].getint(); + int type = registers[instr->genericunaryop.src].gettype(); void *regPtr = registers[instr->genericunaryop.output].typeDataPtr(); new (regPtr) QUrl(toUrl(registers + instr->genericunaryop.src, type, context)); } @@ -953,10 +951,10 @@ void QmlBindingVME::dump(const QByteArray &programData) qWarning().nospace() << "NewUrl" << "\t\t\t" << instr->construct.reg; break; case Instr::CleanupString: - qWarning().nospace() << "CleanupString" << "\t\t" << instr->cleanup.reg << "\t" << instr->cleanup.typeReg; + qWarning().nospace() << "CleanupString" << "\t\t" << instr->cleanup.reg; break; case Instr::CleanupUrl: - qWarning().nospace() << "CleanupUrl" << "\t\t" << instr->cleanup.reg << "\t" << instr->cleanup.typeReg; + qWarning().nospace() << "CleanupUrl" << "\t\t" << instr->cleanup.reg; break; case Instr::Fetch: qWarning().nospace() << "Fetch" << "\t\t\t" << instr->fetch.output << "\t" << instr->fetch.index << "\t" << instr->fetch.objectReg; @@ -977,31 +975,31 @@ void QmlBindingVME::dump(const QByteArray &programData) qWarning().nospace() << "InitString" << "\t\t" << instr->initstring.offset << "\t" << instr->initstring.dataIdx << "\t" << instr->initstring.length; break; case Instr::FindGeneric: - qWarning().nospace() << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.typeReg << "\t" << instr->find.name; + qWarning().nospace() << "FindGeneric" << "\t\t" << instr->find.reg << "\t" << instr->find.name; break; case Instr::FindGenericTerminal: - qWarning().nospace() << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.typeReg << "\t" << instr->find.name; + qWarning().nospace() << "FindGenericTerminal" << "\t" << instr->find.reg << "\t" << instr->find.name; break; case Instr::FindProperty: - qWarning().nospace() << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name; + qWarning().nospace() << "FindProperty" << "\t\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name; break; case Instr::FindPropertyTerminal: - qWarning().nospace() << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.typeReg << "\t" << instr->find.name; + qWarning().nospace() << "FindPropertyTerminal" << "\t" << instr->find.reg << "\t" << instr->find.src << "\t" << instr->find.name; break; case Instr::CleanupGeneric: - qWarning().nospace() << "CleanupGeneric" << "\t\t" << instr->cleanup.reg << "\t" << instr->cleanup.typeReg; + qWarning().nospace() << "CleanupGeneric" << "\t\t" << instr->cleanup.reg; break; case Instr::ConvertGenericToReal: - qWarning().nospace() << "ConvertGenericToReal" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; + qWarning().nospace() << "ConvertGenericToReal" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src; break; case Instr::ConvertGenericToBool: - qWarning().nospace() << "ConvertGenericToBool" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; + qWarning().nospace() << "ConvertGenericToBool" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src; break; case Instr::ConvertGenericToString: - qWarning().nospace() << "ConvertGenericToString" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; + qWarning().nospace() << "ConvertGenericToString" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src; break; case Instr::ConvertGenericToUrl: - qWarning().nospace() << "ConvertGenericToUrl" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src << "\t" << instr->genericunaryop.srcType; + qWarning().nospace() << "ConvertGenericToUrl" << "\t" << instr->genericunaryop.output << "\t" << instr->genericunaryop.src; break; default: qWarning().nospace() << "Unknown"; @@ -1073,35 +1071,30 @@ bool QmlBindingCompilerPrivate::compile(QmlJS::AST::Node *node) convert.type = Instr::ConvertGenericToReal; convert.genericunaryop.output = convertReg; convert.genericunaryop.src = type.reg; - convert.genericunaryop.srcType = 2; // XXX bytecode << convert; } else if (destination->type == QVariant::String) { Instr convert; convert.type = Instr::ConvertGenericToString; convert.genericunaryop.output = convertReg; convert.genericunaryop.src = type.reg; - convert.genericunaryop.srcType = 2; // XXX bytecode << convert; } else if (destination->type == QMetaType::Bool) { Instr convert; convert.type = Instr::ConvertGenericToBool; convert.genericunaryop.output = convertReg; convert.genericunaryop.src = type.reg; - convert.genericunaryop.srcType = 2; // XXX bytecode << convert; } else if (destination->type == QVariant::Url) { Instr convert; convert.type = Instr::ConvertGenericToUrl; convert.genericunaryop.output = convertReg; convert.genericunaryop.src = type.reg; - convert.genericunaryop.srcType = 2; // XXX bytecode << convert; } Instr cleanup; cleanup.type = Instr::CleanupGeneric; cleanup.cleanup.reg = type.reg; - cleanup.cleanup.typeReg = 2; // XXX bytecode << cleanup; Instr instr; @@ -1115,13 +1108,11 @@ bool QmlBindingCompilerPrivate::compile(QmlJS::AST::Node *node) Instr cleanup; cleanup.type = Instr::CleanupString; cleanup.cleanup.reg = convertReg; - cleanup.cleanup.typeReg = -1; bytecode << cleanup; } else if (destination->type == QVariant::Url) { Instr cleanup; cleanup.type = Instr::CleanupUrl; cleanup.cleanup.reg = convertReg; - cleanup.cleanup.typeReg = -1; bytecode << cleanup; } @@ -1353,7 +1344,6 @@ bool QmlBindingCompilerPrivate::parseName(AST::Node *node, Result &type) find.find.reg = reg; find.find.src = -1; - find.find.typeReg = 2; // XXX find.find.name = registerString(name); subscribeName << QString(QLatin1String("$$$Generic_") + name); @@ -1416,7 +1406,6 @@ bool QmlBindingCompilerPrivate::parseName(AST::Node *node, Result &type) prop.find.reg = reg; prop.find.src = reg; - prop.find.typeReg = 2; // XXX prop.find.name = registerString(name); if (subscription(subscribeName, &type)) prop.find.subscribeIndex = subscriptionIndex(subscribeName); @@ -1861,7 +1850,6 @@ void QmlBindingCompilerPrivate::releaseReg(int reg) Instr cleanup; (int &)cleanup.type = c.first; cleanup.cleanup.reg = reg; - cleanup.cleanup.typeReg = c.second; bytecode << cleanup; } -- cgit v0.12 From 178a508040bd43320a19ec2ae3250278d7b133bc Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 21 Dec 2009 16:40:06 +1000 Subject: More binding optimizations --- src/declarative/qml/qmlbindingvme.cpp | 157 +++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 14 deletions(-) diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index b239883..043cbb3 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -97,9 +97,11 @@ struct Instr { Real, // real_value Int, // int_value Bool, // bool_value + String, // string_value AddReal, // binaryop AddInt, // binaryop + AddString, // binaryop MinusReal, // binaryop MinusInt, // binaryop @@ -191,6 +193,11 @@ struct Instr { bool value; } bool_value; struct { + int reg; + int offset; + int length; + } string_value; + struct { int output; int src1; int src2; @@ -280,6 +287,8 @@ struct QmlBindingCompilerPrivate bool tryArith(QmlJS::AST::Node *); bool parseArith(QmlJS::AST::Node *, Result &); + bool numberArith(Result &, const Result &, const Result &, QSOperator::Op op); + bool stringArith(Result &, const Result &, const Result &, QSOperator::Op op); bool tryLogic(QmlJS::AST::Node *); bool parseLogic(QmlJS::AST::Node *, Result &); @@ -302,6 +311,7 @@ struct QmlBindingCompilerPrivate void registerCleanup(int reg, int cleanup, int cleanupType = 0); void releaseReg(int); + int registerLiteralString(const QString &); int registerString(const QString &); QHash > registeredStrings; QByteArray data; @@ -675,6 +685,11 @@ void QmlBindingVME::run(const char *programData, int instrIndex, registers[instr->bool_value.reg].setbool(instr->bool_value.value); break; + case Instr::String: + new (registers[instr->bool_value.reg].getstringptr()) + QString((QChar *)(data + instr->string_value.offset), instr->string_value.length); + break; + case Instr::AddReal: registers[instr->binaryop.output].setqreal(registers[instr->binaryop.src1].getqreal() + registers[instr->binaryop.src2].getqreal()); @@ -684,6 +699,12 @@ void QmlBindingVME::run(const char *programData, int instrIndex, registers[instr->binaryop.output].setint(registers[instr->binaryop.src1].getint() + registers[instr->binaryop.src2].getint()); break; + + case Instr::AddString: + new (registers[instr->binaryop.output].getstringptr()) + QString(*registers[instr->binaryop.src1].getstringptr() + + *registers[instr->binaryop.src2].getstringptr()); + break; case Instr::MinusReal: registers[instr->binaryop.output].setqreal(registers[instr->binaryop.src1].getqreal() - @@ -911,12 +932,18 @@ void QmlBindingVME::dump(const QByteArray &programData) case Instr::Bool: qWarning().nospace() << "Bool" << "\t\t\t" << instr->bool_value.reg << "\t" << instr->bool_value.value; break; + case Instr::String: + qWarning().nospace() << "String" << "\t\t\t" << instr->string_value.reg << "\t" << instr->string_value.offset << "\t" << instr->string_value.length; + break; case Instr::AddReal: qWarning().nospace() << "AddReal" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; break; case Instr::AddInt: qWarning().nospace() << "AddInt" << "\t\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; break; + case Instr::AddString: + qWarning().nospace() << "AddString" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; + break; case Instr::MinusReal: qWarning().nospace() << "MinusReal" << "\t\t" << instr->binaryop.output << "\t" << instr->binaryop.src1 << "\t" << instr->binaryop.src2; break; @@ -1451,17 +1478,25 @@ bool QmlBindingCompilerPrivate::parseArith(QmlJS::AST::Node *node, Result &type) if (!parseExpression(expression->left, lhs)) return false; if (!parseExpression(expression->right, rhs)) return false; - if (lhs.type != QVariant::Int & - lhs.type != QMetaType::QReal) - return false; - - if (rhs.type != QVariant::Int & - rhs.type != QMetaType::QReal) + if ((lhs.type == QVariant::Int || lhs.type == QMetaType::QReal) && + (rhs.type == QVariant::Int || rhs.type == QMetaType::QReal)) + return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else if(expression->op == QSOperator::Sub) + return numberArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else if ((lhs.type == QMetaType::QString || lhs.unknownType) && + (rhs.type == QMetaType::QString || rhs.unknownType) && + (lhs.type == QMetaType::QString || rhs.type == QMetaType::QString)) + return stringArith(type, lhs, rhs, (QSOperator::Op)expression->op); + else return false; +} +bool QmlBindingCompilerPrivate::numberArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op) +{ bool nativeReal = rhs.type == QMetaType::QReal || - lhs.type == QMetaType::QReal; - + lhs.type == QMetaType::QReal || + lhs.unknownType || + rhs.unknownType; if (nativeReal && lhs.type == QMetaType::Int) { Instr convert; @@ -1479,18 +1514,40 @@ bool QmlBindingCompilerPrivate::parseArith(QmlJS::AST::Node *node, Result &type) bytecode << convert; } + int lhsTmp = -1; + int rhsTmp = -1; + if (lhs.unknownType) { + lhsTmp = acquireReg(); + + Instr conv; + conv.type = Instr::ConvertGenericToReal; + conv.genericunaryop.output = lhsTmp; + conv.genericunaryop.src = lhs.reg; + bytecode << conv; + } + + if (rhs.unknownType) { + rhsTmp = acquireReg(); + + Instr conv; + conv.type = Instr::ConvertGenericToReal; + conv.genericunaryop.output = rhsTmp; + conv.genericunaryop.src = rhs.reg; + bytecode << conv; + } + Instr arith; - if (expression->op == QSOperator::Add) { + if (op == QSOperator::Add) { arith.type = nativeReal?Instr::AddReal:Instr::AddInt; - } else if (expression->op == QSOperator::Sub) { + } else if (op == QSOperator::Sub) { arith.type = nativeReal?Instr::MinusReal:Instr::MinusInt; } else { qFatal("Unsupported arithmetic operator"); } arith.binaryop.output = type.reg; - arith.binaryop.src1 = lhs.reg; - arith.binaryop.src2 = rhs.reg; + arith.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp; + arith.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp; bytecode << arith; type.metaObject = 0; @@ -1498,12 +1555,58 @@ bool QmlBindingCompilerPrivate::parseArith(QmlJS::AST::Node *node, Result &type) type.subscriptionSet.unite(lhs.subscriptionSet); type.subscriptionSet.unite(rhs.subscriptionSet); + if (lhsTmp != -1) releaseReg(lhsTmp); + if (rhsTmp != -1) releaseReg(rhsTmp); releaseReg(lhs.reg); releaseReg(rhs.reg); return true; } +bool QmlBindingCompilerPrivate::stringArith(Result &type, const Result &lhs, const Result &rhs, QSOperator::Op op) +{ + if (op != QSOperator::Add) + return false; + + int lhsTmp = -1; + int rhsTmp = -1; + + if (lhs.unknownType) { + lhsTmp = acquireReg(Instr::CleanupString); + + Instr convert; + convert.type = Instr::ConvertGenericToString; + convert.genericunaryop.output = lhsTmp; + convert.genericunaryop.src = lhs.reg; + bytecode << convert; + } + + if (rhs.unknownType) { + rhsTmp = acquireReg(Instr::CleanupString); + + Instr convert; + convert.type = Instr::ConvertGenericToString; + convert.genericunaryop.output = rhsTmp; + convert.genericunaryop.src = rhs.reg; + bytecode << convert; + } + + type.reg = acquireReg(Instr::CleanupString); + type.type = QMetaType::QString; + + Instr add; + add.type = Instr::AddString; + add.binaryop.output = type.reg; + add.binaryop.src1 = (lhsTmp == -1)?lhs.reg:lhsTmp; + add.binaryop.src2 = (rhsTmp == -1)?rhs.reg:rhsTmp; + bytecode << add; + + if (lhsTmp != -1) releaseReg(lhsTmp); + if (rhsTmp != -1) releaseReg(rhsTmp); + + return true; +} + bool QmlBindingCompilerPrivate::tryLogic(QmlJS::AST::Node *node) { if (node->kind != AST::Node::Kind_BinaryExpression) @@ -1645,7 +1748,8 @@ bool QmlBindingCompilerPrivate::tryConstant(QmlJS::AST::Node *node) { return node->kind == AST::Node::Kind_TrueLiteral || node->kind == AST::Node::Kind_FalseLiteral || - node->kind == AST::Node::Kind_NumericLiteral; + node->kind == AST::Node::Kind_NumericLiteral || + node->kind == AST::Node::Kind_StringLiteral; } bool QmlBindingCompilerPrivate::parseConstant(QmlJS::AST::Node *node, Result &type) @@ -1678,6 +1782,11 @@ bool QmlBindingCompilerPrivate::parseConstant(QmlJS::AST::Node *node, Result &ty instr.real_value.value = qreal(static_cast(node)->value); bytecode << instr; return true; + } else if (node->kind == AST::Node::Kind_StringLiteral) { + QString str = static_cast(node)->value->asString(); + type.type = QMetaType::QString; + type.reg = registerLiteralString(str); + return true; } else { return false; } @@ -1857,6 +1966,26 @@ void QmlBindingCompilerPrivate::releaseReg(int reg) registers &= ~mask; } +// Returns a reg +int QmlBindingCompilerPrivate::registerLiteralString(const QString &str) +{ + QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar)); + int offset = data.count(); + data += strdata; + + int reg = acquireReg(Instr::CleanupString); + + Instr string; + string.type = Instr::String; + string.string_value.reg = reg; + string.string_value.offset = offset; + string.string_value.length = str.length(); + bytecode << string; + + return reg; +} + +// Returns an identifier offset int QmlBindingCompilerPrivate::registerString(const QString &string) { Q_ASSERT(!string.isEmpty()); @@ -1869,7 +1998,7 @@ int QmlBindingCompilerPrivate::registerString(const QString &string) data += strdata; iter = registeredStrings.insert(string, qMakePair(registeredStrings.count(), rv)); - } + } Instr reg; reg.type = Instr::InitString; -- cgit v0.12 From 0a4ab50b6ed19a2d3fbe7b1f9d9614ad5d9b339e Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 21 Dec 2009 18:04:14 +1000 Subject: Optimization: signal connections --- .../graphicsitems/qmlgraphicsimagebase.cpp | 23 +++++++++++++++++++--- src/declarative/util/qmlpixmapcache.cpp | 17 ++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/declarative/graphicsitems/qmlgraphicsimagebase.cpp b/src/declarative/graphicsitems/qmlgraphicsimagebase.cpp index 9dd9f1b..e3b98aa 100644 --- a/src/declarative/graphicsitems/qmlgraphicsimagebase.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsimagebase.cpp @@ -116,9 +116,26 @@ void QmlGraphicsImageBase::setSource(const QUrl &url) if (status != QmlPixmapReply::Ready && status != QmlPixmapReply::Error) { QmlPixmapReply *reply = QmlPixmapCache::request(qmlEngine(this), d->url); d->pendingPixmapCache = true; - connect(reply, SIGNAL(finished()), this, SLOT(requestFinished())); - connect(reply, SIGNAL(downloadProgress(qint64,qint64)), - this, SLOT(requestProgress(qint64,qint64))); + + static int replyDownloadProgress = -1; + static int replyFinished = -1; + static int thisRequestProgress = -1; + static int thisRequestFinished = -1; + if (replyDownloadProgress == -1) { + replyDownloadProgress = + QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); + replyFinished = + QmlPixmapReply::staticMetaObject.indexOfSignal("finished()"); + thisRequestProgress = + QmlGraphicsImageBase::staticMetaObject.indexOfSlot("requestProgress(qint64,qint64)"); + thisRequestFinished = + QmlGraphicsImageBase::staticMetaObject.indexOfSlot("requestFinished()"); + } + + QMetaObject::connect(reply, replyFinished, this, + thisRequestFinished, Qt::DirectConnection); + QMetaObject::connect(reply, replyDownloadProgress, this, + thisRequestProgress, Qt::DirectConnection); } else { //### should be unified with requestFinished if (status == QmlPixmapReply::Ready) { diff --git a/src/declarative/util/qmlpixmapcache.cpp b/src/declarative/util/qmlpixmapcache.cpp index 475a21e..3307ff8 100644 --- a/src/declarative/util/qmlpixmapcache.cpp +++ b/src/declarative/util/qmlpixmapcache.cpp @@ -240,8 +240,21 @@ QmlPixmapReply::QmlPixmapReply(const QString &key, QNetworkReply *reply) : QObject(*new QmlPixmapReplyPrivate(key, reply), 0) { Q_D(QmlPixmapReply); - connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), this, SIGNAL(downloadProgress(qint64,qint64))); - connect(d->reply, SIGNAL(finished()), this, SLOT(networkRequestDone())); + + static int replyDownloadProgress = -1; + static int replyFinished = -1; + static int thisDownloadProgress = -1; + static int thisNetworkRequestDone = -1; + + if (replyDownloadProgress == -1) { + replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); + replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()"); + thisDownloadProgress = QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); + thisNetworkRequestDone = QmlPixmapReply::staticMetaObject.indexOfSlot("networkRequestDone()"); + } + + QMetaObject::connect(d->reply, replyDownloadProgress, this, thisDownloadProgress, Qt::DirectConnection); + QMetaObject::connect(d->reply, replyFinished, this, thisNetworkRequestDone); } QmlPixmapReply::~QmlPixmapReply() -- cgit v0.12 From cf7a6fee7af112ca3d6e4c511417b9e42cfc6716 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 21 Dec 2009 18:31:42 +1000 Subject: Empty URLs should not be resolved --- src/declarative/qml/qmlbindingvme.cpp | 11 +++++++---- src/declarative/qml/qmlbindingvme_p.h | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index 043cbb3..2e3dcca 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -237,6 +237,8 @@ struct Program { quint32 signalTableOffset; quint16 subscriptions; quint16 identifiers; + quint16 instructionCount; + quint16 dummy; const char *data() const { return ((const char *)this) + sizeof(Program); } const Instr *instructions() const { return (const Instr *)(data() + dataLength); } @@ -588,7 +590,7 @@ inline static QUrl toUrl(Register *reg, int type, QmlContextPrivate *context, bo return QUrl(); } - if (base.isRelative()) + if (!base.isEmpty() && base.isRelative()) return context->url.resolved(base); else return base; @@ -881,16 +883,16 @@ void QmlBindingVME::run(const char *programData, int instrIndex, } } -void QmlBindingVME::dump(const QByteArray &programData) +void QmlBindingVME::dump(const char *programData) { - const Program *program = (const Program *)programData.constData(); + const Program *program = (const Program *)programData; qWarning() << "Program.bindings:" << program->bindings; qWarning() << "Program.dataLength:" << program->dataLength; qWarning() << "Program.subscriptions:" << program->subscriptions; qWarning() << "Program.indentifiers:" << program->identifiers; - int count = (programData.size() - sizeof(Program) - program->dataLength) / sizeof(Instr); + int count = program->instructionCount; const Instr *instr = program->instructions(); while (count--) { @@ -2147,6 +2149,7 @@ QByteArray QmlBindingCompiler::program() const prog.dataLength = 4 * ((data.size() + 3) / 4); prog.subscriptions = d->committed.subscriptionIds.count(); prog.identifiers = d->committed.registeredStrings.count(); + prog.instructionCount = bytecode.count(); int size = sizeof(Program) + bytecode.count() * sizeof(Instr); size += prog.dataLength; diff --git a/src/declarative/qml/qmlbindingvme_p.h b/src/declarative/qml/qmlbindingvme_p.h index de73037..ceaf2b3 100644 --- a/src/declarative/qml/qmlbindingvme_p.h +++ b/src/declarative/qml/qmlbindingvme_p.h @@ -85,7 +85,7 @@ public: static void run(const char *program, int instr, Config *config, QmlContextPrivate *context, QObject **scopes, QObject **outputs); - static void dump(const QByteArray &); + static void dump(const char *); }; class QmlBindingCompilerPrivate; -- cgit v0.12 From 5861eec545692ad1b6df00dde28ad044cfe1477b Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 21 Dec 2009 18:47:36 +1000 Subject: Improve binding optimizer's subscription logic --- src/declarative/qml/qmlbindingvme.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlbindingvme.cpp index 2e3dcca..01c7a4b 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlbindingvme.cpp @@ -409,6 +409,9 @@ static bool findproperty(QObject *obj, Register *output, QmlPropertyCache::Data *property = findproperty(obj, name, enginePriv, local); if (property) { + if (subIdx != -1) + subscribe(obj, property->notifyIndex, subIdx, config); + if (property->flags & QmlPropertyCache::Data::IsQObjectDerived) { void *args[] = { output->typeDataPtr(), 0 }; QMetaObject::metacall(obj, QMetaObject::ReadProperty, property->coreIndex, args); @@ -444,9 +447,6 @@ static bool findproperty(QObject *obj, Register *output, } - if (subIdx != -1) - subscribe(obj, property->notifyIndex, subIdx, config); - return true; } else { return false; @@ -476,8 +476,13 @@ static bool findgeneric(Register *output, // val while (context) { int contextPropertyIndex = context->propertyNames?context->propertyNames->value(name):-1; + + if (contextPropertyIndex != -1) { + subscribe(QmlContextPrivate::get(context), contextPropertyIndex + context->notifyIndex, + subIdx, config); + if (contextPropertyIndex < context->idValueCount) { output->setQObject(context->idValues[contextPropertyIndex]); output->settype(QMetaType::QObjectStar); -- cgit v0.12