| 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 "config.h" | 5 #include "config.h" |
| 6 #include "platform/graphics/paint/DisplayItemList.h" | 6 #include "platform/graphics/paint/DisplayItemList.h" |
| 7 | 7 |
| 8 #include "platform/NotImplemented.h" | 8 #include "platform/NotImplemented.h" |
| 9 #include "platform/RuntimeEnabledFeatures.h" | 9 #include "platform/RuntimeEnabledFeatures.h" |
| 10 #include "platform/TraceEvent.h" | 10 #include "platform/TraceEvent.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #include "platform/graphics/LoggingCanvas.h" | 21 #include "platform/graphics/LoggingCanvas.h" |
| 22 #include "wtf/text/StringBuilder.h" | 22 #include "wtf/text/StringBuilder.h" |
| 23 #include <stdio.h> | 23 #include <stdio.h> |
| 24 #endif | 24 #endif |
| 25 | 25 |
| 26 namespace blink { | 26 namespace blink { |
| 27 | 27 |
| 28 const DisplayItems& DisplayItemList::displayItems() const | 28 const DisplayItems& DisplayItemList::displayItems() const |
| 29 { | 29 { |
| 30 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); | 30 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); |
| 31 ASSERT(m_newDisplayItems.isEmpty()); | 31 ASSERT(m_newDisplayItems.empty()); |
| 32 return m_currentDisplayItems; | 32 return m_currentDisplayItems; |
| 33 } | 33 } |
| 34 | 34 |
| 35 bool DisplayItemList::lastDisplayItemIsNoopBegin() const | 35 bool DisplayItemList::lastDisplayItemIsNoopBegin() const |
| 36 { | 36 { |
| 37 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); | 37 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); |
| 38 if (m_newDisplayItems.isEmpty()) | 38 if (m_newDisplayItems.empty()) |
| 39 return false; | 39 return false; |
| 40 | 40 |
| 41 const auto& lastDisplayItem = m_newDisplayItems.last(); | 41 const auto& lastDisplayItem = *m_newDisplayItems.back(); |
| 42 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent(); | 42 return lastDisplayItem.isBegin() && !lastDisplayItem.drawsContent(); |
| 43 } | 43 } |
| 44 | 44 |
| 45 void DisplayItemList::removeLastDisplayItem() | 45 void DisplayItemList::removeLastDisplayItem() |
| 46 { | 46 { |
| 47 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); | 47 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); |
| 48 if (m_newDisplayItems.isEmpty()) | 48 if (m_newDisplayItems.empty()) |
| 49 return; | 49 return; |
| 50 | 50 |
| 51 #if ENABLE(ASSERT) | 51 #if ENABLE(ASSERT) |
| 52 // Also remove the index pointing to the removed display item. | 52 // Also remove the index pointing to the removed display item. |
| 53 DisplayItemIndicesByClientMap::iterator it = m_newDisplayItemIndicesByClient
.find(m_newDisplayItems.last().client()); | 53 DisplayItemIndicesByClientMap::iterator it = m_newDisplayItemIndicesByClient
.find(m_newDisplayItems.back()->client()); |
| 54 if (it != m_newDisplayItemIndicesByClient.end()) { | 54 if (it != m_newDisplayItemIndicesByClient.end()) { |
| 55 Vector<size_t>& indices = it->value; | 55 Vector<size_t>& indices = it->value; |
| 56 if (!indices.isEmpty() && indices.last() == (m_newDisplayItems.size() -
1)) | 56 if (!indices.isEmpty() && indices.last() == (m_newDisplayItems.size() -
1)) |
| 57 indices.removeLast(); | 57 indices.removeLast(); |
| 58 } | 58 } |
| 59 #endif | 59 #endif |
| 60 m_newDisplayItems.removeLast(); | 60 m_newDisplayItems.removeLast(); |
| 61 } | 61 } |
| 62 | 62 |
| 63 void DisplayItemList::add(WTF::PassOwnPtr<DisplayItem> displayItem) | 63 void DisplayItemList::processNewItem(DisplayItem* displayItem) |
| 64 { | 64 { |
| 65 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); | 65 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); |
| 66 ASSERT(!m_constructionDisabled); | 66 ASSERT(!m_constructionDisabled); |
| 67 ASSERT(!skippingCache() || !displayItem->isCached()); | 67 ASSERT(!skippingCache() || !displayItem->isCached()); |
| 68 | 68 |
| 69 if (DisplayItem::isCachedType(displayItem->type())) | 69 if (DisplayItem::isCachedType(displayItem->type())) |
| 70 ++m_numCachedItems; | 70 ++m_numCachedItems; |
| 71 | 71 |
| 72 #if ENABLE(ASSERT) | 72 #if ENABLE(ASSERT) |
| 73 // Verify noop begin/end pairs have been removed. | 73 // Verify noop begin/end pairs have been removed. |
| 74 if (!m_newDisplayItems.isEmpty() && m_newDisplayItems.last().isBegin() && !m
_newDisplayItems.last().drawsContent()) | 74 if (m_newDisplayItems.size() >= 2 && displayItem->isEnd()) { |
| 75 ASSERT(!displayItem->isEndAndPairedWith(m_newDisplayItems.last().type())
); | 75 const auto& beginDisplayItem = *m_newDisplayItems.elementAt(m_newDisplay
Items.size() - 2); |
| 76 if (beginDisplayItem.isBegin() && !beginDisplayItem.drawsContent()) |
| 77 ASSERT(!displayItem->isEndAndPairedWith(beginDisplayItem.type())); |
| 78 } |
| 76 #endif | 79 #endif |
| 77 | 80 |
| 78 if (!m_scopeStack.isEmpty()) | 81 if (!m_scopeStack.isEmpty()) |
| 79 displayItem->setScope(m_scopeStack.last().id, m_scopeStack.last().client
); | 82 displayItem->setScope(m_scopeStack.last().id, m_scopeStack.last().client
); |
| 80 | 83 |
| 81 #if ENABLE(ASSERT) | 84 #if ENABLE(ASSERT) |
| 82 size_t index = findMatchingItemFromIndex(displayItem->id(), displayItem->typ
e(), m_newDisplayItemIndicesByClient, m_newDisplayItems); | 85 size_t index = findMatchingItemFromIndex(displayItem->id(), displayItem->typ
e(), m_newDisplayItemIndicesByClient, m_newDisplayItems); |
| 83 if (index != kNotFound) { | 86 if (index != kNotFound) { |
| 84 #ifndef NDEBUG | 87 #ifndef NDEBUG |
| 85 showDebugData(); | 88 showDebugData(); |
| 86 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%
d)\n", | 89 WTFLogAlways("DisplayItem %s has duplicated id with previous %s (index=%
d)\n", |
| 87 displayItem->asDebugString().utf8().data(), m_newDisplayItems[index]
.asDebugString().utf8().data(), static_cast<int>(index)); | 90 displayItem->asDebugString().utf8().data(), m_newDisplayItems.elemen
tAt(index)->asDebugString().utf8().data(), static_cast<int>(index)); |
| 88 #endif | 91 #endif |
| 89 ASSERT_NOT_REACHED(); | 92 ASSERT_NOT_REACHED(); |
| 90 } | 93 } |
| 91 addItemToIndex(displayItem->client(), displayItem->type(), m_newDisplayItems
.size(), m_newDisplayItemIndicesByClient); | 94 addItemToIndex(displayItem->client(), displayItem->type(), m_newDisplayItems
.size() - 1, m_newDisplayItemIndicesByClient); |
| 92 #endif // ENABLE(ASSERT) | 95 #endif // ENABLE(ASSERT) |
| 93 | 96 |
| 94 ASSERT(!displayItem->skippedCache()); // Only DisplayItemList can set the fl
ag. | 97 ASSERT(!displayItem->skippedCache()); // Only DisplayItemList can set the fl
ag. |
| 95 if (skippingCache()) | 98 if (skippingCache()) |
| 96 displayItem->setSkippedCache(); | 99 displayItem->setSkippedCache(); |
| 97 | |
| 98 m_newDisplayItems.append(displayItem); | |
| 99 } | 100 } |
| 100 | 101 |
| 101 void DisplayItemList::beginScope(DisplayItemClient client) | 102 void DisplayItemList::beginScope(DisplayItemClient client) |
| 102 { | 103 { |
| 103 ClientScopeIdMap::iterator it = m_clientScopeIdMap.find(client); | 104 ClientScopeIdMap::iterator it = m_clientScopeIdMap.find(client); |
| 104 int scopeId; | 105 int scopeId; |
| 105 if (it == m_clientScopeIdMap.end()) { | 106 if (it == m_clientScopeIdMap.end()) { |
| 106 m_clientScopeIdMap.add(client, 0); | 107 m_clientScopeIdMap.add(client, 0); |
| 107 scopeId = 0; | 108 scopeId = 0; |
| 108 } else { | 109 } else { |
| 109 scopeId = ++it->value; | 110 scopeId = ++it->value; |
| 110 } | 111 } |
| 111 m_scopeStack.append(Scope(client, scopeId)); | 112 m_scopeStack.append(Scope(client, scopeId)); |
| 112 beginSkippingCache(); | 113 beginSkippingCache(); |
| 113 } | 114 } |
| 114 | 115 |
| 115 void DisplayItemList::endScope(DisplayItemClient client) | 116 void DisplayItemList::endScope(DisplayItemClient client) |
| 116 { | 117 { |
| 117 m_scopeStack.removeLast(); | 118 m_scopeStack.removeLast(); |
| 118 endSkippingCache(); | 119 endSkippingCache(); |
| 119 } | 120 } |
| 120 | 121 |
| 121 void DisplayItemList::invalidate(DisplayItemClient client) | 122 void DisplayItemList::invalidate(DisplayItemClient client) |
| 122 { | 123 { |
| 123 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); | 124 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); |
| 124 // Can only be called during layout/paintInvalidation, not during painting. | 125 // Can only be called during layout/paintInvalidation, not during painting. |
| 125 ASSERT(m_newDisplayItems.isEmpty()); | 126 ASSERT(m_newDisplayItems.empty()); |
| 126 updateValidlyCachedClientsIfNeeded(); | 127 updateValidlyCachedClientsIfNeeded(); |
| 127 m_validlyCachedClients.remove(client); | 128 m_validlyCachedClients.remove(client); |
| 128 } | 129 } |
| 129 | 130 |
| 130 void DisplayItemList::invalidateAll() | 131 void DisplayItemList::invalidateAll() |
| 131 { | 132 { |
| 132 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); | 133 ASSERT(RuntimeEnabledFeatures::slimmingPaintEnabled()); |
| 133 // Can only be called during layout/paintInvalidation, not during painting. | 134 // Can only be called during layout/paintInvalidation, not during painting. |
| 134 ASSERT(m_newDisplayItems.isEmpty()); | 135 ASSERT(m_newDisplayItems.empty()); |
| 135 m_currentDisplayItems.clear(); | 136 m_currentDisplayItems.clear(); |
| 136 m_validlyCachedClients.clear(); | 137 m_validlyCachedClients.clear(); |
| 137 m_validlyCachedClientsDirty = false; | 138 m_validlyCachedClientsDirty = false; |
| 138 } | 139 } |
| 139 | 140 |
| 140 bool DisplayItemList::clientCacheIsValid(DisplayItemClient client) const | 141 bool DisplayItemList::clientCacheIsValid(DisplayItemClient client) const |
| 141 { | 142 { |
| 142 if (skippingCache()) | 143 if (skippingCache()) |
| 143 return false; | 144 return false; |
| 144 updateValidlyCachedClientsIfNeeded(); | 145 updateValidlyCachedClientsIfNeeded(); |
| 145 return m_validlyCachedClients.contains(client); | 146 return m_validlyCachedClients.contains(client); |
| 146 } | 147 } |
| 147 | 148 |
| 148 size_t DisplayItemList::findMatchingItemFromIndex(const DisplayItem::Id& id, Dis
playItem::Type matchingType, const DisplayItemIndicesByClientMap& displayItemInd
icesByClient, const DisplayItems& list) | 149 size_t DisplayItemList::findMatchingItemFromIndex(const DisplayItem::Id& id, Dis
playItem::Type matchingType, const DisplayItemIndicesByClientMap& displayItemInd
icesByClient, const DisplayItems& list) |
| 149 { | 150 { |
| 150 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien
t.find(id.client); | 151 DisplayItemIndicesByClientMap::const_iterator it = displayItemIndicesByClien
t.find(id.client); |
| 151 if (it == displayItemIndicesByClient.end()) | 152 if (it == displayItemIndicesByClient.end()) |
| 152 return kNotFound; | 153 return kNotFound; |
| 153 | 154 |
| 154 const Vector<size_t>& indices = it->value; | 155 const Vector<size_t>& indices = it->value; |
| 155 for (size_t index : indices) { | 156 for (size_t index : indices) { |
| 156 DisplayItems::ItemHandle existingItem = list[index]; | 157 // TODO(pdr): elementAt is not cheap so this should be refactored (See c
rbug.com/505965). |
| 157 ASSERT(existingItem.isGone() || existingItem.client() == id.client); | 158 const DisplayItem& existingItem = *list.elementAt(index); |
| 158 if (!existingItem.isGone() && existingItem.id().equalToExceptForType(id,
matchingType)) | 159 ASSERT(existingItem.ignoreFromDisplayList() || existingItem.client() ==
id.client); |
| 160 if (!existingItem.ignoreFromDisplayList() && existingItem.id().equalToEx
ceptForType(id, matchingType)) |
| 159 return index; | 161 return index; |
| 160 } | 162 } |
| 161 | 163 |
| 162 return kNotFound; | 164 return kNotFound; |
| 163 } | 165 } |
| 164 | 166 |
| 165 void DisplayItemList::addItemToIndex(DisplayItemClient client, DisplayItem::Type
type, size_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) | 167 void DisplayItemList::addItemToIndex(DisplayItemClient client, DisplayItem::Type
type, size_t index, DisplayItemIndicesByClientMap& displayItemIndicesByClient) |
| 166 { | 168 { |
| 167 // Only need to index DrawingDisplayItems and FIXME: BeginSubtreeDisplayItem
s. | 169 // Only need to index DrawingDisplayItems and FIXME: BeginSubtreeDisplayItem
s. |
| 168 if (!DisplayItem::isDrawingType(type)) | 170 if (!DisplayItem::isDrawingType(type)) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 184 return m_currentDisplayItems.iteratorAt(foundIndex); | 186 return m_currentDisplayItems.iteratorAt(foundIndex); |
| 185 | 187 |
| 186 return findOutOfOrderCachedItemForward(currentIt, id, matchingType, displayI
temIndicesByClient); | 188 return findOutOfOrderCachedItemForward(currentIt, id, matchingType, displayI
temIndicesByClient); |
| 187 } | 189 } |
| 188 | 190 |
| 189 // Find forward for the item and index all skipped indexable items. | 191 // Find forward for the item and index all skipped indexable items. |
| 190 DisplayItems::Iterator DisplayItemList::findOutOfOrderCachedItemForward(DisplayI
tems::Iterator currentIt, const DisplayItem::Id& id, DisplayItem::Type matchingT
ype, DisplayItemIndicesByClientMap& displayItemIndicesByClient) | 192 DisplayItems::Iterator DisplayItemList::findOutOfOrderCachedItemForward(DisplayI
tems::Iterator currentIt, const DisplayItem::Id& id, DisplayItem::Type matchingT
ype, DisplayItemIndicesByClientMap& displayItemIndicesByClient) |
| 191 { | 193 { |
| 192 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); | 194 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); |
| 193 for (; currentIt != currentEnd; ++currentIt) { | 195 for (; currentIt != currentEnd; ++currentIt) { |
| 194 DisplayItems::ItemHandle item = *currentIt; | 196 const DisplayItem& item = **currentIt; |
| 195 if (!item.isGone() | 197 if (!item.ignoreFromDisplayList() |
| 196 && DisplayItem::isDrawingType(item.type()) | 198 && DisplayItem::isDrawingType(item.type()) |
| 197 && m_validlyCachedClients.contains(item.client())) { | 199 && m_validlyCachedClients.contains(item.client())) { |
| 198 if (item.id().equalToExceptForType(id, matchingType)) | 200 if (item.id().equalToExceptForType(id, matchingType)) |
| 199 return currentIt; | 201 return currentIt; |
| 200 | 202 |
| 201 size_t currentDisplayItemsIndex = m_currentDisplayItems.indexForIter
ator(currentIt); | 203 addItemToIndex(item.client(), item.type(), currentIt.index(), displa
yItemIndicesByClient); |
| 202 addItemToIndex(item.client(), item.type(), currentDisplayItemsIndex,
displayItemIndicesByClient); | |
| 203 } | 204 } |
| 204 } | 205 } |
| 205 return currentEnd; | 206 return currentEnd; |
| 206 } | 207 } |
| 207 | 208 |
| 208 // Update the existing display items by removing invalidated entries, updating | 209 // Update the existing display items by removing invalidated entries, updating |
| 209 // repainted ones, and appending new items. | 210 // repainted ones, and appending new items. |
| 210 // - For CachedDisplayItem, copy the corresponding cached DrawingDisplayItem; | 211 // - For CachedDisplayItem, copy the corresponding cached DrawingDisplayItem; |
| 211 // - FIXME: Re-enable SubtreeCachedDisplayItem: | 212 // - FIXME: Re-enable SubtreeCachedDisplayItem: |
| 212 // For SubtreeCachedDisplayItem, copy the cached display items between the | 213 // For SubtreeCachedDisplayItem, copy the cached display items between the |
| (...skipping 10 matching lines...) Expand all Loading... |
| 223 | 224 |
| 224 // These data structures are used during painting only. | 225 // These data structures are used during painting only. |
| 225 m_clientScopeIdMap.clear(); | 226 m_clientScopeIdMap.clear(); |
| 226 ASSERT(m_scopeStack.isEmpty()); | 227 ASSERT(m_scopeStack.isEmpty()); |
| 227 m_scopeStack.clear(); | 228 m_scopeStack.clear(); |
| 228 ASSERT(!skippingCache()); | 229 ASSERT(!skippingCache()); |
| 229 #if ENABLE(ASSERT) | 230 #if ENABLE(ASSERT) |
| 230 m_newDisplayItemIndicesByClient.clear(); | 231 m_newDisplayItemIndicesByClient.clear(); |
| 231 #endif | 232 #endif |
| 232 | 233 |
| 233 if (m_currentDisplayItems.isEmpty()) { | 234 if (m_currentDisplayItems.empty()) { |
| 234 #if ENABLE(ASSERT) | 235 #if ENABLE(ASSERT) |
| 235 for (auto& item : m_newDisplayItems) { | 236 for (const auto& item : m_newDisplayItems) { |
| 236 ASSERT(!DisplayItem::isCachedType(item.type()) | 237 ASSERT(!DisplayItem::isCachedType(item->type()) |
| 237 && !DisplayItem::isSubtreeCachedType(item.type())); | 238 && !DisplayItem::isSubtreeCachedType(item->type())); |
| 238 } | 239 } |
| 239 #endif | 240 #endif |
| 240 m_currentDisplayItems.swap(m_newDisplayItems); | 241 m_currentDisplayItems.swap(m_newDisplayItems); |
| 241 m_validlyCachedClientsDirty = true; | 242 m_validlyCachedClientsDirty = true; |
| 242 m_numCachedItems = 0; | 243 m_numCachedItems = 0; |
| 243 return; | 244 return; |
| 244 } | 245 } |
| 245 | 246 |
| 246 updateValidlyCachedClientsIfNeeded(); | 247 updateValidlyCachedClientsIfNeeded(); |
| 247 | 248 |
| 248 // Stores indices to valid DrawingDisplayItems in m_currentDisplayItems that
have not been matched | 249 // Stores indices to valid DrawingDisplayItems in m_currentDisplayItems that
have not been matched |
| 249 // by CachedDisplayItems during synchronized matching. The indexed items wil
l be matched | 250 // by CachedDisplayItems during synchronized matching. The indexed items wil
l be matched |
| 250 // by later out-of-order CachedDisplayItems in m_newDisplayItems. This ensur
es that when | 251 // by later out-of-order CachedDisplayItems in m_newDisplayItems. This ensur
es that when |
| 251 // out-of-order CachedDisplayItems occur, we only traverse at most once over
m_currentDisplayItems | 252 // out-of-order CachedDisplayItems occur, we only traverse at most once over
m_currentDisplayItems |
| 252 // looking for potential matches. Thus we can ensure that the algorithm runs
in linear time. | 253 // looking for potential matches. Thus we can ensure that the algorithm runs
in linear time. |
| 253 DisplayItemIndicesByClientMap displayItemIndicesByClient; | 254 DisplayItemIndicesByClientMap displayItemIndicesByClient; |
| 254 | 255 |
| 255 #if ENABLE(ASSERT) | 256 #if ENABLE(ASSERT) |
| 256 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
{ | 257 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled())
{ |
| 257 // Under-invalidation checking requires a full index of m_currentDisplay
Items. | 258 // Under-invalidation checking requires a full index of m_currentDisplay
Items. |
| 258 size_t i = 0; | 259 size_t i = 0; |
| 259 for (const auto& item : m_currentDisplayItems) { | 260 for (const auto& item : m_currentDisplayItems) { |
| 260 addItemToIndex(item.client(), item.type(), i, displayItemIndicesByCl
ient); | 261 addItemToIndex(item->client(), item->type(), i, displayItemIndicesBy
Client); |
| 261 ++i; | 262 ++i; |
| 262 } | 263 } |
| 263 } | 264 } |
| 264 #endif // ENABLE(ASSERT) | 265 #endif // ENABLE(ASSERT) |
| 265 | 266 |
| 266 DisplayItems updatedList; | 267 DisplayItems updatedList(kMaximumDisplayItemSize, std::max(m_currentDisplayI
tems.size(), m_newDisplayItems.size())); |
| 267 DisplayItems::Iterator currentIt = m_currentDisplayItems.begin(); | 268 DisplayItems::Iterator currentIt = m_currentDisplayItems.begin(); |
| 268 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); | 269 DisplayItems::Iterator currentEnd = m_currentDisplayItems.end(); |
| 269 for (DisplayItems::Iterator newIt = m_newDisplayItems.begin(); newIt != m_ne
wDisplayItems.end(); ++newIt) { | 270 for (DisplayItems::Iterator newIt = m_newDisplayItems.begin(); newIt != m_ne
wDisplayItems.end(); ++newIt) { |
| 270 DisplayItems::ItemHandle newDisplayItem = *newIt; | 271 const DisplayItem& newDisplayItem = **newIt; |
| 271 DisplayItem::Type matchingType = newDisplayItem.type(); | 272 DisplayItem::Type matchingType = newDisplayItem.type(); |
| 272 if (DisplayItem::isCachedType(newDisplayItem.type())) | 273 if (DisplayItem::isCachedType(newDisplayItem.type())) |
| 273 matchingType = DisplayItem::cachedTypeToDrawingType(matchingType); | 274 matchingType = DisplayItem::cachedTypeToDrawingType(matchingType); |
| 274 bool isSynchronized = currentIt != currentEnd | 275 bool isSynchronized = currentIt != currentEnd |
| 275 && !currentIt->isGone() | 276 && !currentIt->ignoreFromDisplayList() |
| 276 && currentIt->id().equalToExceptForType(newDisplayItem.id(), matchin
gType); | 277 && currentIt->id().equalToExceptForType(newDisplayItem.id(), matchin
gType); |
| 277 | 278 |
| 278 if (DisplayItem::isCachedType(newDisplayItem.type())) { | 279 if (DisplayItem::isCachedType(newDisplayItem.type())) { |
| 279 ASSERT(!RuntimeEnabledFeatures::slimmingPaintUnderInvalidationChecki
ngEnabled()); | 280 ASSERT(!RuntimeEnabledFeatures::slimmingPaintUnderInvalidationChecki
ngEnabled()); |
| 280 ASSERT(clientCacheIsValid(newDisplayItem.client())); | 281 ASSERT(clientCacheIsValid(newDisplayItem.client())); |
| 281 if (isSynchronized) { | 282 if (isSynchronized) { |
| 282 updatedList.appendByMoving(currentIt); | 283 updatedList.appendByMoving(*currentIt); |
| 283 } else { | 284 } else { |
| 284 DisplayItems::Iterator foundIt = findOutOfOrderCachedItem(curren
tIt, newDisplayItem.id(), matchingType, displayItemIndicesByClient); | 285 DisplayItems::Iterator foundIt = findOutOfOrderCachedItem(curren
tIt, newDisplayItem.id(), matchingType, displayItemIndicesByClient); |
| 285 isSynchronized = (foundIt == currentIt); | 286 isSynchronized = (foundIt == currentIt); |
| 286 | 287 |
| 287 #ifndef NDEBUG | 288 #ifndef NDEBUG |
| 288 if (foundIt == currentEnd) { | 289 if (foundIt == currentEnd) { |
| 289 showDebugData(); | 290 showDebugData(); |
| 290 WTFLogAlways("CachedDisplayItem %s not found in m_currentDis
playItems\n", | 291 WTFLogAlways("CachedDisplayItem %s not found in m_currentDis
playItems\n", |
| 291 newDisplayItem.asDebugString().utf8().data()); | 292 newDisplayItem.asDebugString().utf8().data()); |
| 292 ASSERT_NOT_REACHED(); | 293 ASSERT_NOT_REACHED(); |
| 293 } | 294 } |
| 294 #endif | 295 #endif |
| 295 // If foundIt == currentEnd, it means that we did not find the c
ached display item. This should be impossible, but may occur | 296 // If foundIt == currentEnd, it means that we did not find the c
ached display item. This should be impossible, but may occur |
| 296 // if there is a bug in the system, such as under-invalidation,
incorrect cache checking or duplicate display ids. In this case, | 297 // if there is a bug in the system, such as under-invalidation,
incorrect cache checking or duplicate display ids. In this case, |
| 297 // attempt to recover rather than crashing or bailing on display
of the rest of the display list. | 298 // attempt to recover rather than crashing or bailing on display
of the rest of the display list. |
| 298 if (foundIt == currentEnd) | 299 if (foundIt == currentEnd) |
| 299 continue; | 300 continue; |
| 300 | 301 |
| 301 currentIt = foundIt; | 302 currentIt = foundIt; |
| 302 | 303 |
| 303 updatedList.appendByMoving(foundIt); | 304 updatedList.appendByMoving(*foundIt); |
| 304 } | 305 } |
| 305 } else { | 306 } else { |
| 306 #if ENABLE(ASSERT) | 307 #if ENABLE(ASSERT) |
| 307 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEn
abled()) | 308 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEn
abled()) |
| 308 checkCachedDisplayItemIsUnchanged(newDisplayItem, displayItemInd
icesByClient); | 309 checkCachedDisplayItemIsUnchanged(newDisplayItem, displayItemInd
icesByClient); |
| 309 else | 310 else |
| 310 ASSERT(!DisplayItem::isDrawingType(newDisplayItem.type()) || new
DisplayItem.skippedCache() || !clientCacheIsValid(newDisplayItem.client())); | 311 ASSERT(!DisplayItem::isDrawingType(newDisplayItem.type()) || new
DisplayItem.skippedCache() || !clientCacheIsValid(newDisplayItem.client())); |
| 311 #endif // ENABLE(ASSERT) | 312 #endif // ENABLE(ASSERT) |
| 312 updatedList.appendByMoving(newIt); | 313 updatedList.appendByMoving(*newIt); |
| 313 } | 314 } |
| 314 | 315 |
| 315 if (isSynchronized) | 316 if (isSynchronized) |
| 316 ++currentIt; | 317 ++currentIt; |
| 317 } | 318 } |
| 318 | 319 |
| 319 #if ENABLE(ASSERT) | 320 #if ENABLE(ASSERT) |
| 320 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) | 321 if (RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled()) |
| 321 checkNoRemainingCachedDisplayItems(); | 322 checkNoRemainingCachedDisplayItems(); |
| 322 #endif // ENABLE(ASSERT) | 323 #endif // ENABLE(ASSERT) |
| 323 | 324 |
| 324 m_newDisplayItems.clear(); | 325 m_newDisplayItems.clear(); |
| 325 m_validlyCachedClientsDirty = true; | 326 m_validlyCachedClientsDirty = true; |
| 326 m_currentDisplayItems.clear(); | |
| 327 m_currentDisplayItems.swap(updatedList); | 327 m_currentDisplayItems.swap(updatedList); |
| 328 m_numCachedItems = 0; | 328 m_numCachedItems = 0; |
| 329 } | 329 } |
| 330 | 330 |
| 331 void DisplayItemList::updateValidlyCachedClientsIfNeeded() const | 331 void DisplayItemList::updateValidlyCachedClientsIfNeeded() const |
| 332 { | 332 { |
| 333 if (!m_validlyCachedClientsDirty) | 333 if (!m_validlyCachedClientsDirty) |
| 334 return; | 334 return; |
| 335 | 335 |
| 336 m_validlyCachedClients.clear(); | 336 m_validlyCachedClients.clear(); |
| 337 m_validlyCachedClientsDirty = false; | 337 m_validlyCachedClientsDirty = false; |
| 338 | 338 |
| 339 DisplayItemClient lastClient = nullptr; | 339 DisplayItemClient lastClient = nullptr; |
| 340 for (const auto& displayItem : m_currentDisplayItems) { | 340 for (const auto& displayItem : m_currentDisplayItems) { |
| 341 if (displayItem.client() == lastClient) | 341 if (displayItem->client() == lastClient) |
| 342 continue; | 342 continue; |
| 343 lastClient = displayItem.client(); | 343 lastClient = displayItem->client(); |
| 344 if (!displayItem.skippedCache()) | 344 if (!displayItem->skippedCache()) |
| 345 m_validlyCachedClients.add(lastClient); | 345 m_validlyCachedClients.add(lastClient); |
| 346 } | 346 } |
| 347 } | 347 } |
| 348 | 348 |
| 349 void DisplayItemList::commitNewDisplayItemsAndAppendToWebDisplayItemList(WebDisp
layItemList* list) | 349 void DisplayItemList::commitNewDisplayItemsAndAppendToWebDisplayItemList(WebDisp
layItemList* list) |
| 350 { | 350 { |
| 351 commitNewDisplayItems(); | 351 commitNewDisplayItems(); |
| 352 for (auto& item : m_currentDisplayItems) | 352 for (const auto& item : m_currentDisplayItems) |
| 353 item.appendToWebDisplayItemList(list); | 353 item->appendToWebDisplayItemList(list); |
| 354 } | 354 } |
| 355 | 355 |
| 356 #if ENABLE(ASSERT) | 356 #if ENABLE(ASSERT) |
| 357 | 357 |
| 358 static void showUnderInvalidationError(const char* reason, const DisplayItems::I
temHandle& displayItem) | 358 static void showUnderInvalidationError(const char* reason, const DisplayItem& di
splayItem) |
| 359 { | 359 { |
| 360 #ifndef NDEBUG | 360 #ifndef NDEBUG |
| 361 WTFLogAlways("%s: %s\nSee http://crbug.com/450725.", reason, displayItem.asD
ebugString().utf8().data()); | 361 WTFLogAlways("%s: %s\nSee http://crbug.com/450725.", reason, displayItem.asD
ebugString().utf8().data()); |
| 362 #else | 362 #else |
| 363 WTFLogAlways("%s. Run debug build to get more details\nSee http://crbug.com/
450725.", reason); | 363 WTFLogAlways("%s. Run debug build to get more details\nSee http://crbug.com/
450725.", reason); |
| 364 #endif // NDEBUG | 364 #endif // NDEBUG |
| 365 } | 365 } |
| 366 | 366 |
| 367 static bool bitmapIsAllZero(const SkBitmap& bitmap) | 367 static bool bitmapIsAllZero(const SkBitmap& bitmap) |
| 368 { | 368 { |
| 369 bitmap.lockPixels(); | 369 bitmap.lockPixels(); |
| 370 bool result = true; | 370 bool result = true; |
| 371 for (int x = 0; result && x < bitmap.width(); ++x) { | 371 for (int x = 0; result && x < bitmap.width(); ++x) { |
| 372 for (int y = 0; result && y < bitmap.height(); ++y) { | 372 for (int y = 0; result && y < bitmap.height(); ++y) { |
| 373 if (SkColorSetA(bitmap.getColor(x, y), 0) != SK_ColorTRANSPARENT) | 373 if (SkColorSetA(bitmap.getColor(x, y), 0) != SK_ColorTRANSPARENT) |
| 374 result = false; | 374 result = false; |
| 375 } | 375 } |
| 376 } | 376 } |
| 377 bitmap.unlockPixels(); | 377 bitmap.unlockPixels(); |
| 378 return result; | 378 return result; |
| 379 } | 379 } |
| 380 | 380 |
| 381 void DisplayItemList::checkCachedDisplayItemIsUnchanged(const DisplayItems::Item
Handle& displayItem, DisplayItemIndicesByClientMap& displayItemIndicesByClient) | 381 void DisplayItemList::checkCachedDisplayItemIsUnchanged(const DisplayItem& displ
ayItem, DisplayItemIndicesByClientMap& displayItemIndicesByClient) |
| 382 { | 382 { |
| 383 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); | 383 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); |
| 384 | 384 |
| 385 if (!DisplayItem::isDrawingType(displayItem.type()) || displayItem.skippedCa
che() || !clientCacheIsValid(displayItem.client())) | 385 if (!DisplayItem::isDrawingType(displayItem.type()) || displayItem.skippedCa
che() || !clientCacheIsValid(displayItem.client())) |
| 386 return; | 386 return; |
| 387 | 387 |
| 388 // If checking under-invalidation, we always generate new display item even
if the client is not invalidated. | 388 // If checking under-invalidation, we always generate new display item even
if the client is not invalidated. |
| 389 // Checks if the new picture is the same as the cached old picture. If the n
ew picture is different but | 389 // Checks if the new picture is the same as the cached old picture. If the n
ew picture is different but |
| 390 // the client is not invalidated, issue error about under-invalidation. | 390 // the client is not invalidated, issue error about under-invalidation. |
| 391 size_t index = findMatchingItemFromIndex(displayItem.id(), displayItem.type(
), displayItemIndicesByClient, m_currentDisplayItems); | 391 size_t index = findMatchingItemFromIndex(displayItem.id(), displayItem.type(
), displayItemIndicesByClient, m_currentDisplayItems); |
| 392 if (index == kNotFound) { | 392 if (index == kNotFound) { |
| 393 showUnderInvalidationError("ERROR: under-invalidation: no cached display
item", displayItem); | 393 showUnderInvalidationError("ERROR: under-invalidation: no cached display
item", displayItem); |
| 394 ASSERT_NOT_REACHED(); | 394 ASSERT_NOT_REACHED(); |
| 395 return; | 395 return; |
| 396 } | 396 } |
| 397 | 397 |
| 398 DisplayItems::Iterator foundItem = m_currentDisplayItems.iteratorAt(index); | 398 DisplayItems::Iterator foundItem = m_currentDisplayItems.iteratorAt(index); |
| 399 RefPtr<const SkPicture> newPicture = displayItem.picture(); | 399 RefPtr<const SkPicture> newPicture = static_cast<const DrawingDisplayItem&>(
displayItem).picture(); |
| 400 RefPtr<const SkPicture> oldPicture = foundItem->picture(); | 400 RefPtr<const SkPicture> oldPicture = static_cast<const DrawingDisplayItem*>(
*foundItem)->picture(); |
| 401 // Remove the display item from cache so that we can check if there are any
remaining cached display items after merging. | 401 // Mark the display item as ignored so that we can check if there are any re
maining cached display items after merging. |
| 402 m_currentDisplayItems.setGone(foundItem); | 402 foundItem->setIgnoredFromDisplayList(); |
| 403 | 403 |
| 404 if (!newPicture && !oldPicture) | 404 if (!newPicture && !oldPicture) |
| 405 return; | 405 return; |
| 406 if (newPicture && oldPicture) { | 406 if (newPicture && oldPicture) { |
| 407 switch (displayItem.underInvalidationCheckingMode()) { | 407 switch (static_cast<const DrawingDisplayItem&>(displayItem).underInvalid
ationCheckingMode()) { |
| 408 case DrawingDisplayItem::CheckPicture: | 408 case DrawingDisplayItem::CheckPicture: |
| 409 if (newPicture->approximateOpCount() == oldPicture->approximateOpCou
nt()) { | 409 if (newPicture->approximateOpCount() == oldPicture->approximateOpCou
nt()) { |
| 410 SkDynamicMemoryWStream newPictureSerialized; | 410 SkDynamicMemoryWStream newPictureSerialized; |
| 411 newPicture->serialize(&newPictureSerialized); | 411 newPicture->serialize(&newPictureSerialized); |
| 412 SkDynamicMemoryWStream oldPictureSerialized; | 412 SkDynamicMemoryWStream oldPictureSerialized; |
| 413 oldPicture->serialize(&oldPictureSerialized); | 413 oldPicture->serialize(&oldPictureSerialized); |
| 414 | 414 |
| 415 if (newPictureSerialized.bytesWritten() == oldPictureSerialized.
bytesWritten()) { | 415 if (newPictureSerialized.bytesWritten() == oldPictureSerialized.
bytesWritten()) { |
| 416 RefPtr<SkData> oldData = adoptRef(oldPictureSerialized.copyT
oData()); | 416 RefPtr<SkData> oldData = adoptRef(oldPictureSerialized.copyT
oData()); |
| 417 RefPtr<SkData> newData = adoptRef(newPictureSerialized.copyT
oData()); | 417 RefPtr<SkData> newData = adoptRef(newPictureSerialized.copyT
oData()); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 448 #endif // NDEBUG | 448 #endif // NDEBUG |
| 449 | 449 |
| 450 ASSERT_NOT_REACHED(); | 450 ASSERT_NOT_REACHED(); |
| 451 } | 451 } |
| 452 | 452 |
| 453 void DisplayItemList::checkNoRemainingCachedDisplayItems() | 453 void DisplayItemList::checkNoRemainingCachedDisplayItems() |
| 454 { | 454 { |
| 455 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); | 455 ASSERT(RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled
()); |
| 456 | 456 |
| 457 for (const auto& displayItem : m_currentDisplayItems) { | 457 for (const auto& displayItem : m_currentDisplayItems) { |
| 458 if (displayItem.isGone() || !DisplayItem::isDrawingType(displayItem.type
()) || !clientCacheIsValid(displayItem.client())) | 458 if (displayItem->ignoreFromDisplayList() || !DisplayItem::isDrawingType(
displayItem->type()) || !clientCacheIsValid(displayItem->client())) |
| 459 continue; | 459 continue; |
| 460 showUnderInvalidationError("May be under-invalidation: no new display it
em", displayItem); | 460 showUnderInvalidationError("May be under-invalidation: no new display it
em", *displayItem); |
| 461 } | 461 } |
| 462 } | 462 } |
| 463 | 463 |
| 464 #endif // ENABLE(ASSERT) | 464 #endif // ENABLE(ASSERT) |
| 465 | 465 |
| 466 #ifndef NDEBUG | 466 #ifndef NDEBUG |
| 467 | 467 |
| 468 WTF::String DisplayItemList::displayItemsAsDebugString(const DisplayItems& list)
const | 468 WTF::String DisplayItemList::displayItemsAsDebugString(const DisplayItems& list)
const |
| 469 { | 469 { |
| 470 StringBuilder stringBuilder; | 470 StringBuilder stringBuilder; |
| 471 size_t i = 0; | 471 size_t i = 0; |
| 472 for (auto it = list.begin(); it != list.end(); ++it, ++i) { | 472 for (auto it = list.begin(); it != list.end(); ++it, ++i) { |
| 473 DisplayItems::ItemHandle displayItem = list[i]; | 473 const DisplayItem& displayItem = *list.elementAt(i); |
| 474 if (i) | 474 if (i) |
| 475 stringBuilder.append(",\n"); | 475 stringBuilder.append(",\n"); |
| 476 if (displayItem.isGone()) { | 476 if (displayItem.ignoreFromDisplayList()) { |
| 477 stringBuilder.append("null"); | 477 stringBuilder.append("null"); |
| 478 continue; | 478 continue; |
| 479 } | 479 } |
| 480 stringBuilder.append(String::format("{index: %d, ", (int)i)); | 480 stringBuilder.append(String::format("{index: %d, ", (int)i)); |
| 481 displayItem.dumpPropertiesAsDebugString(stringBuilder); | 481 displayItem.dumpPropertiesAsDebugString(stringBuilder); |
| 482 stringBuilder.append(", cacheIsValid: "); | 482 stringBuilder.append(", cacheIsValid: "); |
| 483 stringBuilder.append(clientCacheIsValid(displayItem.client()) ? "true" :
"false"); | 483 stringBuilder.append(clientCacheIsValid(displayItem.client()) ? "true" :
"false"); |
| 484 stringBuilder.append('}'); | 484 stringBuilder.append('}'); |
| 485 } | 485 } |
| 486 return stringBuilder.toString(); | 486 return stringBuilder.toString(); |
| 487 } | 487 } |
| 488 | 488 |
| 489 void DisplayItemList::showDebugData() const | 489 void DisplayItemList::showDebugData() const |
| 490 { | 490 { |
| 491 WTFLogAlways("current display items: [%s]\n", displayItemsAsDebugString(m_cu
rrentDisplayItems).utf8().data()); | 491 WTFLogAlways("current display items: [%s]\n", displayItemsAsDebugString(m_cu
rrentDisplayItems).utf8().data()); |
| 492 WTFLogAlways("new display items: [%s]\n", displayItemsAsDebugString(m_newDis
playItems).utf8().data()); | 492 WTFLogAlways("new display items: [%s]\n", displayItemsAsDebugString(m_newDis
playItems).utf8().data()); |
| 493 } | 493 } |
| 494 | 494 |
| 495 #endif // ifndef NDEBUG | 495 #endif // ifndef NDEBUG |
| 496 | 496 |
| 497 void DisplayItemList::replay(GraphicsContext& context) const | 497 void DisplayItemList::replay(GraphicsContext& context) |
| 498 { | 498 { |
| 499 TRACE_EVENT0("blink,benchmark", "DisplayItemList::replay"); | 499 TRACE_EVENT0("blink,benchmark", "DisplayItemList::replay"); |
| 500 ASSERT(m_newDisplayItems.isEmpty()); | 500 ASSERT(m_newDisplayItems.empty()); |
| 501 for (auto& displayItem : m_currentDisplayItems) | 501 for (auto displayItem : m_currentDisplayItems) |
| 502 displayItem.replay(context); | 502 displayItem->replay(context); |
| 503 } | 503 } |
| 504 | 504 |
| 505 } // namespace blink | 505 } // namespace blink |
| OLD | NEW |