Index: third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp |
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp |
index 9b2140e2a59e41bdc5664144d2243c98be6e0024..d4be5d85cf7adcc777287ec0ac29586d1170d453 100644 |
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp |
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp |
@@ -8,6 +8,7 @@ |
#include "platform/graphics/GraphicsLayer.h" |
#include "platform/graphics/paint/DrawingDisplayItem.h" |
#include "third_party/skia/include/core/SkPictureAnalyzer.h" |
+#include "wtf/AutoReset.h" |
#include "wtf/text/StringBuilder.h" |
#ifndef NDEBUG |
@@ -49,7 +50,7 @@ bool PaintController::useCachedDrawingIfPossible(const DisplayItemClient& client |
++m_numCachedNewItems; |
ensureNewDisplayItemListInitialCapacity(); |
if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) |
- processNewItem(m_newDisplayItemList.appendByMoving(m_currentPaintArtifact.getDisplayItemList()[cachedItem]), FromCachedItem); |
+ processNewItem(moveItemFromCurrentListToNewList(cachedItem)); |
m_nextItemToMatch = cachedItem + 1; |
// Items before m_nextItemToMatch have been copied so we don't need to index them. |
@@ -154,7 +155,7 @@ const DisplayItem* PaintController::lastDisplayItem(unsigned offset) |
return nullptr; |
} |
-void PaintController::processNewItem(DisplayItem& displayItem, NewItemSource newItemSource) |
+void PaintController::processNewItem(DisplayItem& displayItem) |
{ |
DCHECK(!m_constructionDisabled); |
@@ -181,21 +182,15 @@ void PaintController::processNewItem(DisplayItem& displayItem, NewItemSource new |
} |
#endif |
- if (isSkippingCache()) { |
- DCHECK(newItemSource == NewPainting); |
+ if (isSkippingCache()) |
displayItem.setSkippedCache(); |
- } |
if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
- if (newItemSource != FromCachedSubsequence) |
- m_currentChunkIsFromCachedSubsequence = false; |
- |
size_t lastChunkIndex = m_newPaintChunks.lastChunkIndex(); |
if (m_newPaintChunks.incrementDisplayItemIndex(displayItem)) { |
DCHECK(lastChunkIndex != m_newPaintChunks.lastChunkIndex()); |
if (lastChunkIndex != kNotFound) |
generateChunkRasterInvalidationRects(m_newPaintChunks.paintChunkAt(lastChunkIndex)); |
- m_currentChunkIsFromCachedSubsequence = true; |
} |
} |
@@ -211,8 +206,8 @@ void PaintController::processNewItem(DisplayItem& displayItem, NewItemSource new |
if (index != kNotFound) { |
#ifndef NDEBUG |
showDebugData(); |
- WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%d)\n", |
- displayItem.asDebugString().utf8().data(), m_newDisplayItemList[index].asDebugString().utf8().data(), static_cast<int>(index)); |
+ WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%zu)\n", |
+ displayItem.asDebugString().utf8().data(), m_newDisplayItemList[index].asDebugString().utf8().data(), index); |
#endif |
NOTREACHED(); |
} |
@@ -223,6 +218,13 @@ void PaintController::processNewItem(DisplayItem& displayItem, NewItemSource new |
checkUnderInvalidation(); |
} |
+DisplayItem& PaintController::moveItemFromCurrentListToNewList(size_t index) |
+{ |
+ m_itemsMovedIntoNewList.resize(m_currentPaintArtifact.getDisplayItemList().size()); |
+ m_itemsMovedIntoNewList[index] = m_newDisplayItemList.size(); |
+ return m_newDisplayItemList.appendByMoving(m_currentPaintArtifact.getDisplayItemList()[index]); |
+} |
+ |
void PaintController::updateCurrentPaintChunkProperties(const PaintChunk::Id* id, const PaintChunkProperties& newProperties) |
{ |
m_newPaintChunks.updateCurrentPaintChunkProperties(id, newProperties); |
@@ -260,7 +262,9 @@ size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con |
const Vector<size_t>& indices = it->value; |
for (size_t index : indices) { |
const DisplayItem& existingItem = list[index]; |
- DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.client); |
+ if (!existingItem.hasValidClient()) |
+ continue; |
+ DCHECK(existingItem.client() == id.client); |
if (id == existingItem.getId()) |
return index; |
} |
@@ -352,6 +356,7 @@ size_t PaintController::findOutOfOrderCachedItemForward(const DisplayItem::Id& i |
// but mark the begin and end of the subsequence for under-invalidation checking. |
void PaintController::copyCachedSubsequence(size_t& cachedItemIndex) |
{ |
+ AutoReset<size_t> subsequenceBeginIndex(&m_currentCachedSubsequenceBeginIndexInNewList, m_newDisplayItemList.size()); |
DisplayItem* cachedItem = &m_currentPaintArtifact.getDisplayItemList()[cachedItemIndex]; |
DCHECK(cachedItem->getType() == DisplayItem::kSubsequence); |
@@ -365,6 +370,7 @@ void PaintController::copyCachedSubsequence(size_t& cachedItemIndex) |
Vector<PaintChunk>::const_iterator cachedChunk; |
if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
cachedChunk = m_currentPaintArtifact.findChunkByDisplayItemIndex(cachedItemIndex); |
+ DCHECK(cachedChunk != m_currentPaintArtifact.paintChunks().end()); |
updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChunk->id : nullptr, cachedChunk->properties); |
} else { |
// This is to avoid compilation error about uninitialized variable on Windows. |
@@ -381,9 +387,10 @@ void PaintController::copyCachedSubsequence(size_t& cachedItemIndex) |
if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) { |
if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && cachedItemIndex == cachedChunk->endIndex) { |
++cachedChunk; |
+ DCHECK(cachedChunk != m_currentPaintArtifact.paintChunks().end()); |
updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChunk->id : nullptr, cachedChunk->properties); |
} |
- processNewItem(m_newDisplayItemList.appendByMoving(*cachedItem), FromCachedSubsequence); |
+ processNewItem(moveItemFromCurrentListToNewList(cachedItemIndex)); |
if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
DCHECK((!m_newPaintChunks.lastChunk().id && !cachedChunk->id) || m_newPaintChunks.lastChunk().matches(*cachedChunk)); |
} |
@@ -467,6 +474,7 @@ void PaintController::commitNewDisplayItems(const LayoutSize& offsetFromLayoutOb |
resetCurrentListIndices(); |
m_outOfOrderItemIndices.clear(); |
m_outOfOrderChunkIndices.clear(); |
+ m_itemsMovedIntoNewList.clear(); |
if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
for (const auto& chunk : m_currentPaintArtifact.paintChunks()) { |
@@ -527,7 +535,7 @@ void PaintController::appendDebugDrawingAfterCommit(const DisplayItemClient& dis |
void PaintController::generateChunkRasterInvalidationRects(PaintChunk& newChunk) |
{ |
DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
- if (m_currentChunkIsFromCachedSubsequence) |
+ if (newChunk.beginIndex >= m_currentCachedSubsequenceBeginIndexInNewList) |
return; |
if (!newChunk.id) { |
@@ -574,33 +582,44 @@ void PaintController::generateChunkRasterInvalidationRectsComparingOldChunk(Pain |
{ |
DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
- // TODO(wangxianzhu): Support raster invalidation for reordered display items without invalidating |
- // display item clients. Currently we invalidate display item clients ensuring raster invalidation. |
// TODO(wangxianzhu): Handle PaintInvalidationIncremental. |
// TODO(wangxianzhu): Optimize paint offset change. |
- // Maps from each client to the index of the first drawing-content display item of the client. |
- HashMap<const DisplayItemClient*, size_t> oldChunkClients; |
- for (size_t i = oldChunk.beginIndex; i < oldChunk.endIndex; ++i) { |
- const DisplayItem& oldItem = m_currentPaintArtifact.getDisplayItemList()[i]; |
- // oldItem.hasValidClient() indicates that the item has not been copied as a cached item into |
- // m_newDislayItemList, so the item either disappeared or changed, and needs raster invalidation. |
- if (oldItem.hasValidClient() && oldItem.drawsContent() && oldChunkClients.add(&oldItem.client(), i).isNewEntry) |
- newChunk.rasterInvalidationRects.append(m_currentPaintArtifact.getDisplayItemList().visualRect(i)); |
- } |
- |
- HashSet<const DisplayItemClient*> newChunkClients; |
- for (size_t i = newChunk.beginIndex; i < newChunk.endIndex; ++i) { |
- const DisplayItem& newItem = m_newDisplayItemList[i]; |
- if (newItem.drawsContent()) { |
- if (!clientCacheIsValid(newItem.client())) { |
- if (newChunkClients.add(&newItem.client()).isNewEntry) |
- newChunk.rasterInvalidationRects.append(newItem.client().visualRect()); |
- } else { |
- // The cached item was moved from the old chunk which should not contain any item of the client now. |
- DCHECK(!oldChunkClients.contains(&newItem.client())); |
+ HashSet<const DisplayItemClient*> invalidatedClientsInOldChunk; |
+ size_t highestMovedToIndex = 0; |
+ for (size_t oldIndex = oldChunk.beginIndex; oldIndex < oldChunk.endIndex; ++oldIndex) { |
+ const DisplayItem& oldItem = m_currentPaintArtifact.getDisplayItemList()[oldIndex]; |
+ const DisplayItemClient* clientToInvalidate = nullptr; |
+ if (!oldItem.hasValidClient()) { |
+ size_t movedToIndex = m_itemsMovedIntoNewList[oldIndex]; |
+ if (m_newDisplayItemList[movedToIndex].drawsContent()) { |
+ if (movedToIndex < newChunk.beginIndex || movedToIndex >= newChunk.endIndex) { |
+ // The item has been moved into another chunk, so need to invalidate it in the old chunk. |
+ clientToInvalidate = &m_newDisplayItemList[movedToIndex].client(); |
+ // And invalidate in the new chunk into which the item was moved. |
+ PaintChunk& movedToChunk = m_newPaintChunks.findChunkByDisplayItemIndex(movedToIndex); |
+ movedToChunk.rasterInvalidationRects.append(clientToInvalidate->visualRect()); |
+ } else if (movedToIndex < highestMovedToIndex) { |
+ // The item has been moved behind other cached items, so need to invalidate the area |
+ // that is probably exposed by the item moved earlier. |
+ clientToInvalidate = &m_newDisplayItemList[movedToIndex].client(); |
+ } else { |
+ highestMovedToIndex = movedToIndex; |
+ } |
} |
+ } else if (oldItem.drawsContent()) { |
+ clientToInvalidate = &oldItem.client(); |
} |
+ if (clientToInvalidate && invalidatedClientsInOldChunk.add(clientToInvalidate).isNewEntry) { |
+ newChunk.rasterInvalidationRects.append(m_currentPaintArtifact.getDisplayItemList().visualRect(oldIndex)); |
+ } |
+ } |
+ |
+ HashSet<const DisplayItemClient*> invalidatedClientsInNewChunk; |
+ for (size_t newIndex = newChunk.beginIndex; newIndex < newChunk.endIndex; ++newIndex) { |
+ const DisplayItem& newItem = m_newDisplayItemList[newIndex]; |
+ if (newItem.drawsContent() && !clientCacheIsValid(newItem.client()) && invalidatedClientsInNewChunk.add(&newItem.client()).isNewEntry) |
+ newChunk.rasterInvalidationRects.append(newItem.client().visualRect()); |
} |
} |
@@ -666,7 +685,7 @@ void PaintController::checkUnderInvalidation() |
// This is to align with the non-under-invalidation-checking path to empty the original cached slot, |
// leaving only disappeared or invalidated display items in the old list after painting. |
m_newDisplayItemList.removeLast(); |
- m_newDisplayItemList.appendByMoving(*oldItem); |
+ moveItemFromCurrentListToNewList(oldItemIndex); |
++m_underInvalidationCheckingBegin; |
} |
@@ -679,7 +698,7 @@ String PaintController::displayItemListAsDebugString(const DisplayItemList& list |
const DisplayItem& displayItem = *it; |
if (i) |
stringBuilder.append(",\n"); |
- stringBuilder.append(String::format("{index: %d, ", (int)i)); |
+ stringBuilder.append(String::format("{index: %zu, ", i)); |
#ifndef NDEBUG |
displayItem.dumpPropertiesAsDebugString(stringBuilder); |
#else |