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 |