diff options
Diffstat (limited to 'src/quick/items')
-rw-r--r-- | src/quick/items/qquickanimatedimage.cpp | 33 | ||||
-rw-r--r-- | src/quick/items/qquickanimatedimage_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquickflickable.cpp | 8 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquickpathview.cpp | 20 | ||||
-rw-r--r-- | src/quick/items/qquicktextnodeengine.cpp | 97 | ||||
-rw-r--r-- | src/quick/items/qquicktextnodeengine_p.h | 29 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 3 | ||||
-rw-r--r-- | src/quick/items/qquickwindow_p.h | 4 |
9 files changed, 151 insertions, 46 deletions
diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index a989e81176..49fef12467 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -104,7 +104,13 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine about its state, such as the current frame and total number of frames. The result is an animated image with a simple progress indicator underneath it. - \b Note: Unlike images, animated images are not cached or shared internally. + \b Note: When animated images are cached, every frame of the animation will be cached. + + Set cache to false if you are playing a long or large animation and you + want to conserve memory. + + If the image data comes from a sequential device (e.g. a socket), + AnimatedImage can only loop if cache is set to true. \clearfloat \snippet qml/animatedimage.qml document @@ -126,6 +132,7 @@ QQuickPixmap* QQuickAnimatedImagePrivate::infoForCurrentFrame(QQmlEngine *engine QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent) : QQuickImage(*(new QQuickAnimatedImagePrivate), parent) { + QObject::connect(this, &QQuickImageBase::cacheChanged, this, &QQuickAnimatedImage::onCacheChanged); } QQuickAnimatedImage::~QQuickAnimatedImage() @@ -372,7 +379,8 @@ void QQuickAnimatedImage::movieRequestFinished() this, SLOT(playingStatusChanged())); connect(d->_movie, SIGNAL(frameChanged(int)), this, SLOT(movieUpdate())); - d->_movie->setCacheMode(QMovie::CacheAll); + if (d->cache) + d->_movie->setCacheMode(QMovie::CacheAll); d->status = Ready; emit statusChanged(d->status); @@ -406,6 +414,11 @@ void QQuickAnimatedImage::movieUpdate() { Q_D(QQuickAnimatedImage); + if (!d->cache) { + qDeleteAll(d->frameMap); + d->frameMap.clear(); + } + if (d->_movie) { d->setPixmap(*d->infoForCurrentFrame(qmlEngine(this))); emit frameChanged(); @@ -426,6 +439,22 @@ void QQuickAnimatedImage::playingStatusChanged() } } +void QQuickAnimatedImage::onCacheChanged() +{ + Q_D(QQuickAnimatedImage); + if (!cache()) { + qDeleteAll(d->frameMap); + d->frameMap.clear(); + if (d->_movie) { + d->_movie->setCacheMode(QMovie::CacheNone); + } + } else { + if (d->_movie) { + d->_movie->setCacheMode(QMovie::CacheAll); + } + } +} + QSize QQuickAnimatedImage::sourceSize() { Q_D(QQuickAnimatedImage); diff --git a/src/quick/items/qquickanimatedimage_p.h b/src/quick/items/qquickanimatedimage_p.h index de37cd8209..409933817f 100644 --- a/src/quick/items/qquickanimatedimage_p.h +++ b/src/quick/items/qquickanimatedimage_p.h @@ -84,6 +84,7 @@ private Q_SLOTS: void movieUpdate(); void movieRequestFinished(); void playingStatusChanged(); + void onCacheChanged(); protected: void load() Q_DECL_OVERRIDE; diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 9c03a6db28..a9396051ab 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -1041,7 +1041,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp } if (fuzzyLessThanOrEqualTo(minY, newY)) { newY = minY; - rejectY = vData.pressPos == minY && vData.move.value() == minY && dy > 0; + rejectY |= vData.pressPos == minY && vData.move.value() == minY && dy > 0; } } else { qreal vel = velocity.y() / QML_FLICK_OVERSHOOTFRICTION; @@ -1101,7 +1101,7 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp } if (fuzzyLessThanOrEqualTo(minX, newX)) { newX = minX; - rejectX = hData.pressPos == minX && hData.move.value() == minX && dx > 0; + rejectX |= hData.pressPos == minX && hData.move.value() == minX && dx > 0; } } else { qreal vel = velocity.x() / QML_FLICK_OVERSHOOTFRICTION; @@ -1527,13 +1527,13 @@ qreal QQuickFlickable::minXExtent() const qreal QQuickFlickable::maxXExtent() const { Q_D(const QQuickFlickable); - return width() - vWidth() - d->hData.endMargin; + return qMin<qreal>(0, width() - vWidth() - d->hData.endMargin); } /* returns -ve */ qreal QQuickFlickable::maxYExtent() const { Q_D(const QQuickFlickable); - return height() - vHeight() - d->vData.endMargin; + return qMin<qreal>(0, height() - vHeight() - d->vData.endMargin); } void QQuickFlickable::componentComplete() diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index f2ad487a0b..64d8bd0ede 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -58,7 +58,7 @@ #include <private/qpodvector_p.h> #include <QtQuick/private/qquickstate_p.h> -#include <private/qqmlnullablevalue_p_p.h> +#include <private/qqmlnullablevalue_p.h> #include <private/qqmlnotifier_p.h> #include <private/qqmlglobal_p.h> #include <private/qlazilyallocated_p.h> diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index 352a939e1b..58605f79dd 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -35,6 +35,7 @@ #include "qquickpathview_p_p.h" #include "qquickwindow.h" #include "qquickflickablebehavior_p.h" //Contains flicking behavior defines +#include "qquicktext_p.h" #include <QtQuick/private/qquickstate_p.h> #include <private/qqmlglobal_p.h> @@ -52,6 +53,8 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcItemViewDelegateLifecycle) + const qreal MinimumFlickVelocity = 75.0; inline qreal qmlMod(qreal x, qreal y) @@ -194,6 +197,7 @@ void QQuickPathViewPrivate::releaseItem(QQuickItem *item) { if (!item || !model) return; + qCDebug(lcItemViewDelegateLifecycle) << "release" << item; QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); itemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Geometry); QQmlInstanceModel::ReleaseFlags flags = model->release(item); @@ -824,9 +828,11 @@ void QQuickPathViewPrivate::setOffset(qreal o) Q_Q(QQuickPathView); if (offset != o) { if (isValid() && q->isComponentComplete()) { + qreal oldOffset = offset; offset = qmlMod(o, qreal(modelCount)); if (offset < 0) offset += qreal(modelCount); + qCDebug(lcItemViewDelegateLifecycle) << o << "was" << oldOffset << "now" << offset; q->refill(); } else { offset = o; @@ -1891,10 +1897,18 @@ void QQuickPathView::refill() // first move existing items and remove items off path int idx = d->firstIndex; + qCDebug(lcItemViewDelegateLifecycle) << "firstIndex" << idx << "currentIndex" << d->currentIndex << "offset" << d->offset; QList<QQuickItem*>::iterator it = d->items.begin(); while (it != d->items.end()) { qreal pos = d->positionOfIndex(idx); QQuickItem *item = *it; + if (lcItemViewDelegateLifecycle().isDebugEnabled()) { + QQuickText *text = qmlobject_cast<QQuickText*>(item); + if (text) + qCDebug(lcItemViewDelegateLifecycle) << "idx" << idx << "@" << pos << ": QQuickText" << text->objectName() << text->text().left(40); + else + qCDebug(lcItemViewDelegateLifecycle) << "idx" << idx << "@" << pos << ":" << item; + } if (pos < 1.0) { d->updateItem(item, pos); if (idx == d->currentIndex) { @@ -1907,7 +1921,7 @@ void QQuickPathView::refill() if (QQuickPathViewAttached *att = d->attached(item)) att->setOnPath(pos < 1.0); if (!d->isInBound(pos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) { -// qDebug() << "release"; + qCDebug(lcItemViewDelegateLifecycle) << "release" << idx << "@" << pos << ", !isInBound: lower" << (d->mappedRange - d->mappedCache) << "upper" << (1.0 + d->mappedCache); d->releaseItem(item); if (it == d->items.begin()) { if (++d->firstIndex >= d->modelCount) { @@ -1942,7 +1956,7 @@ void QQuickPathView::refill() } qreal pos = d->positionOfIndex(idx); while ((d->isInBound(pos, startPos, 1.0 + d->mappedCache) || !d->items.count()) && d->items.count() < count+d->cacheSize) { -// qDebug() << "append" << idx; + qCDebug(lcItemViewDelegateLifecycle) << "append" << idx << "@" << pos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); QQuickItem *item = d->getItem(idx, idx+1, pos >= 1.0); if (!item) { waiting = true; @@ -1967,7 +1981,7 @@ void QQuickPathView::refill() idx = d->modelCount - 1; pos = d->positionOfIndex(idx); while (!waiting && d->isInBound(pos, d->mappedRange - d->mappedCache, startPos) && d->items.count() < count+d->cacheSize) { -// qDebug() << "prepend" << idx; + qCDebug(lcItemViewDelegateLifecycle) << "prepend" << idx << "@" << pos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); QQuickItem *item = d->getItem(idx, idx+1, pos >= 1.0); if (!item) { waiting = true; diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 369570f657..14d305ad50 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -670,61 +670,86 @@ void QQuickTextNodeEngine::addFrameDecorations(QTextDocument *document, QTextFra } } -void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode, - QQuickText::TextStyle style, - const QColor &styleColor) +uint qHash(const QQuickTextNodeEngine::BinaryTreeNodeKey &key) { - if (m_currentLine.isValid()) - processCurrentLine(); + // Just use the default hash for pairs + return qHash(qMakePair(key.fontEngine, qMakePair(key.clipNode, + qMakePair(key.color, key.selectionState)))); +} + +void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularNodes, + QList<BinaryTreeNode *> *imageNodes) +{ + QMultiHash<BinaryTreeNodeKey, BinaryTreeNode *> map; - // Then, go through all the nodes for all lines and combine all QGlyphRuns with a common - // font, selection state and clip node. - typedef QPair<QFontEngine *, QPair<QQuickDefaultClipNode *, QPair<QRgb, int> > > KeyType; - QHash<KeyType, BinaryTreeNode *> map; - QList<BinaryTreeNode *> nodes; - QList<BinaryTreeNode *> imageNodes; for (int i = 0; i < m_processedNodes.size(); ++i) { BinaryTreeNode *node = m_processedNodes.data() + i; if (node->image.isNull()) { - QGlyphRun glyphRun = node->glyphRun; - QRawFont rawFont = glyphRun.rawFont(); + QRawFont rawFont = node->glyphRun.rawFont(); QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont); - QFontEngine *fontEngine = rawFontD->fontEngine; - KeyType key(qMakePair(fontEngine, - qMakePair(node->clipNode, - qMakePair(node->color.rgba(), int(node->selectionState))))); - - BinaryTreeNode *otherNode = map.value(key, 0); - if (otherNode != 0) { - QGlyphRun &otherGlyphRun = otherNode->glyphRun; + BinaryTreeNodeKey key(fontEngine, + node->clipNode, + node->color.rgba(), + int(node->selectionState)); + map.insertMulti(key, node); + } else { + imageNodes->append(node); + } + } - QVector<quint32> otherGlyphIndexes = otherGlyphRun.glyphIndexes(); - QVector<QPointF> otherGlyphPositions = otherGlyphRun.positions(); + QMultiHash<BinaryTreeNodeKey, BinaryTreeNode *>::const_iterator it = map.constBegin(); + while (it != map.constEnd()) { + BinaryTreeNode *primaryNode = it.value(); + regularNodes->append(primaryNode); - otherGlyphIndexes += glyphRun.glyphIndexes(); + int count = 0; + QMultiHash<BinaryTreeNodeKey, BinaryTreeNode *>::const_iterator jt; + for (jt = it; jt != map.constEnd() && jt.key() == it.key(); ++jt) + count += jt.value()->glyphRun.glyphIndexes().size(); - QVector<QPointF> glyphPositions = glyphRun.positions(); - otherGlyphPositions.reserve(otherGlyphPositions.size() + glyphPositions.size()); - for (int j = 0; j < glyphPositions.size(); ++j) { - otherGlyphPositions += glyphPositions.at(j) + (node->position - otherNode->position); - } + if (count != primaryNode->glyphRun.glyphIndexes().size()) { + QGlyphRun &glyphRun = primaryNode->glyphRun; + QVector<quint32> glyphIndexes = glyphRun.glyphIndexes(); + glyphIndexes.reserve(count); - otherGlyphRun.setGlyphIndexes(otherGlyphIndexes); - otherGlyphRun.setPositions(otherGlyphPositions); + QVector<QPointF> glyphPositions = glyphRun.positions(); + glyphPositions.reserve(count); - otherNode->ranges += node->ranges; + for (jt = it + 1; jt != map.constEnd() && jt.key() == it.key(); ++jt) { + BinaryTreeNode *otherNode = jt.value(); + glyphIndexes += otherNode->glyphRun.glyphIndexes(); + primaryNode->ranges += otherNode->ranges; - } else { - map.insert(key, node); - nodes.append(node); + QVector<QPointF> otherPositions = otherNode->glyphRun.positions(); + for (int j = 0; j < otherPositions.size(); ++j) + glyphPositions += otherPositions.at(j) + (otherNode->position - primaryNode->position); } + it = jt; + + Q_ASSERT(glyphPositions.size() == count); + Q_ASSERT(glyphIndexes.size() == count); + + glyphRun.setGlyphIndexes(glyphIndexes); + glyphRun.setPositions(glyphPositions); } else { - imageNodes.append(node); + ++it; } } +} + +void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode, + QQuickText::TextStyle style, + const QColor &styleColor) +{ + if (m_currentLine.isValid()) + processCurrentLine(); + + QList<BinaryTreeNode *> nodes; + QList<BinaryTreeNode *> imageNodes; + mergeProcessedNodes(&nodes, &imageNodes); for (int i = 0; i < m_backgrounds.size(); ++i) { const QRectF &rect = m_backgrounds.at(i).first; diff --git a/src/quick/items/qquicktextnodeengine_p.h b/src/quick/items/qquicktextnodeengine_p.h index 3441a5a973..178454b19e 100644 --- a/src/quick/items/qquicktextnodeengine_p.h +++ b/src/quick/items/qquicktextnodeengine_p.h @@ -102,6 +102,33 @@ public: static void inOrder(const QVarLengthArray<BinaryTreeNode, 16> &binaryTree, QVarLengthArray<int> *sortedIndexes, int currentIndex = 0); }; + struct BinaryTreeNodeKey + { + BinaryTreeNodeKey(QFontEngine *fe, + QQuickDefaultClipNode *cn, + QRgb col, + int selState) + : fontEngine(fe) + , clipNode(cn) + , color(col) + , selectionState(selState) + { + } + + bool operator==(const BinaryTreeNodeKey &otherKey) const + { + return fontEngine == otherKey.fontEngine + && clipNode == otherKey.clipNode + && color == otherKey.color + && selectionState == otherKey.selectionState; + } + + QFontEngine *fontEngine; + QQuickDefaultClipNode *clipNode; + QRgb color; + int selectionState; + }; + QQuickTextNodeEngine() : m_hasSelection(false), m_hasContents(false) {} bool hasContents() const { return m_hasContents; } @@ -141,6 +168,8 @@ public: int start, int end, int selectionStart, int selectionEnd); + void mergeProcessedNodes(QList<BinaryTreeNode *> *regularNodes, + QList<BinaryTreeNode *> *imageNodes); void addToSceneGraph(QQuickTextNode *parent, QQuickText::TextStyle style = QQuickText::Normal, const QColor &styleColor = QColor()); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index aabeefb317..35f4a84980 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1403,6 +1403,9 @@ bool QQuickWindow::event(QEvent *e) break; } + if (e->type() == QEvent::Type(QQuickWindowPrivate::FullUpdateRequest)) + update(); + return QWindow::event(e); } diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index c3ae6c054c..a61c0b0346 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -101,6 +101,10 @@ class Q_QUICK_PRIVATE_EXPORT QQuickWindowPrivate : public QWindowPrivate public: Q_DECLARE_PUBLIC(QQuickWindow) + enum CustomEvents { + FullUpdateRequest = QEvent::User + 1 + }; + static inline QQuickWindowPrivate *get(QQuickWindow *c) { return c->d_func(); } QQuickWindowPrivate(); |