diff options
author | Anton Kudryavtsev <a.kudryavtsev@netris.ru> | 2016-05-26 14:45:31 +0300 |
---|---|---|
committer | Anton Kudryavtsev <a.kudryavtsev@netris.ru> | 2016-08-12 18:50:22 +0000 |
commit | 6f15de1d2da9c83d7fca1d5c8243c0d69a1390ee (patch) | |
tree | cbd01a5cf15c8618eca94a0d6949717798a28aff /src/quick | |
parent | 9010dd0e767c407f107aacfe6be145229e3ba793 (diff) |
PathView: fix infinite construction/destruction loop
... when all (or almost all) items are in the cache.
When all items are in cache, check lower bound is equal
to upper_bound.
In rare cases, especially when almost all items are in cache,
the inserting code was used (not only appending and prepending).
In this code there was not bound check before creation of item
and there was such situation:
1. Create item by inserting code (without bound check)
2. At the next call of refill() remove this item by life cycle
because this item does not meet the conditions. And go to step 1.
In other words at the first call we create some item, at the second
remove this item. And again.
So we had infinite construction/destruction loop. To break it we
should check position of new item before creation in inserting code
too (like we do in appending and prepending code).
Task-number: QTBUG-37815
Change-Id: I015cdeb67ca5fcd06c34b3145b49cbd3e38d4078
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
Diffstat (limited to 'src/quick')
-rw-r--r-- | src/quick/items/qquickpathview.cpp | 44 |
1 files changed, 26 insertions, 18 deletions
diff --git a/src/quick/items/qquickpathview.cpp b/src/quick/items/qquickpathview.cpp index 1dbdd10303..f858b18c84 100644 --- a/src/quick/items/qquickpathview.cpp +++ b/src/quick/items/qquickpathview.cpp @@ -289,6 +289,8 @@ qreal QQuickPathViewPrivate::positionOfIndex(qreal index) const // account the circular space. bool QQuickPathViewPrivate::isInBound(qreal position, qreal lower, qreal upper) const { + if (lower == upper) + return true; if (lower > upper) { if (position > upper && position > lower) position -= mappedRange; @@ -2047,27 +2049,33 @@ void QQuickPathView::refill() idx = startIdx; QQuickItem *lastItem = d->items[0]; while (idx != endIdx) { - //This gets the reference from the delegate model, and will not re-create - QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); - if (!item) { - waiting = true; - break; - } - if (!d->items.contains(item)) { //We found a hole - nextPos = d->positionOfIndex(idx); - qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos << (d->currentIndex == idx ? "current" : "") << "items count was" << d->items.count(); - if (d->currentIndex == idx) { - currentVisible = true; - d->currentItemOffset = nextPos; + nextPos = d->positionOfIndex(idx); + if (d->isInBound(nextPos, d->mappedRange - d->mappedCache, 1.0 + d->mappedCache)) { + //This gets the reference from the delegate model, and will not re-create + QQuickItem *item = d->getItem(idx, idx+1, nextPos >= 1.0); + if (!item) { + waiting = true; + break; } - int lastListIdx = d->items.indexOf(lastItem); - d->items.insert(lastListIdx + 1, item); - d->updateItem(item, nextPos); - } else { - d->releaseItem(item); + + if (!d->items.contains(item)) { //We found a hole + qCDebug(lcItemViewDelegateLifecycle) << "middle insert" << idx << "@" << nextPos + << (d->currentIndex == idx ? "current" : "") + << "items count was" << d->items.count(); + if (d->currentIndex == idx) { + currentVisible = true; + d->currentItemOffset = nextPos; + } + int lastListIdx = d->items.indexOf(lastItem); + d->items.insert(lastListIdx + 1, item); + d->updateItem(item, nextPos); + } else { + d->releaseItem(item); + } + + lastItem = item; } - lastItem = item; ++idx; if (idx >= d->modelCount) idx = 0; |