aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/qquickanimatedimage.cpp33
-rw-r--r--src/quick/items/qquickanimatedimage_p.h1
-rw-r--r--src/quick/items/qquickflickable.cpp8
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickpathview.cpp20
-rw-r--r--src/quick/items/qquicktextnodeengine.cpp97
-rw-r--r--src/quick/items/qquicktextnodeengine_p.h29
-rw-r--r--src/quick/items/qquickwindow.cpp3
-rw-r--r--src/quick/items/qquickwindow_p.h4
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();