From 6f15de1d2da9c83d7fca1d5c8243c0d69a1390ee Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Thu, 26 May 2016 14:45:31 +0300 Subject: 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 --- src/quick/items/qquickpathview.cpp | 44 ++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'src/quick/items/qquickpathview.cpp') 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; -- cgit v1.2.3