| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/graphics/paint/PaintController.h" | 5 #include "platform/graphics/paint/PaintController.h" |
| 6 | 6 |
| 7 #include "platform/TraceEvent.h" | 7 #include "platform/TraceEvent.h" |
| 8 #include "platform/graphics/GraphicsLayer.h" | 8 #include "platform/graphics/GraphicsLayer.h" |
| 9 #include "platform/graphics/paint/DrawingDisplayItem.h" | 9 #include "platform/graphics/paint/DrawingDisplayItem.h" |
| 10 #include "third_party/skia/include/core/SkPictureAnalyzer.h" | 10 #include "third_party/skia/include/core/SkPictureAnalyzer.h" |
| 11 #include "wtf/AutoReset.h" |
| 11 #include "wtf/text/StringBuilder.h" | 12 #include "wtf/text/StringBuilder.h" |
| 12 | 13 |
| 13 #ifndef NDEBUG | 14 #ifndef NDEBUG |
| 14 #include "platform/graphics/LoggingCanvas.h" | 15 #include "platform/graphics/LoggingCanvas.h" |
| 15 #include <stdio.h> | 16 #include <stdio.h> |
| 16 #endif | 17 #endif |
| 17 | 18 |
| 18 namespace blink { | 19 namespace blink { |
| 19 | 20 |
| 20 const PaintArtifact& PaintController::paintArtifact() const | 21 const PaintArtifact& PaintController::paintArtifact() const |
| (...skipping 21 matching lines...) Expand all Loading... |
| 42 | 43 |
| 43 size_t cachedItem = findCachedItem(DisplayItem::Id(client, type)); | 44 size_t cachedItem = findCachedItem(DisplayItem::Id(client, type)); |
| 44 if (cachedItem == kNotFound) { | 45 if (cachedItem == kNotFound) { |
| 45 NOTREACHED(); | 46 NOTREACHED(); |
| 46 return false; | 47 return false; |
| 47 } | 48 } |
| 48 | 49 |
| 49 ++m_numCachedNewItems; | 50 ++m_numCachedNewItems; |
| 50 ensureNewDisplayItemListInitialCapacity(); | 51 ensureNewDisplayItemListInitialCapacity(); |
| 51 if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) | 52 if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) |
| 52 processNewItem(m_newDisplayItemList.appendByMoving(m_currentPaintArtifac
t.getDisplayItemList()[cachedItem]), FromCachedItem); | 53 processNewItem(moveItemFromCurrentListToNewList(cachedItem)); |
| 53 | 54 |
| 54 m_nextItemToMatch = cachedItem + 1; | 55 m_nextItemToMatch = cachedItem + 1; |
| 55 // Items before m_nextItemToMatch have been copied so we don't need to index
them. | 56 // Items before m_nextItemToMatch have been copied so we don't need to index
them. |
| 56 if (m_nextItemToMatch > m_nextItemToIndex) | 57 if (m_nextItemToMatch > m_nextItemToIndex) |
| 57 m_nextItemToIndex = m_nextItemToMatch; | 58 m_nextItemToIndex = m_nextItemToMatch; |
| 58 | 59 |
| 59 if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) { | 60 if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) { |
| 60 if (!isCheckingUnderInvalidation()) { | 61 if (!isCheckingUnderInvalidation()) { |
| 61 m_underInvalidationCheckingBegin = cachedItem; | 62 m_underInvalidationCheckingBegin = cachedItem; |
| 62 m_underInvalidationCheckingEnd = cachedItem + 1; | 63 m_underInvalidationCheckingEnd = cachedItem + 1; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 m_newPaintChunks.decrementDisplayItemIndex(); | 148 m_newPaintChunks.decrementDisplayItemIndex(); |
| 148 } | 149 } |
| 149 | 150 |
| 150 const DisplayItem* PaintController::lastDisplayItem(unsigned offset) | 151 const DisplayItem* PaintController::lastDisplayItem(unsigned offset) |
| 151 { | 152 { |
| 152 if (offset < m_newDisplayItemList.size()) | 153 if (offset < m_newDisplayItemList.size()) |
| 153 return &m_newDisplayItemList[m_newDisplayItemList.size() - offset - 1]; | 154 return &m_newDisplayItemList[m_newDisplayItemList.size() - offset - 1]; |
| 154 return nullptr; | 155 return nullptr; |
| 155 } | 156 } |
| 156 | 157 |
| 157 void PaintController::processNewItem(DisplayItem& displayItem, NewItemSource new
ItemSource) | 158 void PaintController::processNewItem(DisplayItem& displayItem) |
| 158 { | 159 { |
| 159 DCHECK(!m_constructionDisabled); | 160 DCHECK(!m_constructionDisabled); |
| 160 | 161 |
| 161 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS | 162 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS |
| 162 if (!isSkippingCache()) { | 163 if (!isSkippingCache()) { |
| 163 if (displayItem.isCacheable()) { | 164 if (displayItem.isCacheable()) { |
| 164 // Mark the client shouldKeepAlive under this PaintController. | 165 // Mark the client shouldKeepAlive under this PaintController. |
| 165 // The status will end after the new display items are committed. | 166 // The status will end after the new display items are committed. |
| 166 displayItem.client().beginShouldKeepAlive(this); | 167 displayItem.client().beginShouldKeepAlive(this); |
| 167 | 168 |
| 168 if (!m_currentSubsequenceClients.isEmpty()) { | 169 if (!m_currentSubsequenceClients.isEmpty()) { |
| 169 // Mark the client shouldKeepAlive under the current subsequence
. | 170 // Mark the client shouldKeepAlive under the current subsequence
. |
| 170 // The status will end when the subsequence owner is invalidated
or deleted. | 171 // The status will end when the subsequence owner is invalidated
or deleted. |
| 171 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl
ients.last()); | 172 displayItem.client().beginShouldKeepAlive(m_currentSubsequenceCl
ients.last()); |
| 172 } | 173 } |
| 173 } | 174 } |
| 174 | 175 |
| 175 if (displayItem.getType() == DisplayItem::kSubsequence) { | 176 if (displayItem.getType() == DisplayItem::kSubsequence) { |
| 176 m_currentSubsequenceClients.append(&displayItem.client()); | 177 m_currentSubsequenceClients.append(&displayItem.client()); |
| 177 } else if (displayItem.getType() == DisplayItem::kEndSubsequence) { | 178 } else if (displayItem.getType() == DisplayItem::kEndSubsequence) { |
| 178 CHECK(m_currentSubsequenceClients.last() == &displayItem.client()); | 179 CHECK(m_currentSubsequenceClients.last() == &displayItem.client()); |
| 179 m_currentSubsequenceClients.removeLast(); | 180 m_currentSubsequenceClients.removeLast(); |
| 180 } | 181 } |
| 181 } | 182 } |
| 182 #endif | 183 #endif |
| 183 | 184 |
| 184 if (isSkippingCache()) { | 185 if (isSkippingCache()) |
| 185 DCHECK(newItemSource == NewPainting); | |
| 186 displayItem.setSkippedCache(); | 186 displayItem.setSkippedCache(); |
| 187 } | |
| 188 | 187 |
| 189 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 188 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| 190 if (newItemSource != FromCachedSubsequence) | |
| 191 m_currentChunkIsFromCachedSubsequence = false; | |
| 192 | |
| 193 size_t lastChunkIndex = m_newPaintChunks.lastChunkIndex(); | 189 size_t lastChunkIndex = m_newPaintChunks.lastChunkIndex(); |
| 194 if (m_newPaintChunks.incrementDisplayItemIndex(displayItem)) { | 190 if (m_newPaintChunks.incrementDisplayItemIndex(displayItem)) { |
| 195 DCHECK(lastChunkIndex != m_newPaintChunks.lastChunkIndex()); | 191 DCHECK(lastChunkIndex != m_newPaintChunks.lastChunkIndex()); |
| 196 if (lastChunkIndex != kNotFound) | 192 if (lastChunkIndex != kNotFound) |
| 197 generateChunkRasterInvalidationRects(m_newPaintChunks.paintChunk
At(lastChunkIndex)); | 193 generateChunkRasterInvalidationRects(m_newPaintChunks.paintChunk
At(lastChunkIndex)); |
| 198 m_currentChunkIsFromCachedSubsequence = true; | |
| 199 } | 194 } |
| 200 } | 195 } |
| 201 | 196 |
| 202 #if DCHECK_IS_ON() | 197 #if DCHECK_IS_ON() |
| 203 // Verify noop begin/end pairs have been removed. | 198 // Verify noop begin/end pairs have been removed. |
| 204 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) { | 199 if (m_newDisplayItemList.size() >= 2 && displayItem.isEnd()) { |
| 205 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList
.size() - 2]; | 200 const auto& beginDisplayItem = m_newDisplayItemList[m_newDisplayItemList
.size() - 2]; |
| 206 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI
tem::kSubsequence && !beginDisplayItem.drawsContent()) | 201 if (beginDisplayItem.isBegin() && beginDisplayItem.getType() != DisplayI
tem::kSubsequence && !beginDisplayItem.drawsContent()) |
| 207 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType())); | 202 DCHECK(!displayItem.isEndAndPairedWith(beginDisplayItem.getType())); |
| 208 } | 203 } |
| 209 | 204 |
| 210 size_t index = findMatchingItemFromIndex(displayItem.getId(), m_newDisplayIt
emIndicesByClient, m_newDisplayItemList); | 205 size_t index = findMatchingItemFromIndex(displayItem.getId(), m_newDisplayIt
emIndicesByClient, m_newDisplayItemList); |
| 211 if (index != kNotFound) { | 206 if (index != kNotFound) { |
| 212 #ifndef NDEBUG | 207 #ifndef NDEBUG |
| 213 showDebugData(); | 208 showDebugData(); |
| 214 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%
d)\n", | 209 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%
zu)\n", |
| 215 displayItem.asDebugString().utf8().data(), m_newDisplayItemList[inde
x].asDebugString().utf8().data(), static_cast<int>(index)); | 210 displayItem.asDebugString().utf8().data(), m_newDisplayItemList[inde
x].asDebugString().utf8().data(), index); |
| 216 #endif | 211 #endif |
| 217 NOTREACHED(); | 212 NOTREACHED(); |
| 218 } | 213 } |
| 219 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi
splayItemIndicesByClient); | 214 addItemToIndexIfNeeded(displayItem, m_newDisplayItemList.size() - 1, m_newDi
splayItemIndicesByClient); |
| 220 #endif // DCHECK_IS_ON() | 215 #endif // DCHECK_IS_ON() |
| 221 | 216 |
| 222 if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) | 217 if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) |
| 223 checkUnderInvalidation(); | 218 checkUnderInvalidation(); |
| 224 } | 219 } |
| 225 | 220 |
| 221 DisplayItem& PaintController::moveItemFromCurrentListToNewList(size_t index) |
| 222 { |
| 223 m_itemsMovedIntoNewList.resize(m_currentPaintArtifact.getDisplayItemList().s
ize()); |
| 224 m_itemsMovedIntoNewList[index] = m_newDisplayItemList.size(); |
| 225 return m_newDisplayItemList.appendByMoving(m_currentPaintArtifact.getDisplay
ItemList()[index]); |
| 226 } |
| 227 |
| 226 void PaintController::updateCurrentPaintChunkProperties(const PaintChunk::Id* id
, const PaintChunkProperties& newProperties) | 228 void PaintController::updateCurrentPaintChunkProperties(const PaintChunk::Id* id
, const PaintChunkProperties& newProperties) |
| 227 { | 229 { |
| 228 m_newPaintChunks.updateCurrentPaintChunkProperties(id, newProperties); | 230 m_newPaintChunks.updateCurrentPaintChunkProperties(id, newProperties); |
| 229 } | 231 } |
| 230 | 232 |
| 231 const PaintChunkProperties& PaintController::currentPaintChunkProperties() const | 233 const PaintChunkProperties& PaintController::currentPaintChunkProperties() const |
| 232 { | 234 { |
| 233 return m_newPaintChunks.currentPaintChunkProperties(); | 235 return m_newPaintChunks.currentPaintChunkProperties(); |
| 234 } | 236 } |
| 235 | 237 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 253 | 255 |
| 254 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con
st IndicesByClientMap& displayItemIndicesByClient, const DisplayItemList& list) | 256 size_t PaintController::findMatchingItemFromIndex(const DisplayItem::Id& id, con
st IndicesByClientMap& displayItemIndicesByClient, const DisplayItemList& list) |
| 255 { | 257 { |
| 256 IndicesByClientMap::const_iterator it = displayItemIndicesByClient.find(&id.
client); | 258 IndicesByClientMap::const_iterator it = displayItemIndicesByClient.find(&id.
client); |
| 257 if (it == displayItemIndicesByClient.end()) | 259 if (it == displayItemIndicesByClient.end()) |
| 258 return kNotFound; | 260 return kNotFound; |
| 259 | 261 |
| 260 const Vector<size_t>& indices = it->value; | 262 const Vector<size_t>& indices = it->value; |
| 261 for (size_t index : indices) { | 263 for (size_t index : indices) { |
| 262 const DisplayItem& existingItem = list[index]; | 264 const DisplayItem& existingItem = list[index]; |
| 263 DCHECK(!existingItem.hasValidClient() || existingItem.client() == id.cli
ent); | 265 if (!existingItem.hasValidClient()) |
| 266 continue; |
| 267 DCHECK(existingItem.client() == id.client); |
| 264 if (id == existingItem.getId()) | 268 if (id == existingItem.getId()) |
| 265 return index; | 269 return index; |
| 266 } | 270 } |
| 267 | 271 |
| 268 return kNotFound; | 272 return kNotFound; |
| 269 } | 273 } |
| 270 | 274 |
| 271 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz
e_t index, IndicesByClientMap& displayItemIndicesByClient) | 275 void PaintController::addItemToIndexIfNeeded(const DisplayItem& displayItem, siz
e_t index, IndicesByClientMap& displayItemIndicesByClient) |
| 272 { | 276 { |
| 273 if (!displayItem.isCacheable()) | 277 if (!displayItem.isCacheable()) |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 // In this case, the caller should fall back to repaint the display item. | 349 // In this case, the caller should fall back to repaint the display item. |
| 346 return kNotFound; | 350 return kNotFound; |
| 347 } | 351 } |
| 348 | 352 |
| 349 // Copies a cached subsequence from current list to the new list. On return, | 353 // Copies a cached subsequence from current list to the new list. On return, |
| 350 // |cachedItemIndex| points to the item after the EndSubsequence item of the sub
sequence. | 354 // |cachedItemIndex| points to the item after the EndSubsequence item of the sub
sequence. |
| 351 // When paintUnderInvaldiationCheckingEnabled() we'll not actually copy the subs
equence, | 355 // When paintUnderInvaldiationCheckingEnabled() we'll not actually copy the subs
equence, |
| 352 // but mark the begin and end of the subsequence for under-invalidation checking
. | 356 // but mark the begin and end of the subsequence for under-invalidation checking
. |
| 353 void PaintController::copyCachedSubsequence(size_t& cachedItemIndex) | 357 void PaintController::copyCachedSubsequence(size_t& cachedItemIndex) |
| 354 { | 358 { |
| 359 AutoReset<size_t> subsequenceBeginIndex(&m_currentCachedSubsequenceBeginInde
xInNewList, m_newDisplayItemList.size()); |
| 355 DisplayItem* cachedItem = &m_currentPaintArtifact.getDisplayItemList()[cache
dItemIndex]; | 360 DisplayItem* cachedItem = &m_currentPaintArtifact.getDisplayItemList()[cache
dItemIndex]; |
| 356 DCHECK(cachedItem->getType() == DisplayItem::kSubsequence); | 361 DCHECK(cachedItem->getType() == DisplayItem::kSubsequence); |
| 357 | 362 |
| 358 if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) { | 363 if (RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) { |
| 359 DCHECK(!isCheckingUnderInvalidation()); | 364 DCHECK(!isCheckingUnderInvalidation()); |
| 360 m_underInvalidationCheckingBegin = cachedItemIndex; | 365 m_underInvalidationCheckingBegin = cachedItemIndex; |
| 361 m_underInvalidationMessagePrefix = "(In cached subsequence of " + cached
Item->client().debugName() + ")"; | 366 m_underInvalidationMessagePrefix = "(In cached subsequence of " + cached
Item->client().debugName() + ")"; |
| 362 } | 367 } |
| 363 | 368 |
| 364 DisplayItem::Id endSubsequenceId(cachedItem->client(), DisplayItem::kEndSubs
equence); | 369 DisplayItem::Id endSubsequenceId(cachedItem->client(), DisplayItem::kEndSubs
equence); |
| 365 Vector<PaintChunk>::const_iterator cachedChunk; | 370 Vector<PaintChunk>::const_iterator cachedChunk; |
| 366 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 371 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| 367 cachedChunk = m_currentPaintArtifact.findChunkByDisplayItemIndex(cachedI
temIndex); | 372 cachedChunk = m_currentPaintArtifact.findChunkByDisplayItemIndex(cachedI
temIndex); |
| 373 DCHECK(cachedChunk != m_currentPaintArtifact.paintChunks().end()); |
| 368 updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChunk->id :
nullptr, cachedChunk->properties); | 374 updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChunk->id :
nullptr, cachedChunk->properties); |
| 369 } else { | 375 } else { |
| 370 // This is to avoid compilation error about uninitialized variable on Wi
ndows. | 376 // This is to avoid compilation error about uninitialized variable on Wi
ndows. |
| 371 cachedChunk = m_currentPaintArtifact.paintChunks().begin(); | 377 cachedChunk = m_currentPaintArtifact.paintChunks().begin(); |
| 372 } | 378 } |
| 373 | 379 |
| 374 while (true) { | 380 while (true) { |
| 375 DCHECK(cachedItem->hasValidClient()); | 381 DCHECK(cachedItem->hasValidClient()); |
| 376 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS | 382 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS |
| 377 CHECK(cachedItem->client().isAlive()); | 383 CHECK(cachedItem->client().isAlive()); |
| 378 #endif | 384 #endif |
| 379 ++m_numCachedNewItems; | 385 ++m_numCachedNewItems; |
| 380 bool metEndSubsequence = cachedItem->getId() == endSubsequenceId; | 386 bool metEndSubsequence = cachedItem->getId() == endSubsequenceId; |
| 381 if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) { | 387 if (!RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled()) { |
| 382 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && cachedItemIn
dex == cachedChunk->endIndex) { | 388 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && cachedItemIn
dex == cachedChunk->endIndex) { |
| 383 ++cachedChunk; | 389 ++cachedChunk; |
| 390 DCHECK(cachedChunk != m_currentPaintArtifact.paintChunks().end()
); |
| 384 updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChun
k->id : nullptr, cachedChunk->properties); | 391 updateCurrentPaintChunkProperties(cachedChunk->id ? &*cachedChun
k->id : nullptr, cachedChunk->properties); |
| 385 } | 392 } |
| 386 processNewItem(m_newDisplayItemList.appendByMoving(*cachedItem), Fro
mCachedSubsequence); | 393 processNewItem(moveItemFromCurrentListToNewList(cachedItemIndex)); |
| 387 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) | 394 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) |
| 388 DCHECK((!m_newPaintChunks.lastChunk().id && !cachedChunk->id) ||
m_newPaintChunks.lastChunk().matches(*cachedChunk)); | 395 DCHECK((!m_newPaintChunks.lastChunk().id && !cachedChunk->id) ||
m_newPaintChunks.lastChunk().matches(*cachedChunk)); |
| 389 } | 396 } |
| 390 | 397 |
| 391 ++cachedItemIndex; | 398 ++cachedItemIndex; |
| 392 if (metEndSubsequence) | 399 if (metEndSubsequence) |
| 393 break; | 400 break; |
| 394 | 401 |
| 395 // We should always be able to find the EndSubsequence display item. | 402 // We should always be able to find the EndSubsequence display item. |
| 396 DCHECK(cachedItemIndex < m_currentPaintArtifact.getDisplayItemList().siz
e()); | 403 DCHECK(cachedItemIndex < m_currentPaintArtifact.getDisplayItemList().siz
e()); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 460 | 467 |
| 461 for (auto* client : skippedCacheClients) | 468 for (auto* client : skippedCacheClients) |
| 462 client->setDisplayItemsUncached(); | 469 client->setDisplayItemsUncached(); |
| 463 | 470 |
| 464 // The new list will not be appended to again so we can release unused memor
y. | 471 // The new list will not be appended to again so we can release unused memor
y. |
| 465 m_newDisplayItemList.shrinkToFit(); | 472 m_newDisplayItemList.shrinkToFit(); |
| 466 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_ne
wPaintChunks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization()); | 473 m_currentPaintArtifact = PaintArtifact(std::move(m_newDisplayItemList), m_ne
wPaintChunks.releasePaintChunks(), gpuAnalyzer.suitableForGpuRasterization()); |
| 467 resetCurrentListIndices(); | 474 resetCurrentListIndices(); |
| 468 m_outOfOrderItemIndices.clear(); | 475 m_outOfOrderItemIndices.clear(); |
| 469 m_outOfOrderChunkIndices.clear(); | 476 m_outOfOrderChunkIndices.clear(); |
| 477 m_itemsMovedIntoNewList.clear(); |
| 470 | 478 |
| 471 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 479 if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
| 472 for (const auto& chunk : m_currentPaintArtifact.paintChunks()) { | 480 for (const auto& chunk : m_currentPaintArtifact.paintChunks()) { |
| 473 if (chunk.id && chunk.id->client.isJustCreated()) | 481 if (chunk.id && chunk.id->client.isJustCreated()) |
| 474 chunk.id->client.clearIsJustCreated(); | 482 chunk.id->client.clearIsJustCreated(); |
| 475 } | 483 } |
| 476 } | 484 } |
| 477 | 485 |
| 478 // We'll allocate the initial buffer when we start the next paint. | 486 // We'll allocate the initial buffer when we start the next paint. |
| 479 m_newDisplayItemList = DisplayItemList(0); | 487 m_newDisplayItemList = DisplayItemList(0); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 520 DCHECK(m_newDisplayItemList.isEmpty()); | 528 DCHECK(m_newDisplayItemList.isEmpty()); |
| 521 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList(
).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::kDebu
gDrawing, std::move(picture)); | 529 DrawingDisplayItem& displayItem = m_currentPaintArtifact.getDisplayItemList(
).allocateAndConstruct<DrawingDisplayItem>(displayItemClient, DisplayItem::kDebu
gDrawing, std::move(picture)); |
| 522 displayItem.setSkippedCache(); | 530 displayItem.setSkippedCache(); |
| 523 // TODO(wkorman): Only compute and append visual rect for drawings. | 531 // TODO(wkorman): Only compute and append visual rect for drawings. |
| 524 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi
splayItem(displayItem, offsetFromLayoutObject)); | 532 m_currentPaintArtifact.getDisplayItemList().appendVisualRect(visualRectForDi
splayItem(displayItem, offsetFromLayoutObject)); |
| 525 } | 533 } |
| 526 | 534 |
| 527 void PaintController::generateChunkRasterInvalidationRects(PaintChunk& newChunk) | 535 void PaintController::generateChunkRasterInvalidationRects(PaintChunk& newChunk) |
| 528 { | 536 { |
| 529 DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); | 537 DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| 530 if (m_currentChunkIsFromCachedSubsequence) | 538 if (newChunk.beginIndex >= m_currentCachedSubsequenceBeginIndexInNewList) |
| 531 return; | 539 return; |
| 532 | 540 |
| 533 if (!newChunk.id) { | 541 if (!newChunk.id) { |
| 534 newChunk.rasterInvalidationRects.append(FloatRect(LayoutRect::infiniteIn
tRect())); | 542 newChunk.rasterInvalidationRects.append(FloatRect(LayoutRect::infiniteIn
tRect())); |
| 535 return; | 543 return; |
| 536 } | 544 } |
| 537 | 545 |
| 538 // Try to match old chunk sequentially first. | 546 // Try to match old chunk sequentially first. |
| 539 const auto& oldChunks = m_currentPaintArtifact.paintChunks(); | 547 const auto& oldChunks = m_currentPaintArtifact.paintChunks(); |
| 540 while (m_nextChunkToMatch < oldChunks.size()) { | 548 while (m_nextChunkToMatch < oldChunks.size()) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 567 } | 575 } |
| 568 | 576 |
| 569 // We reach here because the chunk is new. | 577 // We reach here because the chunk is new. |
| 570 newChunk.rasterInvalidationRects.append(FloatRect(LayoutRect::infiniteIntRec
t())); | 578 newChunk.rasterInvalidationRects.append(FloatRect(LayoutRect::infiniteIntRec
t())); |
| 571 } | 579 } |
| 572 | 580 |
| 573 void PaintController::generateChunkRasterInvalidationRectsComparingOldChunk(Pain
tChunk& newChunk, const PaintChunk& oldChunk) | 581 void PaintController::generateChunkRasterInvalidationRectsComparingOldChunk(Pain
tChunk& newChunk, const PaintChunk& oldChunk) |
| 574 { | 582 { |
| 575 DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); | 583 DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled()); |
| 576 | 584 |
| 577 // TODO(wangxianzhu): Support raster invalidation for reordered display item
s without invalidating | |
| 578 // display item clients. Currently we invalidate display item clients ensuri
ng raster invalidation. | |
| 579 // TODO(wangxianzhu): Handle PaintInvalidationIncremental. | 585 // TODO(wangxianzhu): Handle PaintInvalidationIncremental. |
| 580 // TODO(wangxianzhu): Optimize paint offset change. | 586 // TODO(wangxianzhu): Optimize paint offset change. |
| 581 | 587 |
| 582 // Maps from each client to the index of the first drawing-content display i
tem of the client. | 588 HashSet<const DisplayItemClient*> invalidatedClientsInOldChunk; |
| 583 HashMap<const DisplayItemClient*, size_t> oldChunkClients; | 589 size_t highestMovedToIndex = 0; |
| 584 for (size_t i = oldChunk.beginIndex; i < oldChunk.endIndex; ++i) { | 590 for (size_t oldIndex = oldChunk.beginIndex; oldIndex < oldChunk.endIndex; ++
oldIndex) { |
| 585 const DisplayItem& oldItem = m_currentPaintArtifact.getDisplayItemList()
[i]; | 591 const DisplayItem& oldItem = m_currentPaintArtifact.getDisplayItemList()
[oldIndex]; |
| 586 // oldItem.hasValidClient() indicates that the item has not been copied
as a cached item into | 592 const DisplayItemClient* clientToInvalidate = nullptr; |
| 587 // m_newDislayItemList, so the item either disappeared or changed, and n
eeds raster invalidation. | 593 if (!oldItem.hasValidClient()) { |
| 588 if (oldItem.hasValidClient() && oldItem.drawsContent() && oldChunkClient
s.add(&oldItem.client(), i).isNewEntry) | 594 size_t movedToIndex = m_itemsMovedIntoNewList[oldIndex]; |
| 589 newChunk.rasterInvalidationRects.append(m_currentPaintArtifact.getDi
splayItemList().visualRect(i)); | 595 if (m_newDisplayItemList[movedToIndex].drawsContent()) { |
| 596 if (movedToIndex < newChunk.beginIndex || movedToIndex >= newChu
nk.endIndex) { |
| 597 // The item has been moved into another chunk, so need to in
validate it in the old chunk. |
| 598 clientToInvalidate = &m_newDisplayItemList[movedToIndex].cli
ent(); |
| 599 // And invalidate in the new chunk into which the item was m
oved. |
| 600 PaintChunk& movedToChunk = m_newPaintChunks.findChunkByDispl
ayItemIndex(movedToIndex); |
| 601 movedToChunk.rasterInvalidationRects.append(clientToInvalida
te->visualRect()); |
| 602 } else if (movedToIndex < highestMovedToIndex) { |
| 603 // The item has been moved behind other cached items, so nee
d to invalidate the area |
| 604 // that is probably exposed by the item moved earlier. |
| 605 clientToInvalidate = &m_newDisplayItemList[movedToIndex].cli
ent(); |
| 606 } else { |
| 607 highestMovedToIndex = movedToIndex; |
| 608 } |
| 609 } |
| 610 } else if (oldItem.drawsContent()) { |
| 611 clientToInvalidate = &oldItem.client(); |
| 612 } |
| 613 if (clientToInvalidate && invalidatedClientsInOldChunk.add(clientToInval
idate).isNewEntry) { |
| 614 newChunk.rasterInvalidationRects.append(m_currentPaintArtifact.getDi
splayItemList().visualRect(oldIndex)); |
| 615 } |
| 590 } | 616 } |
| 591 | 617 |
| 592 HashSet<const DisplayItemClient*> newChunkClients; | 618 HashSet<const DisplayItemClient*> invalidatedClientsInNewChunk; |
| 593 for (size_t i = newChunk.beginIndex; i < newChunk.endIndex; ++i) { | 619 for (size_t newIndex = newChunk.beginIndex; newIndex < newChunk.endIndex; ++
newIndex) { |
| 594 const DisplayItem& newItem = m_newDisplayItemList[i]; | 620 const DisplayItem& newItem = m_newDisplayItemList[newIndex]; |
| 595 if (newItem.drawsContent()) { | 621 if (newItem.drawsContent() && !clientCacheIsValid(newItem.client()) && i
nvalidatedClientsInNewChunk.add(&newItem.client()).isNewEntry) |
| 596 if (!clientCacheIsValid(newItem.client())) { | 622 newChunk.rasterInvalidationRects.append(newItem.client().visualRect(
)); |
| 597 if (newChunkClients.add(&newItem.client()).isNewEntry) | |
| 598 newChunk.rasterInvalidationRects.append(newItem.client().vis
ualRect()); | |
| 599 } else { | |
| 600 // The cached item was moved from the old chunk which should not
contain any item of the client now. | |
| 601 DCHECK(!oldChunkClients.contains(&newItem.client())); | |
| 602 } | |
| 603 } | |
| 604 } | 623 } |
| 605 } | 624 } |
| 606 | 625 |
| 607 void PaintController::showUnderInvalidationError(const char* reason, const Displ
ayItem& newItem, const DisplayItem* oldItem) const | 626 void PaintController::showUnderInvalidationError(const char* reason, const Displ
ayItem& newItem, const DisplayItem* oldItem) const |
| 608 { | 627 { |
| 609 LOG(ERROR) << m_underInvalidationMessagePrefix << " " << reason; | 628 LOG(ERROR) << m_underInvalidationMessagePrefix << " " << reason; |
| 610 #ifndef NDEBUG | 629 #ifndef NDEBUG |
| 611 LOG(ERROR) << "New display item: " << newItem.asDebugString(); | 630 LOG(ERROR) << "New display item: " << newItem.asDebugString(); |
| 612 LOG(ERROR) << "Old display item: " << (oldItem ? oldItem->asDebugString() :
"None"); | 631 LOG(ERROR) << "Old display item: " << (oldItem ? oldItem->asDebugString() :
"None"); |
| 613 #else | 632 #else |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 659 showUnderInvalidationError("under-invalidation: display item changed", | 678 showUnderInvalidationError("under-invalidation: display item changed", |
| 660 m_newDisplayItemList[m_newDisplayItemList.size() - m_skippedProbable
UnderInvalidationCount - 1], | 679 m_newDisplayItemList[m_newDisplayItemList.size() - m_skippedProbable
UnderInvalidationCount - 1], |
| 661 &m_currentPaintArtifact.getDisplayItemList()[m_underInvalidationChec
kingBegin]); | 680 &m_currentPaintArtifact.getDisplayItemList()[m_underInvalidationChec
kingBegin]); |
| 662 CHECK(false); | 681 CHECK(false); |
| 663 } | 682 } |
| 664 | 683 |
| 665 // Discard the forced repainted display item and move the cached item into m
_newDisplayItemList. | 684 // Discard the forced repainted display item and move the cached item into m
_newDisplayItemList. |
| 666 // This is to align with the non-under-invalidation-checking path to empty t
he original cached slot, | 685 // This is to align with the non-under-invalidation-checking path to empty t
he original cached slot, |
| 667 // leaving only disappeared or invalidated display items in the old list aft
er painting. | 686 // leaving only disappeared or invalidated display items in the old list aft
er painting. |
| 668 m_newDisplayItemList.removeLast(); | 687 m_newDisplayItemList.removeLast(); |
| 669 m_newDisplayItemList.appendByMoving(*oldItem); | 688 moveItemFromCurrentListToNewList(oldItemIndex); |
| 670 | 689 |
| 671 ++m_underInvalidationCheckingBegin; | 690 ++m_underInvalidationCheckingBegin; |
| 672 } | 691 } |
| 673 | 692 |
| 674 String PaintController::displayItemListAsDebugString(const DisplayItemList& list
) const | 693 String PaintController::displayItemListAsDebugString(const DisplayItemList& list
) const |
| 675 { | 694 { |
| 676 StringBuilder stringBuilder; | 695 StringBuilder stringBuilder; |
| 677 size_t i = 0; | 696 size_t i = 0; |
| 678 for (auto it = list.begin(); it != list.end(); ++it, ++i) { | 697 for (auto it = list.begin(); it != list.end(); ++it, ++i) { |
| 679 const DisplayItem& displayItem = *it; | 698 const DisplayItem& displayItem = *it; |
| 680 if (i) | 699 if (i) |
| 681 stringBuilder.append(",\n"); | 700 stringBuilder.append(",\n"); |
| 682 stringBuilder.append(String::format("{index: %d, ", (int)i)); | 701 stringBuilder.append(String::format("{index: %zu, ", i)); |
| 683 #ifndef NDEBUG | 702 #ifndef NDEBUG |
| 684 displayItem.dumpPropertiesAsDebugString(stringBuilder); | 703 displayItem.dumpPropertiesAsDebugString(stringBuilder); |
| 685 #else | 704 #else |
| 686 stringBuilder.append(String::format("clientDebugName: %s", displayItem.c
lient().debugName().ascii().data())); | 705 stringBuilder.append(String::format("clientDebugName: %s", displayItem.c
lient().debugName().ascii().data())); |
| 687 #endif | 706 #endif |
| 688 if (displayItem.hasValidClient()) { | 707 if (displayItem.hasValidClient()) { |
| 689 do { | 708 do { |
| 690 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS | 709 #if CHECK_DISPLAY_ITEM_CLIENT_ALIVENESS |
| 691 if (!displayItem.client().isAlive()) { | 710 if (!displayItem.client().isAlive()) { |
| 692 stringBuilder.append(", clientIsAlive: false"); | 711 stringBuilder.append(", clientIsAlive: false"); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 708 return stringBuilder.toString(); | 727 return stringBuilder.toString(); |
| 709 } | 728 } |
| 710 | 729 |
| 711 void PaintController::showDebugData() const | 730 void PaintController::showDebugData() const |
| 712 { | 731 { |
| 713 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri
ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); | 732 WTFLogAlways("current display item list: [%s]\n", displayItemListAsDebugStri
ng(m_currentPaintArtifact.getDisplayItemList()).utf8().data()); |
| 714 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m
_newDisplayItemList).utf8().data()); | 733 WTFLogAlways("new display item list: [%s]\n", displayItemListAsDebugString(m
_newDisplayItemList).utf8().data()); |
| 715 } | 734 } |
| 716 | 735 |
| 717 } // namespace blink | 736 } // namespace blink |
| OLD | NEW |